Skip to content

[Fixies #12540] PyCSW upgrade to version 3 #13112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion geonode/catalogue/backends/pycsw_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@
"pretty_print": "true",
"domainquerytype": "range",
"domaincounts": "true",
"profiles": "apiso,ebrim",
},
"profiles": {"apiso", "ebrim"},
"repository": {
"source": "geonode.catalogue.backends.pycsw_plugin.GeoNodeRepository",
"filter": "uuid IS NOT NULL",
"mappings": os.path.join(os.path.dirname(__file__), "pycsw_local_mappings.py"),
},
"logging": {"level": "ERROR"},
}


Expand Down
13 changes: 12 additions & 1 deletion geonode/catalogue/backends/pycsw_local_mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,29 @@
"pycsw:MdSource": "csw_mdsource",
"pycsw:InsertDate": "csw_insert_date",
"pycsw:XML": "metadata_xml",
"pycsw:Metadata": "metadata",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be metadata_xml since in pycsw doc:

  • pycsw:XML: full XML representation (deprecated; will be removed in a future release)
  • pycsw:Metadata: full metadata representation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed, I left it as it for now

"pycsw:MetadataType": "metadata_type",
"pycsw:AnyText": "csw_anytext",
"pycsw:Language": "language",
"pycsw:Title": "title",
"pycsw:Abstract": "raw_abstract",
"pycsw:Edition": "edition",
"pycsw:Keywords": "keyword_csv",
"pycsw:KeywordType": "keywordstype",
"pycsw:Themes": "csw_themes",
"pycsw:Format": "spatial_representation_type_string",
"pycsw:Source": "source",
"pycsw:Date": "date",
"pycsw:Modified": "date",
"pycsw:Type": "csw_type",
"pycsw:BoundingBox": "csw_wkt_geometry",
"pycsw:VertExtentMin": "csw_vert_extent_min",
"pycsw:VertExtentMax": "csw_vert_extent_max",
"pycsw:CRS": "csw_crs",
"pycsw:AlternateTitle": "alternate",
"pycsw:RevisionDate": "date",
"pycsw:CreationDate": "date",
"pycsw:PublicationDate": "date",
"pycsw:Organization": "organizationname",
"pycsw:OrganizationName": "organizationname",
"pycsw:SecurityConstraints": "securityconstraints",
"pycsw:ParentIdentifier": "parentidentifier",
Expand Down Expand Up @@ -78,6 +83,12 @@
"pycsw:Publisher": "publisher",
"pycsw:Contributor": "contributor",
"pycsw:Relation": "relation",
"pycsw:Platform": "platform",
"pycsw:Instrument": "instrument",
"pycsw:SensorType": "sensortype",
"pycsw:CloudCover": "cloudcover",
"pycsw:Bands": "bands",
"pycsw:Links": "download_links",
"pycsw:Contacts": "contacts",
},
}
2 changes: 1 addition & 1 deletion geonode/catalogue/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def test_given_a_request_for_multiple_dataset_should_return_multiple_value_in_xm
request = self.__request_factory_multiple()
response = csw_global_dispatch(request, self.dataset_filter_multiple)
root = ET.fromstring(response.content)
actual = root.find("{http://www.opengis.net/cat/csw/2.0.2}SearchResults").attrib["numberOfRecordsReturned"]
actual = root.find("{http://www.opengis.net/cat/csw/2.0.2}SearchResults").attrib["numberOfRecordsMatched"]
self.assertEqual(2, int(actual))

@staticmethod
Expand Down
12 changes: 6 additions & 6 deletions geonode/catalogue/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,12 @@ def opensearch_dispatch(request):
"""OpenSearch wrapper"""

ctx = {
"shortname": settings.PYCSW["CONFIGURATION"]["metadata:main"]["identification_title"],
"description": settings.PYCSW["CONFIGURATION"]["metadata:main"]["identification_abstract"],
"developer": settings.PYCSW["CONFIGURATION"]["metadata:main"]["contact_name"],
"contact": settings.PYCSW["CONFIGURATION"]["metadata:main"]["contact_email"],
"attribution": settings.PYCSW["CONFIGURATION"]["metadata:main"]["provider_name"],
"tags": settings.PYCSW["CONFIGURATION"]["metadata:main"]["identification_keywords"].replace(",", " "),
"shortname": settings.PYCSW["CONFIGURATION"]["metadata"]["identification"]["title"],
"description": settings.PYCSW["CONFIGURATION"]["metadata"]["identification"]["description"],
"developer": settings.PYCSW["CONFIGURATION"]["metadata"]["contact"]["name"],
"contact": settings.PYCSW["CONFIGURATION"]["metadata"]["contact"]["email"],
"attribution": settings.PYCSW["CONFIGURATION"]["metadata"]["provider"]["name"],
"tags": " ".join(settings.PYCSW["CONFIGURATION"]["metadata"]["identification"]["keywords"]),
"url": settings.SITEURL.rstrip("/") if settings.SITEURL.startswith("http") else settings.SITEURL,
}

Expand Down
2 changes: 1 addition & 1 deletion geonode/layers/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def dataset_feature_catalogue(request, layername, template="../../catalogue/temp
context_dict = {
"dataset": layer,
"attributes": attributes,
"metadata": settings.PYCSW["CONFIGURATION"]["metadata:main"],
"metadata": settings.PYCSW["CONFIGURATION"]["metadata"],
}
register_event(request, "view", layer)
return render(request, template, context=context_dict, content_type="application/xml")
Expand Down
75 changes: 42 additions & 33 deletions geonode/local_settings.py.geoserver.sample
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ PYCSW = {
"home": ".",
"url": CATALOGUE["default"]["URL"],
"encoding": "UTF-8",
"language": LANGUAGE_CODE,
"language": LANGUAGE_CODE if LANGUAGE_CODE in ("en", "fr", "el") else "en",
"maxrecords": "20",
"pretty_print": "true",
# 'domainquerytype': 'range',
Expand All @@ -191,43 +191,52 @@ PYCSW = {
"allowed_ips": "*",
# 'csw_harvest_pagesize': '10',
},
"metadata:main": {
"identification_title": "GeoNode Catalogue",
"identification_abstract": "GeoNode is an open source platform"
" that facilitates the creation, sharing, and collaborative use"
" of geospatial data",
"identification_keywords": "sdi, catalogue, discovery, metadata," " GeoNode",
"identification_keywords_type": "theme",
"identification_fees": "None",
"identification_accessconstraints": "None",
"provider_name": "Organization Name",
"provider_url": SITEURL,
"contact_name": "Lastname, Firstname",
"contact_position": "Position Title",
"contact_address": "Mailing Address",
"contact_city": "City",
"contact_stateorprovince": "Administrative Area",
"contact_postalcode": "Zip or Postal Code",
"contact_country": "Country",
"contact_phone": "+xx-xxx-xxx-xxxx",
"contact_fax": "+xx-xxx-xxx-xxxx",
"contact_email": "Email Address",
"contact_url": "Contact URL",
"contact_hours": "Hours of Service",
"contact_instructions": "During hours of service. Off on " "weekends.",
"contact_role": "pointOfContact",
},
"metadata:inspire": {
"enabled": "true",
"metadata": {
"inspire": {
"enabled": True,
"languages_supported": "eng,gre",
"default_language": "eng",
"date": "YYYY-MM-DD",
"gemet_keywords": "Utility and governmental services",
"conformity_service": "notEvaluated",
"contact_name": "Organization Name",
"contact_email": "Email Address",
"temp_extent": "YYYY-MM-DD/YYYY-MM-DD",
},
"temp_extent": {
"begin": "YYYY-MM-DD",
"end": "YYYY-MM-DD"
},
},
"identification": {
"title": "GeoNode Catalogue",
"description": "GeoNode is an open source platform"
" that facilitates the creation, sharing, and collaborative use"
" of geospatial data",
"keywords": "sdi, catalogue, discovery, metadata," " GeoNode",
"keywords_type": "theme",
"fees": "None",
"accessconstraints": "None",
},
"provider": {
"name": "Organization Name",
"url": SITEURL,
},
"contact": {
"name": "Lastname, Firstname",
"position": "Position Title",
"address": "Mailing Address",
"city": "City",
"stateorprovince": "Administrative Area",
"postalcode": "Zip or Postal Code",
"country": "Country",
"phone": "+xx-xxx-xxx-xxxx",
"fax": "+xx-xxx-xxx-xxxx",
"email": "Email Address",
"url": "Contact URL",
"hours": "Hours of Service",
"instructions": "During hours of service. Off on " "weekends.",
"role": "pointOfContact",
}
}
}
}

Expand Down Expand Up @@ -274,10 +283,10 @@ if GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY == "mapstore":
pycsw_config = PYCSW["CONFIGURATION"]
if pycsw_config:
pycsw_catalogue = {
("%s" % pycsw_config["metadata:main"]["identification_title"]): {
("%s" % pycsw_config["metadata"]["identification"]): {
"url": CATALOGUE["default"]["URL"],
"type": "csw",
"title": pycsw_config["metadata:main"]["identification_title"],
"title": pycsw_config["metadata"]["identification"]["title"],
"autoload": True,
}
}
Expand Down
85 changes: 47 additions & 38 deletions geonode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -1135,42 +1135,51 @@
"allowed_ips": "*",
# 'csw_harvest_pagesize': '10',
},
"metadata:main": {
"identification_title": "GeoNode Catalogue",
"identification_abstract": "GeoNode is an open source platform"
" that facilitates the creation, sharing, and collaborative use"
" of geospatial data",
"identification_keywords": "sdi, catalogue, discovery, metadata," " GeoNode",
"identification_keywords_type": "theme",
"identification_fees": "None",
"identification_accessconstraints": "None",
"provider_name": "Organization Name",
"provider_url": SITEURL,
"contact_name": "Lastname, Firstname",
"contact_position": "Position Title",
"contact_address": "Mailing Address",
"contact_city": "City",
"contact_stateorprovince": "Administrative Area",
"contact_postalcode": "Zip or Postal Code",
"contact_country": "Country",
"contact_phone": "+xx-xxx-xxx-xxxx",
"contact_fax": "+xx-xxx-xxx-xxxx",
"contact_email": "Email Address",
"contact_url": "Contact URL",
"contact_hours": "Hours of Service",
"contact_instructions": "During hours of service. Off on " "weekends.",
"contact_role": "pointOfContact",
},
"metadata:inspire": {
"enabled": "true",
"languages_supported": "eng,gre",
"default_language": "eng",
"date": "YYYY-MM-DD",
"gemet_keywords": "Utility and governmental services",
"conformity_service": "notEvaluated",
"contact_name": "Organization Name",
"contact_email": "Email Address",
"temp_extent": "YYYY-MM-DD/YYYY-MM-DD",
"metadata": {
"inspire": {
"enabled": True,
"languages_supported": ["eng", "gre"],
"default_language": "eng",
"date": "YYYY-MM-DD",
"gemet_keywords": ["Utility and governmental services"],
"conformity_service": "notEvaluated",
"contact_name": "Organization Name",
"contact_email": "Email Address",
"temp_extent": {
"begin": "YYYY-MM-DD",
"end": "YYYY-MM-DD",
},
},
"identification": {
"title": "GeoNode Catalogue",
"description": "GeoNode is an open source platform"
" that facilitates the creation, sharing, and collaborative use"
" of geospatial data",
"keywords": ["sdi", "catalogue", "discovery", "metadata", "GeoNode"],
"keywords_type": "theme",
"fees": "None",
"accessconstraints": "None",
},
"provider": {
"name": "Organization Name",
"url": SITEURL,
},
"contact": {
"name": "Lastname, Firstname",
"position": "Position Title",
"address": "Mailing Address",
"city": "City",
"stateorprovince": "Administrative Area",
"postalcode": "Zip or Postal Code",
"country": "Country",
"phone": "+xx-xxx-xxx-xxxx",
"fax": "+xx-xxx-xxx-xxxx",
"email": "Email Address",
"url": "Contact URL",
"hours": "Hours of Service",
"instructions": "During hours of service. Off on " "weekends.",
"role": "pointOfContact",
},
},
}
}
Expand Down Expand Up @@ -1454,10 +1463,10 @@ def get_geonode_catalogue_service():
pycsw_config = PYCSW["CONFIGURATION"]
if pycsw_config:
pycsw_catalogue = {
f"{pycsw_config['metadata:main']['identification_title']}": {
f"{pycsw_config['metadata']['identification']}": {
"url": CATALOGUE["default"]["URL"],
"type": "csw",
"title": pycsw_config["metadata:main"]["identification_title"],
"title": pycsw_config["metadata"]["identification"]["title"],
"autoload": True,
"layerOptions": {"tileSize": DEFAULT_TILE_SIZE},
}
Expand Down
6 changes: 3 additions & 3 deletions geonode/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@
site_url = settings.SITEURL.rstrip("/") if settings.SITEURL.startswith("http") else settings.SITEURL
json_data = {}
json_data["siteurl"] = site_url
json_data["name"] = settings.PYCSW["CONFIGURATION"]["metadata:main"]["identification_title"]
json_data["name"] = settings.PYCSW["CONFIGURATION"]["metadata"]["identification"]["title"]

Check warning on line 111 in geonode/views.py

View check run for this annotation

Codecov / codecov/patch

geonode/views.py#L111

Added line #L111 was not covered by tests

json_data["poc"] = {
"name": settings.PYCSW["CONFIGURATION"]["metadata:main"]["contact_name"],
"email": settings.PYCSW["CONFIGURATION"]["metadata:main"]["contact_email"],
"name": settings.PYCSW["CONFIGURATION"]["metadata"]["contact"]["name"],
"email": settings.PYCSW["CONFIGURATION"]["metadata"]["contact"]["email"],
"twitter": f"https://twitter.com/{settings.TWITTER_SITE}",
}

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ oauthlib==3.2.2
pyjwt==2.8.0

# geopython dependencies
git+https://github.com/geopython/[email protected]#egg=pycsw
pyproj<3.7.0
OWSLib==0.31.0
pycsw==2.6.1
SQLAlchemy==2.0.30 # required by PyCSW
Shapely==1.8.5.post1
mercantile==1.2.1
numpy==1.26.*
Jinja2==3.1.4

# # Apps with packages provided in GeoNode's PPA on Launchpad.

Expand Down
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,12 @@ install_requires =
# geopython dependencies
pyproj<3.7.0
OWSLib==0.31.0
pycsw==2.6.1
pycsw @ git+https://github.com/geopython/[email protected]#egg=pycsw
SQLAlchemy==2.0.30 # required by PyCSW
Shapely==1.8.5.post1
mercantile==1.2.1
numpy==1.26.*
Jinja2==3.1.4

# # Apps with packages provided in GeoNode's PPA on Launchpad.

Expand Down
Loading