From 1848bea97a9af6e2e5a69dad46af606c73cffb0c Mon Sep 17 00:00:00 2001 From: Brent Spillner Date: Sun, 7 Apr 2024 10:47:38 +1000 Subject: [PATCH 1/9] 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 a49b4859203d290b2265bc208ef32622b807653c Mon Sep 17 00:00:00 2001 From: Brent Date: Tue, 8 Oct 2024 17:39:33 +1000 Subject: [PATCH 2/9] 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 3/9] 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 4/9] 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 b80120b6254a6d529b110453a1795473a4e6a33b Mon Sep 17 00:00:00 2001 From: Brent Date: Fri, 11 Oct 2024 06:25:33 +1000 Subject: [PATCH 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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"