geonode-pycsw 3.0.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. geonode_pycsw-3.0.0b2.dist-info/METADATA +73 -0
  2. geonode_pycsw-3.0.0b2.dist-info/RECORD +382 -0
  3. geonode_pycsw-3.0.0b2.dist-info/WHEEL +5 -0
  4. geonode_pycsw-3.0.0b2.dist-info/entry_points.txt +2 -0
  5. geonode_pycsw-3.0.0b2.dist-info/licenses/LICENSE.txt +26 -0
  6. geonode_pycsw-3.0.0b2.dist-info/top_level.txt +1 -0
  7. pycsw/__init__.py +33 -0
  8. pycsw/core/__init__.py +29 -0
  9. pycsw/core/admin.py +703 -0
  10. pycsw/core/config.py +621 -0
  11. pycsw/core/etree.py +43 -0
  12. pycsw/core/formats/__init__.py +29 -0
  13. pycsw/core/formats/fmt_json.py +69 -0
  14. pycsw/core/log.py +71 -0
  15. pycsw/core/metadata.py +1996 -0
  16. pycsw/core/pygeofilter_evaluate.py +83 -0
  17. pycsw/core/repository.py +941 -0
  18. pycsw/core/schemas/ogc/cat/csw/3.0/_wrapper.xsd +14 -0
  19. pycsw/core/schemas/ogc/cat/csw/3.0/cswAll.xsd +33 -0
  20. pycsw/core/schemas/ogc/cat/csw/3.0/cswCommon.xsd +71 -0
  21. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetCapabilities.xsd +80 -0
  22. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetDomain.xsd +146 -0
  23. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetRecordById.xsd +58 -0
  24. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetRecords.xsd +391 -0
  25. pycsw/core/schemas/ogc/cat/csw/3.0/cswHarvest.xsd +95 -0
  26. pycsw/core/schemas/ogc/cat/csw/3.0/cswTransaction.xsd +187 -0
  27. pycsw/core/schemas/ogc/cat/csw/3.0/cswUnHarvest.xsd +77 -0
  28. pycsw/core/schemas/ogc/cat/csw/3.0/rec-dcmes.xsd +245 -0
  29. pycsw/core/schemas/ogc/cat/csw/3.0/rec-dcterms.xsd +101 -0
  30. pycsw/core/schemas/ogc/cat/csw/3.0/record.xsd +170 -0
  31. pycsw/core/schemas/ogc/csw/2.0.2/CSW-discovery.xsd +494 -0
  32. pycsw/core/schemas/ogc/csw/2.0.2/CSW-publication.xsd +242 -0
  33. pycsw/core/schemas/ogc/csw/2.0.2/rec-dcmes.xsd +199 -0
  34. pycsw/core/schemas/ogc/csw/2.0.2/rec-dcterms.xsd +94 -0
  35. pycsw/core/schemas/ogc/csw/2.0.2/record.xsd +138 -0
  36. pycsw/core/schemas/ogc/filter/1.1.0/expr.xsd +67 -0
  37. pycsw/core/schemas/ogc/filter/1.1.0/filter.xsd +265 -0
  38. pycsw/core/schemas/ogc/filter/1.1.0/filterCapabilities.xsd +171 -0
  39. pycsw/core/schemas/ogc/filter/1.1.0/sort.xsd +46 -0
  40. pycsw/core/schemas/ogc/filter/2.0/_wrapper.xsd +5 -0
  41. pycsw/core/schemas/ogc/filter/2.0/expr.xsd +44 -0
  42. pycsw/core/schemas/ogc/filter/2.0/filter.xsd +396 -0
  43. pycsw/core/schemas/ogc/filter/2.0/filterAll.xsd +23 -0
  44. pycsw/core/schemas/ogc/filter/2.0/filterCapabilities.xsd +286 -0
  45. pycsw/core/schemas/ogc/filter/2.0/query.xsd +70 -0
  46. pycsw/core/schemas/ogc/filter/2.0/sort.xsd +49 -0
  47. pycsw/core/schemas/ogc/gml/3.1.1/base/basicTypes.xsd +278 -0
  48. pycsw/core/schemas/ogc/gml/3.1.1/base/coordinateOperations.xsd +789 -0
  49. pycsw/core/schemas/ogc/gml/3.1.1/base/coordinateReferenceSystems.xsd +429 -0
  50. pycsw/core/schemas/ogc/gml/3.1.1/base/coordinateSystems.xsd +408 -0
  51. pycsw/core/schemas/ogc/gml/3.1.1/base/coverage.xsd +451 -0
  52. pycsw/core/schemas/ogc/gml/3.1.1/base/dataQuality.xsd +129 -0
  53. pycsw/core/schemas/ogc/gml/3.1.1/base/datums.xsd +484 -0
  54. pycsw/core/schemas/ogc/gml/3.1.1/base/defaultStyle.xsd +454 -0
  55. pycsw/core/schemas/ogc/gml/3.1.1/base/dictionary.xsd +137 -0
  56. pycsw/core/schemas/ogc/gml/3.1.1/base/direction.xsd +72 -0
  57. pycsw/core/schemas/ogc/gml/3.1.1/base/dynamicFeature.xsd +115 -0
  58. pycsw/core/schemas/ogc/gml/3.1.1/base/feature.xsd +199 -0
  59. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryAggregates.xsd +430 -0
  60. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryBasic0d1d.xsd +602 -0
  61. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryBasic2d.xsd +213 -0
  62. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryComplexes.xsd +141 -0
  63. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryPrimitives.xsd +1609 -0
  64. pycsw/core/schemas/ogc/gml/3.1.1/base/gml.xsd +22 -0
  65. pycsw/core/schemas/ogc/gml/3.1.1/base/gmlBase.xsd +294 -0
  66. pycsw/core/schemas/ogc/gml/3.1.1/base/grids.xsd +76 -0
  67. pycsw/core/schemas/ogc/gml/3.1.1/base/measures.xsd +200 -0
  68. pycsw/core/schemas/ogc/gml/3.1.1/base/observation.xsd +96 -0
  69. pycsw/core/schemas/ogc/gml/3.1.1/base/referenceSystems.xsd +211 -0
  70. pycsw/core/schemas/ogc/gml/3.1.1/base/temporal.xsd +332 -0
  71. pycsw/core/schemas/ogc/gml/3.1.1/base/temporalReferenceSystems.xsd +251 -0
  72. pycsw/core/schemas/ogc/gml/3.1.1/base/temporalTopology.xsd +186 -0
  73. pycsw/core/schemas/ogc/gml/3.1.1/base/topology.xsd +459 -0
  74. pycsw/core/schemas/ogc/gml/3.1.1/base/units.xsd +170 -0
  75. pycsw/core/schemas/ogc/gml/3.1.1/base/valueObjects.xsd +361 -0
  76. pycsw/core/schemas/ogc/gml/3.1.1/smil/smil20-language.xsd +117 -0
  77. pycsw/core/schemas/ogc/gml/3.1.1/smil/smil20.xsd +234 -0
  78. pycsw/core/schemas/ogc/gml/3.2.1/basicTypes.xsd +268 -0
  79. pycsw/core/schemas/ogc/gml/3.2.1/coordinateOperations.xsd +525 -0
  80. pycsw/core/schemas/ogc/gml/3.2.1/coordinateReferenceSystems.xsd +373 -0
  81. pycsw/core/schemas/ogc/gml/3.2.1/coordinateSystems.xsd +297 -0
  82. pycsw/core/schemas/ogc/gml/3.2.1/coverage.xsd +292 -0
  83. pycsw/core/schemas/ogc/gml/3.2.1/datums.xsd +287 -0
  84. pycsw/core/schemas/ogc/gml/3.2.1/defaultStyle.xsd +453 -0
  85. pycsw/core/schemas/ogc/gml/3.2.1/deprecatedTypes.xsd +1133 -0
  86. pycsw/core/schemas/ogc/gml/3.2.1/dictionary.xsd +90 -0
  87. pycsw/core/schemas/ogc/gml/3.2.1/direction.xsd +84 -0
  88. pycsw/core/schemas/ogc/gml/3.2.1/dynamicFeature.xsd +109 -0
  89. pycsw/core/schemas/ogc/gml/3.2.1/feature.xsd +94 -0
  90. pycsw/core/schemas/ogc/gml/3.2.1/geometryAggregates.xsd +197 -0
  91. pycsw/core/schemas/ogc/gml/3.2.1/geometryBasic0d1d.xsd +277 -0
  92. pycsw/core/schemas/ogc/gml/3.2.1/geometryBasic2d.xsd +124 -0
  93. pycsw/core/schemas/ogc/gml/3.2.1/geometryComplexes.xsd +95 -0
  94. pycsw/core/schemas/ogc/gml/3.2.1/geometryPrimitives.xsd +846 -0
  95. pycsw/core/schemas/ogc/gml/3.2.1/gml.xsd +20 -0
  96. pycsw/core/schemas/ogc/gml/3.2.1/gmlBase.xsd +185 -0
  97. pycsw/core/schemas/ogc/gml/3.2.1/grids.xsd +64 -0
  98. pycsw/core/schemas/ogc/gml/3.2.1/measures.xsd +68 -0
  99. pycsw/core/schemas/ogc/gml/3.2.1/observation.xsd +95 -0
  100. pycsw/core/schemas/ogc/gml/3.2.1/referenceSystems.xsd +70 -0
  101. pycsw/core/schemas/ogc/gml/3.2.1/temporal.xsd +269 -0
  102. pycsw/core/schemas/ogc/gml/3.2.1/temporalReferenceSystems.xsd +189 -0
  103. pycsw/core/schemas/ogc/gml/3.2.1/temporalTopology.xsd +119 -0
  104. pycsw/core/schemas/ogc/gml/3.2.1/topology.xsd +386 -0
  105. pycsw/core/schemas/ogc/gml/3.2.1/units.xsd +162 -0
  106. pycsw/core/schemas/ogc/gml/3.2.1/valueObjects.xsd +205 -0
  107. pycsw/core/schemas/ogc/ogcapi/records/part1/1.0/ogcapi-records-1.yaml +932 -0
  108. pycsw/core/schemas/ogc/ows/1.0.0/ows19115subset.xsd +222 -0
  109. pycsw/core/schemas/ogc/ows/1.0.0/owsAll.xsd +20 -0
  110. pycsw/core/schemas/ogc/ows/1.0.0/owsCommon.xsd +155 -0
  111. pycsw/core/schemas/ogc/ows/1.0.0/owsDataIdentification.xsd +112 -0
  112. pycsw/core/schemas/ogc/ows/1.0.0/owsExceptionReport.xsd +67 -0
  113. pycsw/core/schemas/ogc/ows/1.0.0/owsGetCapabilities.xsd +108 -0
  114. pycsw/core/schemas/ogc/ows/1.0.0/owsOperationsMetadata.xsd +161 -0
  115. pycsw/core/schemas/ogc/ows/1.0.0/owsServiceIdentification.xsd +55 -0
  116. pycsw/core/schemas/ogc/ows/1.0.0/owsServiceProvider.xsd +46 -0
  117. pycsw/core/schemas/ogc/ows/1.1.0/ows19115subset.xsd +236 -0
  118. pycsw/core/schemas/ogc/ows/1.1.0/owsAll.xsd +23 -0
  119. pycsw/core/schemas/ogc/ows/1.1.0/owsCommon.xsd +158 -0
  120. pycsw/core/schemas/ogc/ows/1.1.0/owsContents.xsd +87 -0
  121. pycsw/core/schemas/ogc/ows/1.1.0/owsDataIdentification.xsd +128 -0
  122. pycsw/core/schemas/ogc/ows/1.1.0/owsDomainType.xsd +280 -0
  123. pycsw/core/schemas/ogc/ows/1.1.0/owsExceptionReport.xsd +77 -0
  124. pycsw/core/schemas/ogc/ows/1.1.0/owsGetCapabilities.xsd +113 -0
  125. pycsw/core/schemas/ogc/ows/1.1.0/owsGetResourceByID.xsd +52 -0
  126. pycsw/core/schemas/ogc/ows/1.1.0/owsInputOutputData.xsd +60 -0
  127. pycsw/core/schemas/ogc/ows/1.1.0/owsManifest.xsd +125 -0
  128. pycsw/core/schemas/ogc/ows/1.1.0/owsOperationsMetadata.xsd +141 -0
  129. pycsw/core/schemas/ogc/ows/1.1.0/owsServiceIdentification.xsd +61 -0
  130. pycsw/core/schemas/ogc/ows/1.1.0/owsServiceProvider.xsd +48 -0
  131. pycsw/core/schemas/ogc/ows/2.0/ows19115subset.xsd +364 -0
  132. pycsw/core/schemas/ogc/ows/2.0/owsAdditionalParameters.xsd +114 -0
  133. pycsw/core/schemas/ogc/ows/2.0/owsAll.xsd +29 -0
  134. pycsw/core/schemas/ogc/ows/2.0/owsCommon.xsd +275 -0
  135. pycsw/core/schemas/ogc/ows/2.0/owsContents.xsd +163 -0
  136. pycsw/core/schemas/ogc/ows/2.0/owsDataIdentification.xsd +202 -0
  137. pycsw/core/schemas/ogc/ows/2.0/owsDomainType.xsd +388 -0
  138. pycsw/core/schemas/ogc/ows/2.0/owsExceptionReport.xsd +126 -0
  139. pycsw/core/schemas/ogc/ows/2.0/owsGetCapabilities.xsd +220 -0
  140. pycsw/core/schemas/ogc/ows/2.0/owsGetResourceByID.xsd +83 -0
  141. pycsw/core/schemas/ogc/ows/2.0/owsInputOutputData.xsd +98 -0
  142. pycsw/core/schemas/ogc/ows/2.0/owsManifest.xsd +181 -0
  143. pycsw/core/schemas/ogc/ows/2.0/owsOperationsMetadata.xsd +234 -0
  144. pycsw/core/schemas/ogc/ows/2.0/owsServiceIdentification.xsd +98 -0
  145. pycsw/core/schemas/ogc/ows/2.0/owsServiceProvider.xsd +64 -0
  146. pycsw/core/schemas/w3c/1999/xlink.xsd +271 -0
  147. pycsw/core/schemas/w3c/2001/xml.xsd +287 -0
  148. pycsw/core/util.py +552 -0
  149. pycsw/oaipmh.py +311 -0
  150. pycsw/ogc/__init__.py +29 -0
  151. pycsw/ogc/api/__init__.py +28 -0
  152. pycsw/ogc/api/oapi.py +558 -0
  153. pycsw/ogc/api/records.py +1414 -0
  154. pycsw/ogc/api/templates/_base.html +76 -0
  155. pycsw/ogc/api/templates/collection.html +44 -0
  156. pycsw/ogc/api/templates/collections.html +45 -0
  157. pycsw/ogc/api/templates/conformance.html +21 -0
  158. pycsw/ogc/api/templates/exception.html +8 -0
  159. pycsw/ogc/api/templates/item.html +228 -0
  160. pycsw/ogc/api/templates/items.html +337 -0
  161. pycsw/ogc/api/templates/landing_page.html +27 -0
  162. pycsw/ogc/api/templates/openapi.html +58 -0
  163. pycsw/ogc/api/templates/queryables.html +50 -0
  164. pycsw/ogc/api/templates/stac_items.html +173 -0
  165. pycsw/ogc/api/templates/static/favicon.ico +0 -0
  166. pycsw/ogc/api/templates/static/logo-horizontal.png +0 -0
  167. pycsw/ogc/api/templates/static/logo-vertical-darkbg.png +0 -0
  168. pycsw/ogc/api/util.py +252 -0
  169. pycsw/ogc/csw/__init__.py +29 -0
  170. pycsw/ogc/csw/cql.py +133 -0
  171. pycsw/ogc/csw/csw2.py +2042 -0
  172. pycsw/ogc/csw/csw3.py +2193 -0
  173. pycsw/ogc/fes/__init__.py +29 -0
  174. pycsw/ogc/fes/fes1.py +433 -0
  175. pycsw/ogc/fes/fes2.py +451 -0
  176. pycsw/ogc/gml/__init__.py +29 -0
  177. pycsw/ogc/gml/gml3.py +240 -0
  178. pycsw/ogc/gml/gml32.py +243 -0
  179. pycsw/opensearch.py +857 -0
  180. pycsw/plugins/__init__.py +29 -0
  181. pycsw/plugins/outputschemas/__init__.py +31 -0
  182. pycsw/plugins/outputschemas/atom.py +143 -0
  183. pycsw/plugins/outputschemas/datacite.py +375 -0
  184. pycsw/plugins/outputschemas/dif.py +213 -0
  185. pycsw/plugins/outputschemas/fgdc.py +180 -0
  186. pycsw/plugins/outputschemas/gm03.py +240 -0
  187. pycsw/plugins/profiles/__init__.py +29 -0
  188. pycsw/plugins/profiles/apiso/__init__.py +29 -0
  189. pycsw/plugins/profiles/apiso/apiso.py +757 -0
  190. pycsw/plugins/profiles/apiso/schemas/ogc/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd +13 -0
  191. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gco/basicTypes.xsd +429 -0
  192. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gco/gco.xsd +12 -0
  193. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gco/gcoBase.xsd +61 -0
  194. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/applicationSchema.xsd +42 -0
  195. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/citation.xsd +275 -0
  196. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/constraints.xsd +106 -0
  197. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/content.xsd +188 -0
  198. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/dataQuality.xsd +554 -0
  199. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/distribution.xsd +202 -0
  200. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/extent.xsd +205 -0
  201. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/freeText.xsd +122 -0
  202. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/gmd.xsd +12 -0
  203. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/identification.xsd +348 -0
  204. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/maintenance.xsd +86 -0
  205. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/metadataApplication.xsd +175 -0
  206. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/metadataEntity.xsd +70 -0
  207. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/metadataExtension.xsd +99 -0
  208. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/portrayalCatalogue.xsd +36 -0
  209. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/referenceSystem.xsd +100 -0
  210. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/spatialRepresentation.xsd +237 -0
  211. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/basicTypes.xsd +267 -0
  212. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coordinateOperations.xsd +639 -0
  213. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coordinateReferenceSystems.xsd +526 -0
  214. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coordinateSystems.xsd +401 -0
  215. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coverage.xsd +462 -0
  216. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/datums.xsd +342 -0
  217. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/dictionary.xsd +129 -0
  218. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/direction.xsd +80 -0
  219. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/dynamicFeature.xsd +142 -0
  220. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/feature.xsd +215 -0
  221. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryAggregates.xsd +216 -0
  222. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryBasic0d1d.xsd +304 -0
  223. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryBasic2d.xsd +123 -0
  224. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryComplexes.xsd +89 -0
  225. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryPrimitives.xsd +892 -0
  226. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/gml.xsd +14 -0
  227. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/gmlBase.xsd +305 -0
  228. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/grids.xsd +58 -0
  229. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/measures.xsd +167 -0
  230. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/observation.xsd +90 -0
  231. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/referenceSystems.xsd +69 -0
  232. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/temporal.xsd +263 -0
  233. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/temporalReferenceSystems.xsd +183 -0
  234. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/temporalTopology.xsd +124 -0
  235. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/topology.xsd +372 -0
  236. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/units.xsd +156 -0
  237. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/valueObjects.xsd +212 -0
  238. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/catalogues.xsd +112 -0
  239. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/codelistItem.xsd +168 -0
  240. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/crsItem.xsd +1030 -0
  241. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/extendedTypes.xsd +75 -0
  242. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/gmx.xsd +2 -0
  243. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/gmxUsage.xsd +127 -0
  244. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/uomItem.xsd +162 -0
  245. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gsr/gsr.xsd +12 -0
  246. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gsr/spatialReferencing.xsd +24 -0
  247. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gss/geometry.xsd +35 -0
  248. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gss/gss.xsd +12 -0
  249. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gts/gts.xsd +12 -0
  250. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gts/temporalObjects.xsd +34 -0
  251. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/srv/serviceMetadata.xsd +197 -0
  252. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/srv/serviceModel.xsd +220 -0
  253. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/srv/srv.xsd +13 -0
  254. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gco/basicTypes.xsd +431 -0
  255. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gco/gco.xsd +12 -0
  256. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gco/gcoBase.xsd +63 -0
  257. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/applicationSchema.xsd +43 -0
  258. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/citation.xsd +276 -0
  259. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/constraints.xsd +107 -0
  260. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/content.xsd +190 -0
  261. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/dataQuality.xsd +556 -0
  262. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/distribution.xsd +203 -0
  263. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/extent.xsd +206 -0
  264. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/freeText.xsd +123 -0
  265. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/gmd.xsd +12 -0
  266. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/identification.xsd +349 -0
  267. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/maintenance.xsd +87 -0
  268. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/metadataApplication.xsd +176 -0
  269. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/metadataEntity.xsd +71 -0
  270. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/metadataExtension.xsd +100 -0
  271. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/portrayalCatalogue.xsd +37 -0
  272. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/referenceSystem.xsd +101 -0
  273. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/spatialRepresentation.xsd +238 -0
  274. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/catalogues.xsd +113 -0
  275. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/codelistItem.xsd +169 -0
  276. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/crsItem.xsd +1031 -0
  277. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/extendedTypes.xsd +76 -0
  278. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/gmx.xsd +12 -0
  279. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/gmxUsage.xsd +128 -0
  280. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/uomItem.xsd +163 -0
  281. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gsr/gsr.xsd +12 -0
  282. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gsr/spatialReferencing.xsd +25 -0
  283. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gss/geometry.xsd +36 -0
  284. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gss/gss.xsd +12 -0
  285. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gts/gts.xsd +12 -0
  286. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gts/temporalObjects.xsd +35 -0
  287. pycsw/plugins/profiles/ebrim/__init__.py +29 -0
  288. pycsw/plugins/profiles/ebrim/ebrim.py +174 -0
  289. pycsw/plugins/profiles/ebrim/schemas/ogc/csw/2.0.2/profiles/ebrim/1.0/csw-ebrim-iri.xsd +146 -0
  290. pycsw/plugins/profiles/ebrim/schemas/ogc/csw/2.0.2/profiles/ebrim/1.0/csw-ebrim.xsd +104 -0
  291. pycsw/plugins/profiles/iso19115p3/__init__.py +29 -0
  292. pycsw/plugins/profiles/iso19115p3/iso19115p3.py +854 -0
  293. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/cat.xsd +13 -0
  294. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/catalogues.xsd +53 -0
  295. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/codelistItem.xsd +54 -0
  296. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/crsItem.xsd +181 -0
  297. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/uomItem.xsd +38 -0
  298. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/1.0/cit.xsd +7 -0
  299. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/1.0/citation.xsd +514 -0
  300. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/2.0/cit.xsd +10 -0
  301. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/2.0/citation.xsd +523 -0
  302. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gco/1.0/baseTypes2014.xsd +530 -0
  303. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gco/1.0/gco.xsd +16 -0
  304. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gcx/1.0/extendedTypes.xsd +92 -0
  305. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gcx/1.0/extendedTypes_autoFromShapeChange.xsd +60 -0
  306. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gcx/1.0/gcx.xsd +8 -0
  307. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gex/1.0/extent.xsd +241 -0
  308. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gex/1.0/gex.xsd +9 -0
  309. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gmw/1.0/gmlWrapperTypes2014.xsd +159 -0
  310. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gmw/1.0/gmw.xsd +14 -0
  311. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/lan/1.0/lan.xsd +8 -0
  312. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/lan/1.0/language.xsd +140 -0
  313. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/1.0/acquisitionInformationImagery.xsd +622 -0
  314. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/1.0/mac.xsd +11 -0
  315. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/2.0/acquisitionInformationImagery.xsd +590 -0
  316. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/2.0/event.xsd +108 -0
  317. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/2.0/mac.xsd +10 -0
  318. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mas/1.0/applicationSchema.xsd +61 -0
  319. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mas/1.0/mas.xsd +9 -0
  320. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mcc/1.0/AbstractCommonClasses.xsd +358 -0
  321. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mcc/1.0/commonClasses.xsd +220 -0
  322. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mcc/1.0/mcc.xsd +8 -0
  323. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mco/1.0/constraints.xsd +188 -0
  324. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mco/1.0/mco.xsd +8 -0
  325. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md1/1.0/md1.xsd +9 -0
  326. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md1/1.0/metadataWExtendedType.xsd +4 -0
  327. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md2/1.0/md2.xsd +15 -0
  328. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md2/1.0/metadataWithExtensions.xsd +4 -0
  329. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mda/1.0/mda.xsd +8 -0
  330. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mda/1.0/metadataApplication.xsd +200 -0
  331. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/1.0/mdb.xsd +14 -0
  332. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/1.0/metadataBase.xsd +98 -0
  333. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/2.0/mdb.xsd +20 -0
  334. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/2.0/metadataBase.xsd +102 -0
  335. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mds/1.0/mds.xsd +22 -0
  336. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mds/1.0/metadataDataServices.xsd +4 -0
  337. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdt/1.0/mdt.xsd +13 -0
  338. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdt/1.0/metadataTransfer.xsd +111 -0
  339. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mex/1.0/metadataExtension.xsd +156 -0
  340. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mex/1.0/mex.xsd +8 -0
  341. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mmi/1.0/maintenance.xsd +76 -0
  342. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mmi/1.0/mmi.xsd +8 -0
  343. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mpc/1.0/mpc.xsd +8 -0
  344. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mpc/1.0/portrayalCatalogue.xsd +31 -0
  345. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/1.0/content.xsd +416 -0
  346. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/1.0/contentInformationImagery.xsd +185 -0
  347. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/1.0/mrc.xsd +11 -0
  348. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/2.0/content.xsd +419 -0
  349. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/2.0/contentInformationImagery.xsd +171 -0
  350. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/2.0/mrc.xsd +11 -0
  351. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrd/1.0/distribution.xsd +267 -0
  352. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrd/1.0/mrd.xsd +8 -0
  353. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mri/1.0/identification.xsd +517 -0
  354. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mri/1.0/mri.xsd +9 -0
  355. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/1.0/lineage.xsd +147 -0
  356. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/1.0/lineageImagery.xsd +236 -0
  357. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/1.0/mrl.xsd +9 -0
  358. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/2.0/lineage.xsd +147 -0
  359. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/2.0/lineageImagery.xsd +312 -0
  360. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/2.0/mrl.xsd +11 -0
  361. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrs/1.0/mrs.xsd +8 -0
  362. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrs/1.0/referenceSystem.xsd +47 -0
  363. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/1.0/msr.xsd +10 -0
  364. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/1.0/spatialRepresentation.xsd +375 -0
  365. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/1.0/spatialRepresentationImagery.xsd +119 -0
  366. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/2.0/msr.xsd +15 -0
  367. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/2.0/spatialRepresentation.xsd +381 -0
  368. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/2.0/spatialRepresentationImagery.xsd +120 -0
  369. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.0/serviceInformation.xsd +272 -0
  370. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.0/srv.xsd +6 -0
  371. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.1/serviceInformation.xsd +278 -0
  372. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.1/srv.xsd +6 -0
  373. pycsw/plugins/profiles/profile.py +141 -0
  374. pycsw/plugins/repository/__init__.py +29 -0
  375. pycsw/plugins/repository/odc/__init__.py +29 -0
  376. pycsw/plugins/repository/odc/odc.py +153 -0
  377. pycsw/server.py +938 -0
  378. pycsw/sru.py +217 -0
  379. pycsw/stac/__init__.py +29 -0
  380. pycsw/stac/api.py +571 -0
  381. pycsw/wsgi.py +233 -0
  382. pycsw/wsgi_flask.py +345 -0
pycsw/core/admin.py ADDED
@@ -0,0 +1,703 @@
1
+ # -*- coding: utf-8 -*-
2
+ # =================================================================
3
+ #
4
+ # Authors: Tom Kralidis <tomkralidis@gmail.com>
5
+ # Angelos Tzotsos <tzotsos@gmail.com>
6
+ #
7
+ # Copyright (c) 2024 Tom Kralidis
8
+ # Copyright (c) 2015 Angelos Tzotsos
9
+ #
10
+ # Permission is hereby granted, free of charge, to any person
11
+ # obtaining a copy of this software and associated documentation
12
+ # files (the "Software"), to deal in the Software without
13
+ # restriction, including without limitation the rights to use,
14
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ # copies of the Software, and to permit persons to whom the
16
+ # Software is furnished to do so, subject to the following
17
+ # conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be
20
+ # included in all copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29
+ # OTHER DEALINGS IN THE SOFTWARE.
30
+ #
31
+ # =================================================================
32
+
33
+ import json
34
+ import logging
35
+ import os
36
+ import sys
37
+ from glob import glob
38
+
39
+ import click
40
+
41
+ from pycsw import __version__
42
+ from pycsw.core import config as pconfig
43
+ from pycsw.core import metadata, repository, util
44
+ from pycsw.core.etree import etree
45
+ from pycsw.core.etree import PARSER
46
+ from pycsw.core.util import parse_ini_config, str2bool
47
+ from pycsw.ogc.api.util import get_typed_value, yaml_dump, yaml_load
48
+
49
+ LOGGER = logging.getLogger(__name__)
50
+
51
+
52
+ def load_records(context, database, table, xml_dirpath, recursive=False, force_update=False):
53
+ """Load metadata records from directory of files to database"""
54
+
55
+ repo = repository.Repository(database, context, table=table)
56
+
57
+ file_list = []
58
+
59
+ loaded_files = set()
60
+ if os.path.isfile(xml_dirpath):
61
+ file_list.append(xml_dirpath)
62
+ elif recursive:
63
+ for root, dirs, files in os.walk(xml_dirpath):
64
+ for mfile in files:
65
+ if mfile.endswith('.xml'):
66
+ file_list.append(os.path.join(root, mfile))
67
+ else:
68
+ files = glob(os.path.join(xml_dirpath, '*.xml')) + glob(os.path.join(xml_dirpath, '*.json'))
69
+ for rec in files:
70
+ file_list.append(rec)
71
+
72
+ total = len(file_list)
73
+ counter = 0
74
+
75
+ for recfile in sorted(file_list):
76
+ counter += 1
77
+ metadata_record = None
78
+ LOGGER.info('Processing file %s (%d of %d)', recfile, counter, total)
79
+ # read document
80
+ try:
81
+ with open(recfile) as fh:
82
+ metadata_record = json.load(fh)
83
+ except json.decoder.JSONDecodeError:
84
+ metadata_record = etree.parse(recfile, context.parser)
85
+ except etree.XMLSyntaxError:
86
+ LOGGER.error('XML document "%s" is not well-formed', recfile, exc_info=True)
87
+ continue
88
+ except Exception:
89
+ LOGGER.exception('XML document "%s" is not well-formed', recfile)
90
+ continue
91
+
92
+ try:
93
+ record = metadata.parse_record(context, metadata_record, repo)
94
+ except Exception:
95
+ LOGGER.exception('Could not parse "%s" as an XML record', recfile)
96
+ continue
97
+
98
+ for rec in record:
99
+ LOGGER.info('Inserting %s %s into database %s, table %s ....',
100
+ rec.typename, rec.identifier, database, table)
101
+
102
+ # TODO: do this as CSW Harvest
103
+ try:
104
+ repo.insert(rec, 'local', util.get_today_and_now())
105
+ loaded_files.add(recfile)
106
+ LOGGER.info('Inserted %s', recfile)
107
+ except Exception as err:
108
+ if force_update:
109
+ LOGGER.info('Record exists. Updating.')
110
+ repo.update(rec)
111
+ LOGGER.info('Updated %s', recfile)
112
+ loaded_files.add(recfile)
113
+ else:
114
+ if err.args: # Pull a decent error message
115
+ LOGGER.error('ERROR: %s not inserted: %s', recfile, err.args[0], exc_info=True)
116
+ else:
117
+ LOGGER.error('ERROR: %s not inserted: %s', recfile, err, exc_info=True)
118
+
119
+ return tuple(loaded_files)
120
+
121
+
122
+ def export_records(context, database, table, xml_dirpath):
123
+ """Export metadata records from database to directory of files"""
124
+ repo = repository.Repository(database, context, table=table)
125
+
126
+ LOGGER.info('Querying database %s, table %s ....', database, table)
127
+ records = repo.session.query(repo.dataset)
128
+
129
+ LOGGER.info('Found %d records\n', records.count())
130
+
131
+ LOGGER.info('Exporting records\n')
132
+
133
+ dirpath = os.path.abspath(xml_dirpath)
134
+
135
+ exported_files = set()
136
+
137
+ if not os.path.exists(dirpath):
138
+ LOGGER.info('Directory %s does not exist. Creating...', dirpath)
139
+ try:
140
+ os.makedirs(dirpath)
141
+ except OSError as err:
142
+ LOGGER.exception('Could not create directory')
143
+ raise RuntimeError('Could not create %s %s' % (dirpath, err)) from err
144
+
145
+ for record in records.all():
146
+ identifier = \
147
+ getattr(record,
148
+ context.md_core_model['mappings']['pycsw:Identifier'])
149
+
150
+ LOGGER.info('Processing %s', identifier)
151
+
152
+ # sanitize identifier
153
+ identifier = util.secure_filename(identifier)
154
+ # write to XML document
155
+
156
+ metadata_type = \
157
+ getattr(record,
158
+ context.md_core_model['mappings']['pycsw:MetadataType'])
159
+
160
+ if 'json' in metadata_type:
161
+ extension = 'json'
162
+ else:
163
+ extension = 'xml'
164
+
165
+ filename = os.path.join(dirpath, '%s.%s' % (identifier, extension))
166
+
167
+ try:
168
+ LOGGER.info('Writing to file %s', filename)
169
+ if hasattr(record.xml, 'decode'):
170
+ str_xml = record.xml.decode('utf-8')
171
+ else:
172
+ str_xml = record.xml
173
+ with open(filename, 'w') as xml:
174
+ xml.write('<?xml version="1.0" encoding="UTF-8"?>\n')
175
+ xml.write(str_xml)
176
+ except Exception:
177
+ # Something went wrong so skip over this file but log an error
178
+ LOGGER.exception('Error writing %s to disk', filename)
179
+ # If we wrote a partial file or created an empty file make sure it is removed
180
+ if os.path.exists(filename):
181
+ os.remove(filename)
182
+ continue
183
+ else:
184
+ exported_files.add(filename)
185
+
186
+ return tuple(exported_files)
187
+
188
+
189
+ def refresh_harvested_records(context, database, table, url):
190
+ """refresh / harvest all non-local records in repository"""
191
+ from owslib.csw import CatalogueServiceWeb
192
+
193
+ # get configuration and init repo connection
194
+ repos = repository.Repository(database, context, table=table)
195
+
196
+ # get all harvested records
197
+ count, records = repos.query(constraint={'where': "mdsource != 'local'", 'values': []})
198
+
199
+ if int(count) > 0:
200
+ LOGGER.info('Refreshing %s harvested records', count)
201
+ csw = CatalogueServiceWeb(url)
202
+
203
+ for rec in records:
204
+ source = \
205
+ getattr(rec,
206
+ context.md_core_model['mappings']['pycsw:Source'])
207
+ schema = \
208
+ getattr(rec,
209
+ context.md_core_model['mappings']['pycsw:Schema'])
210
+ identifier = \
211
+ getattr(rec,
212
+ context.md_core_model['mappings']['pycsw:Identifier'])
213
+
214
+ LOGGER.info('Harvesting %s (identifier = %s) ...',
215
+ source, identifier)
216
+ # TODO: find a smarter way of catching this
217
+ if schema == 'http://www.isotc211.org/2005/gmd':
218
+ schema = 'http://www.isotc211.org/schemas/2005/gmd/'
219
+ try:
220
+ csw.harvest(source, schema)
221
+ LOGGER.info(csw.response)
222
+ except Exception:
223
+ LOGGER.exception('Could not harvest')
224
+ else:
225
+ LOGGER.info('No harvested records')
226
+
227
+
228
+ def gen_sitemap(context, database, table, url, output_file):
229
+ """generate an XML sitemap from all records in repository"""
230
+
231
+ # get configuration and init repo connection
232
+ repos = repository.Repository(database, context, table=table)
233
+
234
+ # write out sitemap document
235
+ urlset = etree.Element(util.nspath_eval('sitemap:urlset',
236
+ context.namespaces),
237
+ nsmap=context.namespaces)
238
+
239
+ schema_loc = util.nspath_eval('xsi:schemaLocation', context.namespaces)
240
+
241
+ urlset.attrib[schema_loc] = \
242
+ '%s http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd' % \
243
+ context.namespaces['sitemap']
244
+
245
+ # get all records
246
+ count, records = repos.query(constraint={}, maxrecords=99999999)
247
+
248
+ LOGGER.info('Found %s records', count)
249
+
250
+ for rec in records:
251
+ url_ = etree.SubElement(urlset,
252
+ util.nspath_eval('sitemap:url',
253
+ context.namespaces))
254
+ uri = '%s?service=CSW&version=2.0.2&request=GetRepositoryItem&id=%s' % \
255
+ (url,
256
+ getattr(rec,
257
+ context.md_core_model['mappings']['pycsw:Identifier']))
258
+ etree.SubElement(url_,
259
+ util.nspath_eval('sitemap:loc',
260
+ context.namespaces)).text = uri
261
+
262
+ # write to file
263
+ LOGGER.info('Writing to %s', output_file)
264
+ with open(output_file, 'wb') as ofile:
265
+ ofile.write(etree.tostring(urlset, pretty_print=1,
266
+ encoding='utf8', xml_declaration=1))
267
+
268
+
269
+ def post_xml(url, xml, timeout=30):
270
+ """Execute HTTP XML POST request and print response"""
271
+
272
+ LOGGER.info('Executing HTTP POST request %s on server %s', xml, url)
273
+
274
+ from owslib.util import http_post
275
+ try:
276
+ with open(xml) as f:
277
+ return http_post(url=url, request=f.read(), timeout=timeout)
278
+ except Exception as err:
279
+ LOGGER.exception('HTTP XML POST error')
280
+ raise RuntimeError(err) from err
281
+
282
+
283
+ def get_sysprof():
284
+ """Get versions of dependencies"""
285
+
286
+ none = 'Module not found'
287
+
288
+ try:
289
+ import sqlalchemy
290
+ vsqlalchemy = sqlalchemy.__version__
291
+ except ImportError:
292
+ vsqlalchemy = none
293
+
294
+ try:
295
+ import pyproj
296
+ vpyproj = pyproj.__version__
297
+ except ImportError:
298
+ vpyproj = none
299
+
300
+ try:
301
+ import shapely
302
+ try:
303
+ vshapely = shapely.__version__
304
+ except AttributeError:
305
+ import shapely.geos
306
+ vshapely = shapely.geos.geos_capi_version
307
+ except ImportError:
308
+ vshapely = none
309
+
310
+ try:
311
+ import owslib
312
+ try:
313
+ vowslib = owslib.__version__
314
+ except AttributeError:
315
+ vowslib = 'Module found, version not specified'
316
+ except ImportError:
317
+ vowslib = none
318
+
319
+ return '''pycsw system profile
320
+ --------------------
321
+ Python version: %s
322
+ os: %s
323
+ SQLAlchemy: %s
324
+ Shapely: %s
325
+ lxml: %s
326
+ libxml2: %s
327
+ pyproj: %s
328
+ OWSLib: %s''' % (sys.version_info, sys.platform, vsqlalchemy,
329
+ vshapely, etree.__version__, etree.LIBXML_VERSION,
330
+ vpyproj, vowslib)
331
+
332
+
333
+ def validate_xml(xml, xsd):
334
+ """Validate XML document against XML Schema"""
335
+
336
+ LOGGER.info('Validating %s against schema %s', xml, xsd)
337
+
338
+ schema = etree.XMLSchema(file=xsd)
339
+
340
+ try:
341
+ tree = etree.parse(xml, PARSER)
342
+ schema.assertValid(tree)
343
+ return 'Valid'
344
+ except Exception as err:
345
+ LOGGER.exception('Invalid XML')
346
+ raise RuntimeError('ERROR: %s' % str(err)) from err
347
+
348
+
349
+ def delete_records(context, database, table):
350
+ """Deletes all records from repository"""
351
+
352
+ LOGGER.info('Deleting all records')
353
+
354
+ repo = repository.Repository(database, context, table=table)
355
+ repo.delete(constraint={'where': '', 'values': []})
356
+
357
+
358
+ def cli_option_verbosity(f):
359
+ def callback(ctx, param, value):
360
+ if value is not None:
361
+ logging.basicConfig(stream=sys.stdout,
362
+ level=getattr(logging, value))
363
+ return True
364
+
365
+ return click.option('--verbosity', '-v',
366
+ type=click.Choice(['ERROR', 'WARNING', 'INFO', 'DEBUG']),
367
+ help='Verbosity',
368
+ callback=callback)(f)
369
+
370
+
371
+ CLI_OPTION_CONFIG = click.option('--config', '-c', required=True,
372
+ type=click.Path(exists=True, resolve_path=True),
373
+ help='Path to pycsw configuration')
374
+
375
+ CLI_OPTION_YES = click.option('--yes', '-y', is_flag=True, default=False,
376
+ help='Bypass confirmation')
377
+
378
+ CLI_OPTION_YES_PROMPT = click.option('--yes', '-y', is_flag=True,
379
+ default=False,
380
+ prompt='This will delete all records! Continue?',
381
+ help='Bypass confirmation')
382
+
383
+
384
+ def cli_callbacks(f):
385
+ f = cli_option_verbosity(f)
386
+ return f
387
+
388
+
389
+ @click.group()
390
+ @click.version_option(version=__version__)
391
+ def cli():
392
+ pass
393
+
394
+
395
+ @click.command('setup-repository')
396
+ @cli_callbacks
397
+ @click.pass_context
398
+ @CLI_OPTION_CONFIG
399
+ def cli_setup_repository(ctx, config, verbosity):
400
+ """Create repository tables and indexes"""
401
+
402
+ with open(config, encoding='utf8') as fh:
403
+ cfg = yaml_load(fh)
404
+
405
+ try:
406
+ repository.setup(cfg['repository']['database'], table=cfg['repository'].get('table'))
407
+ except Exception as err:
408
+ msg = f'ERROR: Repository already exists: {err}'
409
+ raise click.ClickException(msg) from err
410
+
411
+
412
+ @click.command('load-records')
413
+ @cli_callbacks
414
+ @click.pass_context
415
+ @CLI_OPTION_CONFIG
416
+ @click.option('--path', '-p', 'path', required=True,
417
+ help='File or directory path to metadata records',
418
+ type=click.Path(exists=True, resolve_path=True, file_okay=True))
419
+ @click.option('--recursive', '-r', is_flag=True,
420
+ default=False, help='Bypass confirmation')
421
+ @CLI_OPTION_YES
422
+ def cli_load_records(ctx, config, path, recursive, yes, verbosity):
423
+ """Load metadata records from directory or file into repository"""
424
+
425
+ with open(config, encoding='utf8') as fh:
426
+ cfg = yaml_load(fh)
427
+
428
+ context = pconfig.StaticContext()
429
+
430
+ load_records(
431
+ context,
432
+ cfg['repository']['database'],
433
+ cfg['repository']['table'],
434
+ path,
435
+ recursive,
436
+ yes
437
+ )
438
+
439
+
440
+ @click.command('delete-records')
441
+ @cli_callbacks
442
+ @click.pass_context
443
+ @CLI_OPTION_CONFIG
444
+ @CLI_OPTION_YES_PROMPT
445
+ def cli_delete_records(ctx, config, yes, verbosity):
446
+ """Delete all records from repository"""
447
+
448
+ with open(config, encoding='utf8') as fh:
449
+ cfg = yaml_load(fh)
450
+
451
+ context = pconfig.StaticContext()
452
+
453
+ delete_records(
454
+ context,
455
+ cfg['repository']['database'],
456
+ cfg['repository']['table']
457
+ )
458
+
459
+
460
+ @click.command('export-records')
461
+ @cli_callbacks
462
+ @click.pass_context
463
+ @CLI_OPTION_CONFIG
464
+ @click.option('--path', '-p', 'path', required=True,
465
+ help='Directory path to metadata records',
466
+ type=click.Path(exists=True, resolve_path=True,
467
+ writable=True, file_okay=False))
468
+ def cli_export_records(ctx, config, path, verbosity):
469
+ """Dump metadata records from repository into directory"""
470
+
471
+ with open(config, encoding='utf8') as fh:
472
+ cfg = yaml_load(fh)
473
+
474
+ context = pconfig.StaticContext()
475
+
476
+ export_records(
477
+ context,
478
+ cfg['repository']['database'],
479
+ cfg['repository']['table'],
480
+ path
481
+ )
482
+
483
+
484
+ @click.command('rebuild-db-indexes')
485
+ @cli_callbacks
486
+ @click.pass_context
487
+ @CLI_OPTION_CONFIG
488
+ def cli_rebuild_db_indexes(ctx, config, verbosity):
489
+ """Rebuild repository database indexes"""
490
+
491
+ with open(config, encoding='utf8') as fh:
492
+ cfg = yaml_load(fh)
493
+
494
+ context = pconfig.StaticContext()
495
+
496
+ repo = repository.Repository(cfg['repository']['database'], context, table=cfg['repository'].get('table'))
497
+ repo.rebuild_db_indexes()
498
+
499
+
500
+ @click.command('optimize-db')
501
+ @cli_callbacks
502
+ @click.pass_context
503
+ @CLI_OPTION_CONFIG
504
+ def cli_optimize_db(ctx, config, verbosity):
505
+ """Optimize repository database"""
506
+
507
+ with open(config, encoding='utf8') as fh:
508
+ cfg = yaml_load(fh)
509
+
510
+ context = pconfig.StaticContext()
511
+
512
+ repo = repository.Repository(cfg['repository']['database'], context, table=cfg['repository'].get('table'))
513
+ repo.optimize_db()
514
+
515
+
516
+ @click.command('refresh-harvested-records')
517
+ @cli_callbacks
518
+ @click.pass_context
519
+ @CLI_OPTION_CONFIG
520
+ @click.option('--url', '-u', 'url', help='URL of harvest endpoint')
521
+ def cli_refresh_harvested_records(ctx, config, verbosity, url):
522
+ """Refresh / harvest non-local records in repository"""
523
+
524
+ with open(config, encoding='utf8') as fh:
525
+ cfg = yaml_load(fh)
526
+
527
+ context = pconfig.StaticContext()
528
+
529
+ refresh_harvested_records(
530
+ context,
531
+ cfg['repository']['database'],
532
+ cfg['repository']['table'],
533
+ url
534
+ )
535
+
536
+
537
+ @click.command('gen-sitemap')
538
+ @cli_callbacks
539
+ @click.pass_context
540
+ @CLI_OPTION_CONFIG
541
+ @click.option('--output', '-o', 'output', required=True,
542
+ help='Filepath to write sitemap',
543
+ type=click.Path(resolve_path=True, writable=True,
544
+ dir_okay=False))
545
+ def cli_gen_sitemap(ctx, config, output, verbosity):
546
+ """Generate XML Sitemap"""
547
+
548
+ with open(config, encoding='utf8') as fh:
549
+ cfg = yaml_load(fh)
550
+
551
+ context = pconfig.StaticContext()
552
+
553
+ gen_sitemap(
554
+ context,
555
+ cfg['repository']['database'],
556
+ cfg['repository']['table'],
557
+ cfg['server']['url'],
558
+ output
559
+ )
560
+
561
+
562
+ @click.command('post-xml')
563
+ @cli_callbacks
564
+ @click.pass_context
565
+ @click.option('--url', '-u', 'url', required=True, help='URL of CSW endpoint')
566
+ @click.option('--xml', '-x', 'xml', required=True,
567
+ help='XML file to POST',
568
+ type=click.Path(resolve_path=True, exists=True,
569
+ dir_okay=False))
570
+ @click.option('--timeout', '-t', 'timeout', default=30,
571
+ help='Timeout (in seconds) for HTTP requests')
572
+ def cli_post_xml(ctx, url, xml, timeout, verbosity):
573
+ """Execute a CSW request via HTTP POST"""
574
+
575
+ click.echo(post_xml(url, xml, timeout))
576
+
577
+
578
+ @click.command('validate-xml')
579
+ @cli_callbacks
580
+ @click.pass_context
581
+ @click.option('--xml', '-x', 'xml', required=True,
582
+ help='XML document',
583
+ type=click.Path(resolve_path=True, exists=True,
584
+ dir_okay=False))
585
+ @click.option('--xsd', '-s', 'xsd', required=True,
586
+ help='XML Schema document',
587
+ type=click.Path(resolve_path=True, exists=True,
588
+ dir_okay=False))
589
+ def cli_validate_xml(ctx, xml, xsd, verbosity):
590
+ """Validate an XML document against an XML Schema"""
591
+
592
+ validate_xml(xml, xsd)
593
+
594
+
595
+ @click.command('get-sysprof')
596
+ @click.pass_context
597
+ def cli_get_sysprof(ctx):
598
+ """Get versions of dependencies"""
599
+
600
+ click.echo(get_sysprof())
601
+
602
+
603
+ @click.command('migrate-config')
604
+ @cli_callbacks
605
+ @click.pass_context
606
+ @CLI_OPTION_CONFIG
607
+ def cli_migrate_config(ctx, config, verbosity):
608
+ """Migrate pycsw ini config to YAML"""
609
+
610
+ dict_ = {
611
+ 'server': {},
612
+ 'logging': {},
613
+ 'manager': {},
614
+ 'metadata': {
615
+ 'identification': {},
616
+ 'provider': {},
617
+ 'contact': {},
618
+ 'inspire': {}
619
+ },
620
+ 'profiles': [],
621
+ 'federatedcatalogues': [],
622
+ 'repository': {}
623
+ }
624
+
625
+ cfg = parse_ini_config(config)
626
+
627
+ for name, value in cfg.items('server'):
628
+ if name == 'loglevel':
629
+ dict_['logging']['level'] = value
630
+ elif name == 'logfile':
631
+ dict_['logging']['logfile'] = value
632
+ elif name == 'profiles':
633
+ dict_[name] = value.split(',')
634
+ elif name == 'federatedcatalogues':
635
+ dict_[name] = value.split(',')
636
+ else:
637
+ dict_['server'][name] = get_typed_value(value)
638
+
639
+ for name, value in cfg.items('metadata:main'):
640
+ if name.startswith('identification'):
641
+ new_key = name.replace('identification_', '')
642
+ if new_key == 'keywords':
643
+ dict_['metadata']['identification'][new_key] = value.split(',')
644
+ elif new_key == 'abstract':
645
+ dict_['metadata']['identification']['description'] = value
646
+ else:
647
+ dict_['metadata']['identification'][new_key] = get_typed_value(value)
648
+
649
+ if name.startswith('provider'):
650
+ new_key = name.replace('provider_', '')
651
+ dict_['metadata']['provider'][new_key] = get_typed_value(value)
652
+
653
+ if name.startswith('contact'):
654
+ new_key = name.replace('contact_', '')
655
+ dict_['metadata']['contact'][new_key] = get_typed_value(value)
656
+
657
+ for name, value in cfg.items('manager'):
658
+ if name == 'allowed_ips':
659
+ dict_['manager'][name] = value.split(',')
660
+ elif name == 'transactions':
661
+ dict_['manager'][name] = str2bool(value)
662
+ else:
663
+ dict_['manager'][name] = get_typed_value(value)
664
+
665
+ for name, value in cfg.items('repository'):
666
+ if name == 'facets':
667
+ dict_['repository'][name] = value.split(',')
668
+ else:
669
+ dict_['repository'][name] = get_typed_value(value)
670
+
671
+ for name, value in cfg.items('metadata:inspire'):
672
+ if name == 'languages_supported':
673
+ dict_['metadata']['inspire'][name] = value.split(',')
674
+ elif name == 'enabled':
675
+ dict_['metadata']['inspire'][name] = str2bool(value)
676
+ elif name == 'gemet_keywords':
677
+ dict_['metadata']['inspire'][name] = value.split(',')
678
+ elif name == 'temp_extent':
679
+ begin, end = value.split('/')
680
+ dict_['metadata']['inspire'][name] = {
681
+ 'begin': begin,
682
+ 'end': end
683
+ }
684
+ else:
685
+ dict_['metadata']['inspire'][name] = get_typed_value(value)
686
+
687
+ yaml_file = config.replace('.cfg', '.yml')
688
+ click.echo(f'Writing to {yaml_file}')
689
+ yaml_dump(dict_, yaml_file)
690
+
691
+
692
+ cli.add_command(cli_setup_repository)
693
+ cli.add_command(cli_load_records)
694
+ cli.add_command(cli_export_records)
695
+ cli.add_command(cli_delete_records)
696
+ cli.add_command(cli_rebuild_db_indexes)
697
+ cli.add_command(cli_optimize_db)
698
+ cli.add_command(cli_refresh_harvested_records)
699
+ cli.add_command(cli_gen_sitemap)
700
+ cli.add_command(cli_post_xml)
701
+ cli.add_command(cli_validate_xml)
702
+ cli.add_command(cli_get_sysprof)
703
+ cli.add_command(cli_migrate_config)