From 5c67b73db35efabf79a8a5ca61cfdaed2d41125f Mon Sep 17 00:00:00 2001 From: speleophysics Date: Fri, 16 Apr 2021 10:57:37 -0500 Subject: [PATCH 01/16] changed all already exists errors to warnings --- owslib/wmts.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/owslib/wmts.py b/owslib/wmts.py index 174aa1bdc..015946381 100644 --- a/owslib/wmts.py +++ b/owslib/wmts.py @@ -233,8 +233,9 @@ def gather_layers(parent_elem, parent_metadata): parse_remote_metadata=parse_remote_metadata) if cm.id: if cm.id in self.contents: - raise KeyError('Content metadata for layer "%s" ' + msg=('Content metadata for layer "%s" ' 'already exists' % cm.id) + warnings.warn(msg, RuntimeWarning) self.contents[cm.id] = cm gather_layers(elem, cm) gather_layers(caps, None) @@ -244,8 +245,9 @@ def gather_layers(parent_elem, parent_metadata): tms = TileMatrixSet(elem) if tms.identifier: if tms.identifier in self.tilematrixsets: - raise KeyError('TileMatrixSet with identifier "%s" ' + msg = ('TileMatrixSet with identifier "%s" ' 'already exists' % tms.identifier) + warnings.warn(msg, RuntimeWarning) self.tilematrixsets[tms.identifier] = tms self.themes = {} @@ -253,8 +255,9 @@ def gather_layers(parent_elem, parent_metadata): theme = Theme(elem) if theme.identifier: if theme.identifier in self.themes: - raise KeyError('Theme with identifier "%s" already exists' + msg=('Theme with identifier "%s" already exists' % theme.identifier) + warnings.warn(msg, RuntimeWarning) self.themes[theme.identifier] = theme serviceMetadataURL = self._capabilities.find(_SERVICE_METADATA_URL_TAG) @@ -509,8 +512,9 @@ def __init__(self, elem): tm = TileMatrix(tilematrix) if tm.identifier: if tm.identifier in self.tilematrix: - raise KeyError('TileMatrix with identifier "%s" ' + msg = ('TileMatrix with identifier "%s" ' 'already exists' % tm.identifier) + warnings.warn(msg, RuntimeWarning) self.tilematrix[tm.identifier] = tm @@ -738,9 +742,10 @@ def __init__(self, elem, parent=None, index=0, parse_remote_metadata=False): for tmsl in tile_matrix_set_links: if tmsl.tilematrixset: if tmsl.tilematrixset in self.tilematrixsetlinks: - raise KeyError('TileMatrixSetLink with tilematrixset "%s"' + msg = ('TileMatrixSetLink with tilematrixset "%s"' ' already exists' % tmsl.tilematrixset) + warnings.warn(msg, RuntimeWarning) self.tilematrixsetlinks[tmsl.tilematrixset] = tmsl self.resourceURLs = [] From 1848bea97a9af6e2e5a69dad46af606c73cffb0c Mon Sep 17 00:00:00 2001 From: Brent Spillner Date: Sun, 7 Apr 2024 10:47:38 +1000 Subject: [PATCH 02/16] Removed dependency on the pytz library. --- etc/RPM/python-owslib.spec | 2 +- owslib/util.py | 20 ++++++++++++++++---- requirements.txt | 1 - tests/doctests/sml_52n_network.txt | 1 - tests/doctests/sml_ndbc_station.txt | 4 ++-- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/etc/RPM/python-owslib.spec b/etc/RPM/python-owslib.spec index 96f8599de..8dfad75df 100644 --- a/etc/RPM/python-owslib.spec +++ b/etc/RPM/python-owslib.spec @@ -25,7 +25,7 @@ BuildRequires: python-devel BuildRequires: python-setuptools BuildRequires: fdupes Requires: python -Requires: python-dateutil python-pytz +Requires: python-dateutil %description OWSLib is a Python package for client programming with Open Geospatial Consortium (OGC) web service (hence OWS) interface standards, and their related content models. diff --git a/owslib/util.py b/owslib/util.py index 7894aa729..c715b3ce0 100644 --- a/owslib/util.py +++ b/owslib/util.py @@ -12,8 +12,7 @@ import sys from collections import OrderedDict from dateutil import parser -from datetime import datetime, timedelta -import pytz +from datetime import datetime, timedelta, tzinfo from owslib.etree import etree, ParseError from owslib.namespaces import Namespaces from urllib.parse import urlsplit, urlencode, urlparse, parse_qs, urlunparse, parse_qsl @@ -38,6 +37,20 @@ class ServiceException(Exception): pass +# Allows marking timestamps as UTC without pulling in all of Pytz +class TimeZone_UTC(tzinfo): + def tzname(self, dt): + return "UTC" + + def utcoffset(self, dt): + return timedelta(0) + + def dst(self, dt): + return timedelta(0) + +tz_utc = TimeZone_UTC() + + # http://stackoverflow.com/questions/6256183/combine-two-dictionaries-of-dictionaries-python def dict_union(d1, d2): return dict((x, (dict_union(d1.get(x, {}), d2[x]) if isinstance(d2.get(x), dict) else d2.get(x, d1.get(x)))) @@ -649,8 +662,7 @@ def extract_time(element): except Exception: att = testXMLValue(element.attrib.get('indeterminatePosition'), True) if att and att == 'now': - dt = datetime.utcnow() - dt.replace(tzinfo=pytz.utc) + dt = datetime.utcnow().replace(tzinfo=tz_utc) else: dt = None return dt diff --git a/requirements.txt b/requirements.txt index c1b2c09bd..1531aa42f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ dataclasses; python_version < '3.7' lxml python-dateutil>=1.5 -pytz pyyaml requests>=1.0 diff --git a/tests/doctests/sml_52n_network.txt b/tests/doctests/sml_52n_network.txt index 010fbb6b5..94add7ddc 100644 --- a/tests/doctests/sml_52n_network.txt +++ b/tests/doctests/sml_52n_network.txt @@ -3,7 +3,6 @@ Imports >>> from tests.utils import resource_file >>> from owslib.swe.sensor.sml import SensorML >>> from dateutil import parser - >>> import pytz Initialize diff --git a/tests/doctests/sml_ndbc_station.txt b/tests/doctests/sml_ndbc_station.txt index bd2ecf3af..bda0e559a 100644 --- a/tests/doctests/sml_ndbc_station.txt +++ b/tests/doctests/sml_ndbc_station.txt @@ -3,7 +3,7 @@ Imports >>> from tests.utils import resource_file >>> from owslib.swe.sensor.sml import SensorML >>> from dateutil import parser - >>> import pytz + >>> from owslib.util import TimeZone_UTC Initialize @@ -104,7 +104,7 @@ History 2 >>> event = his[0] - >>> parser.parse(event.date).replace(tzinfo=pytz.utc).isoformat() + >>> parser.parse(event.date).replace(tzinfo=TimeZone_UTC()).isoformat() '2010-01-12T00:00:00+00:00' >>> event.description 'Deployment start event' From a8b0a2c0c5dd772838b53611ac4ff167ef7bc43f Mon Sep 17 00:00:00 2001 From: Paul van Genuchten Date: Fri, 4 Oct 2024 21:24:57 +0200 Subject: [PATCH 03/16] adds support for gmx:anchor in gmd:identifier, fixes #946 --- owslib/iso.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/owslib/iso.py b/owslib/iso.py index ae486b36b..c30a4c883 100644 --- a/owslib/iso.py +++ b/owslib/iso.py @@ -407,15 +407,26 @@ def __init__(self, md=None, identtype=None): self.uricode = [] _values = md.findall(util.nspath_eval( - 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:RS_Identifier/gmd:code/gco:CharacterString', + 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:MD_Identifier/gmd:code/gco:CharacterString', namespaces)) _values += md.findall(util.nspath_eval( - 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:MD_Identifier/gmd:code/gco:CharacterString', + 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:RS_Identifier/gmd:code/gco:CharacterString', namespaces)) for i in _values: val = util.testXMLValue(i) if val is not None: self.uricode.append(val) + + _values = md.findall(util.nspath_eval( + 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:MD_Identifier/gmd:code/gmx:Anchor', + namespaces)) + _values += md.findall(util.nspath_eval( + 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:RS_Identifier/gmd:code/gmx:Anchor', + namespaces)) + for i in _values: + val = util.testXMLValue(i.attrib.get('xlink:href'), True) + if val is not None: + self.uricode.append(val) self.uricodespace = [] for i in md.findall(util.nspath_eval( From b9cd08b02f1c14b0e9c924ac445046f20434a590 Mon Sep 17 00:00:00 2001 From: Seth G Date: Sun, 6 Oct 2024 19:34:37 +0200 Subject: [PATCH 04/16] WFS 2.0 URL building (#612) --- owslib/feature/__init__.py | 7 ++----- owslib/util.py | 4 ++-- tests/test_util.py | 7 +++++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/owslib/feature/__init__.py b/owslib/feature/__init__.py index 9f3de0f14..b46ff9511 100644 --- a/owslib/feature/__init__.py +++ b/owslib/feature/__init__.py @@ -9,7 +9,7 @@ from urllib.parse import urlencode from owslib.crs import Crs -from owslib.util import Authentication +from owslib.util import Authentication, build_get_url from owslib.feature.schema import get_schema from owslib.feature.postrequest import PostRequest_1_1_0, PostRequest_2_0_0 @@ -209,7 +209,6 @@ def getGETGetFeatureRequest( if m.get("type").lower() == method.lower() ) ) - base_url = base_url if base_url.endswith("?") else base_url + "?" request = {"service": "WFS", "version": self.version, "request": "GetFeature"} @@ -248,9 +247,7 @@ def getGETGetFeatureRequest( if outputFormat is not None: request["outputFormat"] = outputFormat - data = urlencode(request, doseq=True) - - return base_url + data + return build_get_url(base_url, request) def getPOSTGetFeatureRequest( self, diff --git a/owslib/util.py b/owslib/util.py index 5e1e560e3..dfc16b32e 100644 --- a/owslib/util.py +++ b/owslib/util.py @@ -566,7 +566,7 @@ def getNamespace(element): return "" -def build_get_url(base_url, params, overwrite=False): +def build_get_url(base_url, params, overwrite=False, doseq=False): ''' Utility function to build a full HTTP GET URL from the service base URL and a dictionary of HTTP parameters. TODO: handle parameters case-insensitive? @@ -598,7 +598,7 @@ def build_get_url(base_url, params, overwrite=False): if key not in pars: qs.append((key, value)) - urlqs = urlencode(tuple(qs)) + urlqs = urlencode(tuple(qs), doseq=doseq) return base_url.split('?')[0] + '?' + urlqs diff --git a/tests/test_util.py b/tests/test_util.py index 975822b40..70a9148d6 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -28,6 +28,7 @@ def test_clean_ows_url(): def test_build_get_url(): assert build_get_url("http://example.org/wps", {'service': 'WPS'}) == 'http://example.org/wps?service=WPS' assert build_get_url("http://example.org/wms", {'SERVICE': 'wms'}) == 'http://example.org/wms?SERVICE=wms' + assert build_get_url("http://example.org/wms?map=/path/to/foo.map&", {'SERVICE': 'wms'}) == 'http://example.org/wms?map=%2Fpath%2Fto%2Ffoo.map&SERVICE=wms' assert build_get_url("http://example.org/wps?service=WPS", {'request': 'GetCapabilities'}) == \ 'http://example.org/wps?service=WPS&request=GetCapabilities' assert build_get_url("http://example.org/wps?service=WPS", {'request': 'GetCapabilities'}) == \ @@ -38,6 +39,12 @@ def test_build_get_url(): # Parameter is case-senstive assert build_get_url("http://example.org/ows?SERVICE=WPS", {'service': 'WMS'}) == \ 'http://example.org/ows?SERVICE=WPS&service=WMS' + # Test with trailing ampersand and doseq False (default) + assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1,2]}, doseq=False) == \ + 'http://example.org/ows?SERVICE=WFS&typename=test&keys=%5B1%2C+2%5D' + # Test with trailing ampersand and doseq True + assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1,2]}, doseq=True) == \ + 'http://example.org/ows?SERVICE=WFS&typename=test&keys=1&keys=2' def test_build_get_url_overwrite(): From 3e54828815a1f981e362bb84f64263ffded25cd2 Mon Sep 17 00:00:00 2001 From: sethg Date: Tue, 8 Oct 2024 09:09:51 +0200 Subject: [PATCH 05/16] Lint fixes --- owslib/wmts.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/owslib/wmts.py b/owslib/wmts.py index 4a590f316..494bbdf0e 100644 --- a/owslib/wmts.py +++ b/owslib/wmts.py @@ -241,8 +241,8 @@ def gather_layers(parent_elem, parent_metadata): parse_remote_metadata=parse_remote_metadata) if cm.id: if cm.id in self.contents: - msg=('Content metadata for layer "%s" ' - 'already exists' % cm.id) + msg = ('Content metadata for layer "%s" ' + 'already exists' % cm.id) warnings.warn(msg, RuntimeWarning) self.contents[cm.id] = cm gather_layers(elem, cm) @@ -254,7 +254,7 @@ def gather_layers(parent_elem, parent_metadata): if tms.identifier: if tms.identifier in self.tilematrixsets: msg = ('TileMatrixSet with identifier "%s" ' - 'already exists' % tms.identifier) + 'already exists' % tms.identifier) warnings.warn(msg, RuntimeWarning) self.tilematrixsets[tms.identifier] = tms @@ -263,8 +263,8 @@ def gather_layers(parent_elem, parent_metadata): theme = Theme(elem) if theme.identifier: if theme.identifier in self.themes: - msg=('Theme with identifier "%s" already exists' - % theme.identifier) + msg = ('Theme with identifier "%s" already exists' + % theme.identifier) warnings.warn(msg, RuntimeWarning) self.themes[theme.identifier] = theme @@ -523,7 +523,7 @@ def __init__(self, elem): if tm.identifier: if tm.identifier in self.tilematrix: msg = ('TileMatrix with identifier "%s" ' - 'already exists' % tm.identifier) + 'already exists' % tm.identifier) warnings.warn(msg, RuntimeWarning) self.tilematrix[tm.identifier] = tm @@ -753,8 +753,7 @@ def __init__(self, elem, parent=None, index=0, parse_remote_metadata=False): if tmsl.tilematrixset: if tmsl.tilematrixset in self.tilematrixsetlinks: msg = ('TileMatrixSetLink with tilematrixset "%s"' - ' already exists' % - tmsl.tilematrixset) + ' already exists' % tmsl.tilematrixset) warnings.warn(msg, RuntimeWarning) self.tilematrixsetlinks[tmsl.tilematrixset] = tmsl From a49b4859203d290b2265bc208ef32622b807653c Mon Sep 17 00:00:00 2001 From: Brent Date: Tue, 8 Oct 2024 17:39:33 +1000 Subject: [PATCH 06/16] Updated to land on current master, reflects new OWSLib requirement for Python version 3.10 or beyond (although not material to the issue solved in this branch) --- requirements.txt | 2 +- setup.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1531aa42f..e8a1938ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ dataclasses; python_version < '3.7' lxml -python-dateutil>=1.5 +python-dateutil pyyaml requests>=1.0 diff --git a/setup.py b/setup.py index ed1d6eccb..e0698fd2d 100644 --- a/setup.py +++ b/setup.py @@ -88,7 +88,7 @@ def get_package_version(): maintainer_email='tomkralidis@gmail.com', url='https://owslib.readthedocs.io', install_requires=reqs, - python_requires='>=3.6', + python_requires='>=3.10', cmdclass={'test': PyTest}, packages=find_packages(exclude=["docs", "etc", "examples", "tests"]), classifiers=[ @@ -100,9 +100,9 @@ def get_package_version(): 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Topic :: Scientific/Engineering :: GIS', ] ) From ec5b5b9ca83544ae34bc1a8a6c9fed908fc0dead Mon Sep 17 00:00:00 2001 From: Brent Date: Tue, 8 Oct 2024 19:04:42 +1000 Subject: [PATCH 07/16] Removing pytz dependency from requirements.txt after pruning all merge conflicts. --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 864dc07c9..f4d789801 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ lxml python-dateutil -pytz pyyaml requests From 8583d5a29422ac52101e837d111cf0be6562ea07 Mon Sep 17 00:00:00 2001 From: Brent Date: Tue, 8 Oct 2024 19:31:15 +1000 Subject: [PATCH 08/16] Cosmetic edits to pass flake8 style checks in CI pipeline. --- owslib/util.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/owslib/util.py b/owslib/util.py index d9ca072f6..439814f91 100644 --- a/owslib/util.py +++ b/owslib/util.py @@ -38,14 +38,15 @@ class ServiceException(Exception): # Allows marking timestamps as UTC without pulling in all of Pytz class TimeZone_UTC(tzinfo): - def tzname(self, dt): - return "UTC" + def tzname(self, dt): + return "UTC" - def utcoffset(self, dt): - return timedelta(0) + def utcoffset(self, dt): + return timedelta(0) + + def dst(self, dt): + return timedelta(0) - def dst(self, dt): - return timedelta(0) tz_utc = TimeZone_UTC() From 3824231cf23249500d9d0fe89c679b9c7dac5970 Mon Sep 17 00:00:00 2001 From: Paul van Genuchten Date: Tue, 8 Oct 2024 10:02:49 +0200 Subject: [PATCH 09/16] add tests for anchor tests --- owslib/iso.py | 22 +- tests/resources/csw_iso_identifier.xml | 607 +++++++++++++++++++++++++ tests/test_iso_parsing.py | 18 + 3 files changed, 643 insertions(+), 4 deletions(-) create mode 100644 tests/resources/csw_iso_identifier.xml diff --git a/owslib/iso.py b/owslib/iso.py index c30a4c883..d1d191d92 100644 --- a/owslib/iso.py +++ b/owslib/iso.py @@ -414,7 +414,7 @@ def __init__(self, md=None, identtype=None): namespaces)) for i in _values: val = util.testXMLValue(i) - if val is not None: + if val not in [None,'']: self.uricode.append(val) _values = md.findall(util.nspath_eval( @@ -424,17 +424,31 @@ def __init__(self, md=None, identtype=None): 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:RS_Identifier/gmd:code/gmx:Anchor', namespaces)) for i in _values: - val = util.testXMLValue(i.attrib.get('xlink:href'), True) - if val is not None: + val = util.testXMLValue(i) + val1 = i.attrib.get(util.nspath_eval('xlink:href', namespaces)) + if val1 not in [None,'']: + self.uricode.append(val1) + elif val not in [None,'']: self.uricode.append(val) + self.uricodespace = [] for i in md.findall(util.nspath_eval( 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:RS_Identifier/gmd:codeSpace/gco:CharacterString', namespaces)): val = util.testXMLValue(i) - if val is not None: + if val not in [None,'']: self.uricodespace.append(val) + for i in md.findall(util.nspath_eval( + 'gmd:citation/gmd:CI_Citation/gmd:identifier/gmd:RS_Identifier/gmd:codeSpace/gmx:Anchor', + namespaces)): + val = util.testXMLValue(i) + val1 = i.attrib.get(util.nspath_eval('xlink:href', namespaces)) + if val1 not in [None,'']: + self.uricode.append(val1) + elif val not in [None,'']: + self.uricode.append(val) + self.date = [] self.datetype = [] diff --git a/tests/resources/csw_iso_identifier.xml b/tests/resources/csw_iso_identifier.xml new file mode 100644 index 000000000..64dc86fce --- /dev/null +++ b/tests/resources/csw_iso_identifier.xml @@ -0,0 +1,607 @@ + + + + f44dac86-2228-412f-8355-e56446ca9933 + + + Nederlands; Vlaams + + + dataset + + + + + + + + Ministerie van Defensie, Koninklijke Marine, Dienst der Hydrografie + + + Hoofd Gegevens Beheer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + niet beschikbaar + + + + + + + https://www.defensie.nl/onderwerpen/hydrografie/downloads/publicaties/2024/07/25/beschikbaarheid-online-van-data-van-de-dienst-der-hydrografie + + + + + + + contactpunt + + + + + 2024-08-28 + + + ISO 19115 + + + Nederlands metadata profiel op ISO 19115 voor geografie 2.1.0 + + + + + + + ETRS89-GRS80 + + + + + + + + + + + Eemsmonding volgens het Eems-Dollardverdrag + + + + + 2020-10-05 + + + revisie + + + + + + + b3ed10bc-479a-4277-9683-56c908a7fa83 + + + + + + + Eemsmonding volgens het Eems-Dollardverdrag + + + + + + continu geactualiseerd + + + + + Ministerie van Defensie, Koninklijke Marine, Dienst der Hydrografie + + + Ministerie van Defensie, Koninklijke Marine, Dienst der Hydrografie + + + Hoofd Gegevens Beheer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + niet beschikbaar + + + + + + + https://www.defensie.nl/onderwerpen/hydrografie/downloads/publicaties/2024/07/25/beschikbaarheid-online-van-data-van-de-dienst-der-hydrografie + + + + + + + contactpunt + + + + + + + 5-jaarlijks + + + 2020 + + + + + + + Gebiedsbeheer, gebieden waar beperkingen gelden, gereguleerde gebieden en rapportage-eenheden + + + theme + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + publicatie + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeutheme-theme + + + + + + + + + + + Eems-Dollardverdrag + + + Eems + + + Dollard + + + basisset NOVEX + + + + + + + Nationaal + + + theme + + + + + Ruimtelijke dekking + + + + + 2019-05-22 + + + publicatie + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeumetadatacodelistSpatialScope-SpatialScope + + + + + + + + + + + + + + + + + + + De verstrekte gegevens mogen niet gebruikt worden als middel om mee te navigeren, aangezien zij op zichzelf staan en niet bijgewerkt zijn conform de Berichten aan Zeevarenden. + + + De Dienst der Hydrografie behoudt zich het recht voor haar Morele rechten (art. 6 bis Conventie van Bern) uit te oefenen op het gereproduceerde materiaal, waarin de verstrekte gegevens verwerkt zijn. + + + + + + + anders + + + Geen beperkingen + + + Er zijn geen condities voor toegang en gebruik + + + + + + + anders + + + Geen beperkingen voor publieke toegang + + + + + + + + + + + + + + + + vector + + + + + + + 50000 + + + + + + + Nederlands; Vlaams + + + utf8 + + + oceans + + + + + Noordzee en binnenwater + + + + + 2.4506 + + + 7.9872 + + + 50.9152 + + + 54.0807 + + + + + + + + + + + + + + gml+xml + + + GML, version 3.2.1 + + + Data specificatie hydrografie + + + + + + + + + + + + + Hoofd Gegevens Beheer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + hydrologistiek@mindef.nl + + + + + + + www.defensie.nl/hydro + + + + + + + distributeur + + + + + + + + + + + https://inspire1.bathy.online/geoserver/MarineRegion/wms?service=WMS&version=1.3.0&request=GetCapabilities + + + OGC:WMS + + + view + + + ManagementRestrictionOrRegulationZone + + + Marine Region + + + + + + + https://inspire1.bathy.online/geoserver/MarineRegion/wfs?service=WFS&version=2.0.0&request=GetCapabilities + + + OGC:WFS + + + download + + + MarineRegion:ManagementRestrictionOrRegulationZone + + + Marine Region + + + + + + + https://inspire1.bathy.online/atom/b3ed10bc-479a-4277-9683-56c908a7fa83.atom + + + INSPIRE Atom + + + download + + + ManagementRestrictionOrRegulationZone + + + accessPoint + + + download + + + + + + + dvd + + + + + + + + + + + + + dataset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VERORDENING (EU) Nr. 1089/2010 VAN DE COMMISSIE van 23 november 2010 ter uitvoering van Richtlijn 2007/2/EG van het Europees Parlement en de Raad betreffende de interoperabiliteit van verzamelingen ruimtelijke gegevens en van diensten met betrekking tot ruimtelijke gegevens + + + + + 2010-12-08 + + + publicatie + + + + + + + Dataset is geharmoniseerd + + + true + + + + + + + + + + + + + + Ministerie van Defensie, Koninklijke Marine, Dienst der Hydrografie + + + + + + + + + + diff --git a/tests/test_iso_parsing.py b/tests/test_iso_parsing.py index 6997c6da0..737539eee 100644 --- a/tests/test_iso_parsing.py +++ b/tests/test_iso_parsing.py @@ -595,3 +595,21 @@ def test_md_parsing_keywords_no_anchor(): assert iden.keywords[1].keywords[1].url is None assert iden.keywords[1].keywords[2].name == 'parcelles cadastrales' assert iden.keywords[1].keywords[2].url is None + +def test_md_indentifier_anchor(): + """Test the parsing of identifier where the id is defined by a + gmx:Anchor + + MD_Metadata record available in + tests/resources/csw_iso_identifier.xml + + """ + md_resource = get_md_resource( + 'tests/resources/csw_iso_identifier.xml') + md = MD_Metadata(md_resource) + assert type(md) is MD_Metadata + assert md.referencesystem.code == 'ETRS89-GRS80' + iden = md.identification[0] + assert_list(iden.uricode, 1) + assert iden.uricode[0] == 'https://www.nationaalgeoregister.nl/geonetwork/srv/metadata/f44dac86-2228-412f-8355-e56446ca9933' + \ No newline at end of file From ace5c219f1fa8fe3f0d4d617b5d02a9e346eba85 Mon Sep 17 00:00:00 2001 From: Lachlan Partington Date: Mon, 30 Sep 2024 13:41:32 +0800 Subject: [PATCH 10/16] Add srsname to wfs200.py getfeature GET request - not added to the POST request (same behaviour as wfs110.py implementation) --- owslib/feature/__init__.py | 10 ++++++++++ owslib/feature/wfs200.py | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/owslib/feature/__init__.py b/owslib/feature/__init__.py index b46ff9511..7b8a23058 100644 --- a/owslib/feature/__init__.py +++ b/owslib/feature/__init__.py @@ -160,6 +160,7 @@ def getGETGetFeatureRequest( featureversion=None, propertyname=None, maxfeatures=None, + srsname=None, storedQueryID=None, storedQueryParams=None, outputFormat=None, @@ -183,6 +184,8 @@ def getGETGetFeatureRequest( List of feature property names. '*' matches all. maxfeatures : int Maximum number of features to be returned. + srsname: string + EPSG code to request the data in method : string Qualified name of the HTTP DCP method to use. outputFormat: string (optional) @@ -238,6 +241,13 @@ def getGETGetFeatureRequest( request["count"] = str(maxfeatures) else: request["maxfeatures"] = str(maxfeatures) + if srsname: + request["srsname"] = str(srsname) + + # Check if desired SRS is supported by the service for each + # typename. Warning will be thrown if that SRS is not allowed. + for name in typename: + _ = self.getSRS(srsname, name) if startindex: request["startindex"] = str(startindex) if storedQueryID: diff --git a/owslib/feature/wfs200.py b/owslib/feature/wfs200.py index 651eaaafb..3825da2a6 100644 --- a/owslib/feature/wfs200.py +++ b/owslib/feature/wfs200.py @@ -226,6 +226,7 @@ def getfeature( featureversion=None, propertyname=None, maxfeatures=None, + srsname=None, storedQueryID=None, storedQueryParams=None, method="Get", @@ -254,6 +255,8 @@ def getfeature( For Post request, leave blank (None) to get all properties. maxfeatures : int Maximum number of features to be returned. + srsname: string + EPSG code to request the data in storedQueryID : string A name identifying a prepared set available in WFS-service storedQueryParams : dict @@ -298,6 +301,7 @@ def getfeature( featureversion, propertyname, maxfeatures, + srsname, storedQueryID, storedQueryParams, outputFormat, From d14d447d17ad45bca6f56c119bfb59021417575a Mon Sep 17 00:00:00 2001 From: Lachlan Partington Date: Wed, 9 Oct 2024 10:19:31 +0800 Subject: [PATCH 11/16] Add test case for WFS 2.0.0 srsname. Change SERVICE_URL for all cases to https://services.ga.gov.au/gis/stratunits/ows. --- tests/test_wfs_generic.py | 109 +++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 59 deletions(-) diff --git a/tests/test_wfs_generic.py b/tests/test_wfs_generic.py index 9413845ce..44daa993b 100644 --- a/tests/test_wfs_generic.py +++ b/tests/test_wfs_generic.py @@ -6,8 +6,7 @@ import json import pytest -SERVICE_URL = 'https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288' - +SERVICE_URL = 'https://services.ga.gov.au/gis/stratunits/ows' def test_caps_info(): getcapsin = open(resource_file("wfs_HSRS_GetCapabilities_1_1_0.xml"), "rb").read() @@ -59,59 +58,50 @@ def test_verbOptions_wfs_100(): assert len(verbOptions[0]) == 2 -@pytest.mark.xfail @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_outputformat_wfs_100(): - wfs = WebFeatureService('https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.0.0') + wfs = WebFeatureService(SERVICE_URL, version='1.0.0') feature = wfs.getfeature( - typename=['sb:Project_Area'], maxfeatures=1, propertyname=None, outputFormat='application/json') + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json') assert len(json.loads(feature.read())['features']) == 1 -@pytest.mark.xfail @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_outputformat_wfs_110(): - wfs = WebFeatureService('https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.1.0') + wfs = WebFeatureService(SERVICE_URL, version='1.1.0') feature = wfs.getfeature( - typename=['sb:Project_Area'], maxfeatures=1, propertyname=None, outputFormat='application/json') + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json') assert len(json.loads(feature.read())['features']) == 1 -@pytest.mark.xfail @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_outputformat_wfs_200(): - wfs = WebFeatureService('https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='2.0.0') + wfs = WebFeatureService(SERVICE_URL, version='2.0.0') feature = wfs.getfeature( - typename=['sb:Project_Area'], maxfeatures=1, propertyname=None, outputFormat='application/json') + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json') assert len(json.loads(feature.read())['features']) == 1 -@pytest.mark.xfail @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_srsname_wfs_100(): - wfs = WebFeatureService('https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.0.0') + wfs = WebFeatureService(SERVICE_URL, version='1.0.0') # ServiceException: Unable to support srsName: EPSG:99999999 with pytest.raises(ServiceException): feature = wfs.getfeature( - typename=['sb:Project_Area'], maxfeatures=1, propertyname=None, outputFormat='application/json', + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json', srsname="EPSG:99999999") - wfs = WebFeatureService('https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.0.0') + wfs = WebFeatureService(SERVICE_URL, version='1.0.0') feature = wfs.getfeature( - typename=['sb:Project_Area'], maxfeatures=1, propertyname=None, outputFormat='application/json', + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json', srsname="urn:x-ogc:def:crs:EPSG:4326") assert len(json.loads(feature.read())['features']) == 1 @@ -121,73 +111,76 @@ def test_srsname_wfs_100(): @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_srsname_wfs_110(): - wfs = WebFeatureService( - 'https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.1.0') + wfs = WebFeatureService(SERVICE_URL, version='1.1.0') # ServiceException: Unable to support srsName: EPSG:99999999 with pytest.raises(ServiceException): feature = wfs.getfeature( - typename=['sb:Project_Area'], maxfeatures=1, propertyname=None, outputFormat='application/json', + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json', srsname="EPSG:99999999") - wfs = WebFeatureService( - 'https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.0.0') + wfs = WebFeatureService(SERVICE_URL, version='1.1.0') feature = wfs.getfeature( - typename=['sb:Project_Area'], maxfeatures=1, propertyname=None, outputFormat='application/json', + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json', + srsname="urn:x-ogc:def:crs:EPSG:4326") + assert len(json.loads(feature.read())['features']) == 1 + + +@pytest.mark.online +@pytest.mark.skipif(not service_ok(SERVICE_URL), + reason="WFS service is unreachable") +def test_srsname_wfs_200(): + wfs = WebFeatureService(SERVICE_URL, version='2.0.0') + # ServiceException: Unable to support srsName: EPSG:99999999 + with pytest.raises(ServiceException): + feature = wfs.getfeature( + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json', + srsname="EPSG:99999999") + + wfs = WebFeatureService(SERVICE_URL, version='2.0.0') + feature = wfs.getfeature( + typename=['stratunit:StratigraphicUnit'], maxfeatures=1, propertyname=None, outputFormat='application/json', srsname="urn:x-ogc:def:crs:EPSG:4326") assert len(json.loads(feature.read())['features']) == 1 -@pytest.mark.xfail @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_schema_wfs_100(): - wfs = WebFeatureService( - 'https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.0.0') - schema = wfs.get_schema('footprint') - assert len(schema['properties']) == 4 - assert schema['properties']['summary'] == 'string' - assert schema['geometry'] == 'Polygon' + wfs = WebFeatureService(SERVICE_URL, version='1.0.0') + schema = wfs.get_schema('stratunit:StratigraphicUnit') + assert len(schema['properties']) == 33 + assert schema['properties']['DESCRIPTION'] == 'string' + assert schema['geometry'] is None -@pytest.mark.xfail @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_schema_wfs_110(): - wfs = WebFeatureService( - 'https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='1.1.0') - schema = wfs.get_schema('footprint') - assert len(schema['properties']) == 4 - assert schema['properties']['summary'] == 'string' - assert schema['geometry'] == '3D Polygon' + wfs = WebFeatureService(SERVICE_URL, version='1.1.0') + schema = wfs.get_schema('stratunit:StratigraphicUnit') + assert len(schema['properties']) == 33 + assert schema['properties']['DESCRIPTION'] == 'string' + assert schema['geometry'] is None -@pytest.mark.xfail @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_schema_wfs_200(): - wfs = WebFeatureService( - 'https://www.sciencebase.gov/catalogMaps/mapping/ows/53398e51e4b0db25ad10d288', - version='2.0.0') - schema = wfs.get_schema('footprint') - assert len(schema['properties']) == 4 - assert schema['properties']['summary'] == 'string' - assert schema['geometry'] == '3D Polygon' + wfs = WebFeatureService(SERVICE_URL, version='2.0.0') + schema = wfs.get_schema('stratunit:StratigraphicUnit') + assert len(schema['properties']) == 33 + assert schema['properties']['DESCRIPTION'] == 'string' + assert schema['geometry'] is None @pytest.mark.online @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_xmlfilter_wfs_110(): - wfs = WebFeatureService( - 'https://services.ga.gov.au/gis/stratunits/ows', - version='1.1.0') + wfs = WebFeatureService(SERVICE_URL, version='1.1.0') filter_prop = PropertyIsLike(propertyname='stratunit:GEOLOGICHISTORY', literal='Cisuralian - Guadalupian', matchCase=True) @@ -203,9 +196,7 @@ def test_xmlfilter_wfs_110(): @pytest.mark.skipif(not service_ok(SERVICE_URL), reason="WFS service is unreachable") def test_xmlfilter_wfs_200(): - wfs = WebFeatureService( - 'https://services.ga.gov.au/gis/stratunits/ows', - version='2.0.0') + wfs = WebFeatureService(SERVICE_URL, version='2.0.0') filter_prop = PropertyIsLike(propertyname='stratunit:geologichistory', literal='Cisuralian - Guadalupian', matchCase=True) From b80120b6254a6d529b110453a1795473a4e6a33b Mon Sep 17 00:00:00 2001 From: Brent Date: Fri, 11 Oct 2024 06:25:33 +1000 Subject: [PATCH 12/16] Added a simple test for time zone normalization to UTC --- tests/test_util.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_util.py b/tests/test_util.py index 70a9148d6..1b9ebd328 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,6 +1,7 @@ # -*- coding: UTF-8 -*- import codecs -from owslib.util import clean_ows_url, build_get_url, strip_bom +from owslib.util import clean_ows_url, build_get_url, strip_bom, tz_utc +from datetime import datetime, timezone def test_strip_bom(): @@ -51,3 +52,10 @@ def test_build_get_url_overwrite(): # Use overwrite flag assert build_get_url("http://example.org/ows?SERVICE=WPS", {'SERVICE': 'WMS'}, overwrite=True) == \ 'http://example.org/ows?SERVICE=WMS' + + +def test_time_zone_utc(): + now = datetime.utcnow() + as_utc = now.replace(tzinfo=tz_utc) + assert(as_utc.isoformat()[-6:] == "+00:00") + From bcc4b20715167d05ee9c03de0c6cdb0a104a4afd Mon Sep 17 00:00:00 2001 From: Brent Date: Fri, 11 Oct 2024 06:56:13 +1000 Subject: [PATCH 13/16] Added a test for owslib/utils.py::extract_time() --- tests/test_util.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_util.py b/tests/test_util.py index 1b9ebd328..f8d47ec9c 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,6 +1,7 @@ # -*- coding: UTF-8 -*- import codecs -from owslib.util import clean_ows_url, build_get_url, strip_bom, tz_utc +from owslib.util import clean_ows_url, build_get_url, strip_bom, extract_time, tz_utc +from owslib.etree import etree from datetime import datetime, timezone @@ -59,3 +60,11 @@ def test_time_zone_utc(): as_utc = now.replace(tzinfo=tz_utc) assert(as_utc.isoformat()[-6:] == "+00:00") + +def test_extract_time(): + definite_sample = "2006-07-27T21:10:00Z" + indefinite_sample = "" + start = extract_time(etree.fromstring(definite_sample)) + assert(start.isoformat()[-6:] == "+00:00") + stop = extract_time(etree.fromstring(indefinite_sample)) + assert(stop.isoformat()[-6:] == "+00:00") From 1058b0b8565f919be67b2dc3260440dc4664fd8c Mon Sep 17 00:00:00 2001 From: Brent Date: Fri, 11 Oct 2024 07:25:52 +1000 Subject: [PATCH 14/16] Replaced stub TimeZone_UTC() class with the standard datetime.timezone.utc. This drops support for Python 3.8 and earlier, but OWSLib now targets 3.10 and later. --- owslib/util.py | 19 ++----------------- tests/doctests/sml_ndbc_station.txt | 4 ++-- tests/test_util.py | 4 ++-- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/owslib/util.py b/owslib/util.py index 439814f91..586877e58 100644 --- a/owslib/util.py +++ b/owslib/util.py @@ -11,7 +11,7 @@ import sys from collections import OrderedDict from dateutil import parser -from datetime import datetime, timedelta, tzinfo +from datetime import datetime, timezone from owslib.etree import etree, ParseError from owslib.namespaces import Namespaces from urllib.parse import urlsplit, urlencode, urlparse, parse_qs, urlunparse, parse_qsl @@ -36,21 +36,6 @@ class ServiceException(Exception): pass -# Allows marking timestamps as UTC without pulling in all of Pytz -class TimeZone_UTC(tzinfo): - def tzname(self, dt): - return "UTC" - - def utcoffset(self, dt): - return timedelta(0) - - def dst(self, dt): - return timedelta(0) - - -tz_utc = TimeZone_UTC() - - # http://stackoverflow.com/questions/6256183/combine-two-dictionaries-of-dictionaries-python def dict_union(d1, d2): return dict((x, (dict_union(d1.get(x, {}), d2[x]) if isinstance(d2.get(x), dict) else d2.get(x, d1.get(x)))) @@ -662,7 +647,7 @@ def extract_time(element): except Exception: att = testXMLValue(element.attrib.get('indeterminatePosition'), True) if att and att == 'now': - dt = datetime.utcnow().replace(tzinfo=tz_utc) + dt = datetime.utcnow().replace(tzinfo=timezone.utc) else: dt = None return dt diff --git a/tests/doctests/sml_ndbc_station.txt b/tests/doctests/sml_ndbc_station.txt index bda0e559a..4a25902c7 100644 --- a/tests/doctests/sml_ndbc_station.txt +++ b/tests/doctests/sml_ndbc_station.txt @@ -3,7 +3,7 @@ Imports >>> from tests.utils import resource_file >>> from owslib.swe.sensor.sml import SensorML >>> from dateutil import parser - >>> from owslib.util import TimeZone_UTC + >>> from datetime import timezone Initialize @@ -104,7 +104,7 @@ History 2 >>> event = his[0] - >>> parser.parse(event.date).replace(tzinfo=TimeZone_UTC()).isoformat() + >>> parser.parse(event.date).replace(tzinfo=timezone.utc).isoformat() '2010-01-12T00:00:00+00:00' >>> event.description 'Deployment start event' diff --git a/tests/test_util.py b/tests/test_util.py index f8d47ec9c..6f377c157 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,6 +1,6 @@ # -*- coding: UTF-8 -*- import codecs -from owslib.util import clean_ows_url, build_get_url, strip_bom, extract_time, tz_utc +from owslib.util import clean_ows_url, build_get_url, strip_bom, extract_time from owslib.etree import etree from datetime import datetime, timezone @@ -57,7 +57,7 @@ def test_build_get_url_overwrite(): def test_time_zone_utc(): now = datetime.utcnow() - as_utc = now.replace(tzinfo=tz_utc) + as_utc = now.replace(tzinfo=timezone.utc) assert(as_utc.isoformat()[-6:] == "+00:00") From 5e8f39ade909cf0ecbf95c74d41a636267fc0999 Mon Sep 17 00:00:00 2001 From: Brent Date: Sat, 12 Oct 2024 20:56:14 +1000 Subject: [PATCH 15/16] Cosmetic changes to get a clean bill of health from flake8 --- tests/test_util.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test_util.py b/tests/test_util.py index 6f377c157..06508699a 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -30,7 +30,8 @@ def test_clean_ows_url(): def test_build_get_url(): assert build_get_url("http://example.org/wps", {'service': 'WPS'}) == 'http://example.org/wps?service=WPS' assert build_get_url("http://example.org/wms", {'SERVICE': 'wms'}) == 'http://example.org/wms?SERVICE=wms' - assert build_get_url("http://example.org/wms?map=/path/to/foo.map&", {'SERVICE': 'wms'}) == 'http://example.org/wms?map=%2Fpath%2Fto%2Ffoo.map&SERVICE=wms' + assert build_get_url("http://example.org/wms?map=/path/to/foo.map&", {'SERVICE': 'wms'}) == \ + 'http://example.org/wms?map=%2Fpath%2Fto%2Ffoo.map&SERVICE=wms' assert build_get_url("http://example.org/wps?service=WPS", {'request': 'GetCapabilities'}) == \ 'http://example.org/wps?service=WPS&request=GetCapabilities' assert build_get_url("http://example.org/wps?service=WPS", {'request': 'GetCapabilities'}) == \ @@ -42,10 +43,10 @@ def test_build_get_url(): assert build_get_url("http://example.org/ows?SERVICE=WPS", {'service': 'WMS'}) == \ 'http://example.org/ows?SERVICE=WPS&service=WMS' # Test with trailing ampersand and doseq False (default) - assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1,2]}, doseq=False) == \ + assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1, 2]}, doseq=False) == \ 'http://example.org/ows?SERVICE=WFS&typename=test&keys=%5B1%2C+2%5D' # Test with trailing ampersand and doseq True - assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1,2]}, doseq=True) == \ + assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1, 2]}, doseq=True) == \ 'http://example.org/ows?SERVICE=WFS&typename=test&keys=1&keys=2' @@ -58,13 +59,13 @@ def test_build_get_url_overwrite(): def test_time_zone_utc(): now = datetime.utcnow() as_utc = now.replace(tzinfo=timezone.utc) - assert(as_utc.isoformat()[-6:] == "+00:00") + assert as_utc.isoformat()[-6:] == "+00:00" def test_extract_time(): definite_sample = "2006-07-27T21:10:00Z" indefinite_sample = "" start = extract_time(etree.fromstring(definite_sample)) - assert(start.isoformat()[-6:] == "+00:00") + assert start.isoformat()[-6:] == "+00:00" stop = extract_time(etree.fromstring(indefinite_sample)) - assert(stop.isoformat()[-6:] == "+00:00") + assert stop.isoformat()[-6:] == "+00:00" From d86f598a0ff9ecbb603e9fb081a62d810f0222f4 Mon Sep 17 00:00:00 2001 From: Brent Date: Sat, 12 Oct 2024 20:56:14 +1000 Subject: [PATCH 16/16] Cosmetic changes to get a clean bill of health from flake8 --- owslib/util.py | 2 +- tests/test_util.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/owslib/util.py b/owslib/util.py index 586877e58..779b444cb 100644 --- a/owslib/util.py +++ b/owslib/util.py @@ -11,7 +11,7 @@ import sys from collections import OrderedDict from dateutil import parser -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from owslib.etree import etree, ParseError from owslib.namespaces import Namespaces from urllib.parse import urlsplit, urlencode, urlparse, parse_qs, urlunparse, parse_qsl diff --git a/tests/test_util.py b/tests/test_util.py index 6f377c157..06508699a 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -30,7 +30,8 @@ def test_clean_ows_url(): def test_build_get_url(): assert build_get_url("http://example.org/wps", {'service': 'WPS'}) == 'http://example.org/wps?service=WPS' assert build_get_url("http://example.org/wms", {'SERVICE': 'wms'}) == 'http://example.org/wms?SERVICE=wms' - assert build_get_url("http://example.org/wms?map=/path/to/foo.map&", {'SERVICE': 'wms'}) == 'http://example.org/wms?map=%2Fpath%2Fto%2Ffoo.map&SERVICE=wms' + assert build_get_url("http://example.org/wms?map=/path/to/foo.map&", {'SERVICE': 'wms'}) == \ + 'http://example.org/wms?map=%2Fpath%2Fto%2Ffoo.map&SERVICE=wms' assert build_get_url("http://example.org/wps?service=WPS", {'request': 'GetCapabilities'}) == \ 'http://example.org/wps?service=WPS&request=GetCapabilities' assert build_get_url("http://example.org/wps?service=WPS", {'request': 'GetCapabilities'}) == \ @@ -42,10 +43,10 @@ def test_build_get_url(): assert build_get_url("http://example.org/ows?SERVICE=WPS", {'service': 'WMS'}) == \ 'http://example.org/ows?SERVICE=WPS&service=WMS' # Test with trailing ampersand and doseq False (default) - assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1,2]}, doseq=False) == \ + assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1, 2]}, doseq=False) == \ 'http://example.org/ows?SERVICE=WFS&typename=test&keys=%5B1%2C+2%5D' # Test with trailing ampersand and doseq True - assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1,2]}, doseq=True) == \ + assert build_get_url("http://example.org/ows?SERVICE=WFS&", {'typename': 'test', 'keys': [1, 2]}, doseq=True) == \ 'http://example.org/ows?SERVICE=WFS&typename=test&keys=1&keys=2' @@ -58,13 +59,13 @@ def test_build_get_url_overwrite(): def test_time_zone_utc(): now = datetime.utcnow() as_utc = now.replace(tzinfo=timezone.utc) - assert(as_utc.isoformat()[-6:] == "+00:00") + assert as_utc.isoformat()[-6:] == "+00:00" def test_extract_time(): definite_sample = "2006-07-27T21:10:00Z" indefinite_sample = "" start = extract_time(etree.fromstring(definite_sample)) - assert(start.isoformat()[-6:] == "+00:00") + assert start.isoformat()[-6:] == "+00:00" stop = extract_time(etree.fromstring(indefinite_sample)) - assert(stop.isoformat()[-6:] == "+00:00") + assert stop.isoformat()[-6:] == "+00:00"