diff --git a/pyproject.toml b/pyproject.toml index c151100a..8543018e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,6 @@ dependencies = [ "requests>=2.7.0", "requests-toolbelt>=0.7.1", "requests-file>=1.5.1", - "pytz", ] [project.urls] diff --git a/src/zeep/cache.py b/src/zeep/cache.py index 3cc734a7..796288e2 100644 --- a/src/zeep/cache.py +++ b/src/zeep/cache.py @@ -8,7 +8,6 @@ from typing import Dict, Tuple, Union import platformdirs -import pytz # The sqlite3 is not available on Google App Engine so we handle the # ImportError here and set the sqlite3 var to None. @@ -169,8 +168,8 @@ def _is_expired(value, timeout): if timeout is None: return False - now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=pytz.utc) - max_age = value.replace(tzinfo=pytz.utc) + now = datetime.datetime.now(datetime.timezone.utc) + max_age = value.replace(tzinfo=datetime.timezone.utc) max_age += datetime.timedelta(seconds=timeout) return now > max_age diff --git a/src/zeep/wsse/utils.py b/src/zeep/wsse/utils.py index affefcd9..04e50e69 100644 --- a/src/zeep/wsse/utils.py +++ b/src/zeep/wsse/utils.py @@ -1,7 +1,6 @@ import datetime from uuid import uuid4 -import pytz from lxml import etree from lxml.builder import ElementMaker @@ -29,7 +28,7 @@ def get_security_header(doc): def get_timestamp(timestamp=None, zulu_timestamp=None): timestamp = timestamp or datetime.datetime.now(datetime.timezone.utc) - timestamp = timestamp.replace(tzinfo=pytz.utc, microsecond=0) + timestamp = timestamp.replace(tzinfo=datetime.timezone.utc, microsecond=0) if zulu_timestamp: return timestamp.isoformat().replace("+00:00", "Z") else: diff --git a/src/zeep/xsd/types/builtins.py b/src/zeep/xsd/types/builtins.py index d98e2526..8c5c6ba1 100644 --- a/src/zeep/xsd/types/builtins.py +++ b/src/zeep/xsd/types/builtins.py @@ -5,7 +5,6 @@ from decimal import Decimal as _Decimal import isodate -import pytz from zeep.xsd.const import xsd_ns from zeep.xsd.types.any import AnyType @@ -151,22 +150,7 @@ def xmlvalue(self, value): if isinstance(value, str): return value - # Bit of a hack, since datetime is a subclass of date we can't just - # test it with an isinstance(). And actually, we should not really - # care about the type, as long as it has the required attributes - if not all(hasattr(value, attr) for attr in ("hour", "minute", "second")): - value = datetime.datetime.combine( - value, - datetime.time( - getattr(value, "hour", 0), - getattr(value, "minute", 0), - getattr(value, "second", 0), - ), - ) - - if getattr(value, "microsecond", 0): - return isodate.isostrf.strftime(value, "%Y-%m-%dT%H:%M:%S.%f%Z") - return isodate.isostrf.strftime(value, "%Y-%m-%dT%H:%M:%S%Z") + return value.isoformat().replace("+00:00", "Z") @treat_whitespace("collapse") def pythonvalue(self, value): @@ -189,9 +173,7 @@ def xmlvalue(self, value): if isinstance(value, str): return value - if value.microsecond: - return isodate.isostrf.strftime(value, "%H:%M:%S.%f%Z") - return isodate.isostrf.strftime(value, "%H:%M:%S%Z") + return value.isoformat().replace("+00:00", "Z") @treat_whitespace("collapse") def pythonvalue(self, value): @@ -207,7 +189,7 @@ class Date(BuiltinType): def xmlvalue(self, value): if isinstance(value, str): return value - return isodate.isostrf.strftime(value, "%Y-%m-%d") + return value.strftime("%Y-%m-%d") @treat_whitespace("collapse") def pythonvalue(self, value): @@ -548,12 +530,12 @@ class PositiveInteger(NonNegativeInteger): ## # Other def _parse_timezone(val): - """Return a pytz.tzinfo object""" + """Return a timezone object""" if not val: return if val == "Z" or val == "+00:00": - return pytz.utc + return datetime.timezone.utc negative = val.startswith("-") minutes = int(val[-2:]) @@ -561,22 +543,17 @@ def _parse_timezone(val): if negative: minutes = 0 - minutes - return pytz.FixedOffset(minutes) + return datetime.timezone(offset=datetime.timedelta(minutes=minutes)) -def _unparse_timezone(tzinfo): +def _unparse_timezone(tzinfo: datetime.timezone): if not tzinfo: return "" - if tzinfo == pytz.utc: + if tzinfo == datetime.timezone.utc: return "Z" - hours = math.floor(tzinfo._minutes / 60) - minutes = tzinfo._minutes % 60 - - if hours > 0: - return "+%02d:%02d" % (hours, minutes) - return "-%02d:%02d" % (abs(hours), minutes) + return datetime.datetime.now(tz=tzinfo).isoformat()[-6:] _types = [ diff --git a/tests/test_xsd_builtins.py b/tests/test_xsd_builtins.py index 4063771e..b4215e75 100644 --- a/tests/test_xsd_builtins.py +++ b/tests/test_xsd_builtins.py @@ -3,7 +3,6 @@ import isodate import pytest -import pytz from zeep.xsd.types import builtins @@ -161,14 +160,16 @@ def test_xmlvalue(self): value = datetime.datetime(2016, 3, 4, 21, 14, 42) assert instance.xmlvalue(value) == "2016-03-04T21:14:42" - value = datetime.datetime(2016, 3, 4, 21, 14, 42, tzinfo=pytz.utc) + value = datetime.datetime(2016, 3, 4, 21, 14, 42, tzinfo=datetime.timezone.utc) assert instance.xmlvalue(value) == "2016-03-04T21:14:42Z" - value = datetime.datetime(2016, 3, 4, 21, 14, 42, 123456, tzinfo=pytz.utc) + value = datetime.datetime( + 2016, 3, 4, 21, 14, 42, 123456, tzinfo=datetime.timezone.utc + ) assert instance.xmlvalue(value) == "2016-03-04T21:14:42.123456Z" - value = datetime.datetime(2016, 3, 4, 21, 14, 42, tzinfo=pytz.utc) - value = value.astimezone(pytz.timezone("Europe/Amsterdam")) + value = datetime.datetime(2016, 3, 4, 21, 14, 42, tzinfo=datetime.timezone.utc) + value = value.astimezone(datetime.timezone(datetime.timedelta(hours=1))) assert instance.xmlvalue(value) == "2016-03-04T22:14:42+01:00" assert ( @@ -262,7 +263,7 @@ class TestgYearMonth: def test_xmlvalue(self): instance = builtins.gYearMonth() assert instance.xmlvalue((2012, 10, None)) == "2012-10" - assert instance.xmlvalue((2012, 10, pytz.utc)) == "2012-10Z" + assert instance.xmlvalue((2012, 10, datetime.timezone.utc)) == "2012-10Z" def test_pythonvalue(self): instance = builtins.gYearMonth() @@ -270,10 +271,14 @@ def test_pythonvalue(self): assert instance.pythonvalue("2001-10+02:00") == ( 2001, 10, - pytz.FixedOffset(120), + datetime.timezone(datetime.timedelta(minutes=120)), + ) + assert instance.pythonvalue("2001-10Z") == (2001, 10, datetime.timezone.utc) + assert instance.pythonvalue("2001-10+00:00") == ( + 2001, + 10, + datetime.timezone.utc, ) - assert instance.pythonvalue("2001-10Z") == (2001, 10, pytz.utc) - assert instance.pythonvalue("2001-10+00:00") == (2001, 10, pytz.utc) assert instance.pythonvalue("-2001-10") == (-2001, 10, None) assert instance.pythonvalue("-20001-10") == (-20001, 10, None) @@ -285,19 +290,22 @@ class TestgYear: def test_xmlvalue(self): instance = builtins.gYear() assert instance.xmlvalue((2001, None)) == "2001" - assert instance.xmlvalue((2001, pytz.utc)) == "2001Z" + assert instance.xmlvalue((2001, datetime.timezone.utc)) == "2001Z" def test_pythonvalue(self): instance = builtins.gYear() assert instance.pythonvalue("2001") == (2001, None) - assert instance.pythonvalue("2001+02:00") == (2001, pytz.FixedOffset(120)) - assert instance.pythonvalue("2001Z") == (2001, pytz.utc) - assert instance.pythonvalue("2001+00:00") == (2001, pytz.utc) + assert instance.pythonvalue("2001+02:00") == ( + 2001, + datetime.timezone(datetime.timedelta(minutes=120)), + ) + assert instance.pythonvalue("2001Z") == (2001, datetime.timezone.utc) + assert instance.pythonvalue("2001+00:00") == (2001, datetime.timezone.utc) assert instance.pythonvalue("-2001") == (-2001, None) assert instance.pythonvalue("-20000") == (-20000, None) assert instance.pythonvalue(" \t2001+02:00\r\n ") == ( 2001, - pytz.FixedOffset(120), + datetime.timezone(datetime.timedelta(minutes=120)), ) with pytest.raises(builtins.ParseError): @@ -312,9 +320,17 @@ def test_xmlvalue(self): def test_pythonvalue(self): instance = builtins.gMonthDay() assert instance.pythonvalue("--05-01") == (5, 1, None) - assert instance.pythonvalue("--11-01Z") == (11, 1, pytz.utc) - assert instance.pythonvalue("--11-01+02:00") == (11, 1, pytz.FixedOffset(120)) - assert instance.pythonvalue("--11-01-04:00") == (11, 1, pytz.FixedOffset(-240)) + assert instance.pythonvalue("--11-01Z") == (11, 1, datetime.timezone.utc) + assert instance.pythonvalue("--11-01+02:00") == ( + 11, + 1, + datetime.timezone(datetime.timedelta(minutes=120)), + ) + assert instance.pythonvalue("--11-01-04:00") == ( + 11, + 1, + datetime.timezone(datetime.timedelta(minutes=-240)), + ) assert instance.pythonvalue("--11-15") == (11, 15, None) assert instance.pythonvalue("--02-29") == (2, 29, None) assert instance.pythonvalue("\t\r\n --05-01 ") == (5, 1, None) @@ -331,12 +347,18 @@ def test_xmlvalue(self): def test_pythonvalue(self): instance = builtins.gMonth() assert instance.pythonvalue("--05") == (5, None) - assert instance.pythonvalue("--11Z") == (11, pytz.utc) - assert instance.pythonvalue("--11+02:00") == (11, pytz.FixedOffset(120)) - assert instance.pythonvalue("--11-04:00") == (11, pytz.FixedOffset(-240)) + assert instance.pythonvalue("--11Z") == (11, datetime.timezone.utc) + assert instance.pythonvalue("--11+02:00") == ( + 11, + datetime.timezone(datetime.timedelta(minutes=120)), + ) + assert instance.pythonvalue("--11-04:00") == ( + 11, + datetime.timezone(datetime.timedelta(minutes=-240)), + ) assert instance.pythonvalue("--11") == (11, None) assert instance.pythonvalue("--02") == (2, None) - assert instance.pythonvalue("\n\t --11Z \r") == (11, pytz.utc) + assert instance.pythonvalue("\n\t --11Z \r") == (11, datetime.timezone.utc) with pytest.raises(builtins.ParseError): assert instance.pythonvalue("99") @@ -349,18 +371,24 @@ def test_xmlvalue(self): value = (1, None) assert instance.xmlvalue(value) == "---01" - value = (1, pytz.FixedOffset(120)) + value = (1, datetime.timezone(datetime.timedelta(minutes=120))) assert instance.xmlvalue(value) == "---01+02:00" - value = (1, pytz.FixedOffset(-240)) + value = (1, datetime.timezone(datetime.timedelta(minutes=-240))) assert instance.xmlvalue(value) == "---01-04:00" def test_pythonvalue(self): instance = builtins.gDay() assert instance.pythonvalue("---01") == (1, None) - assert instance.pythonvalue("---01Z") == (1, pytz.utc) - assert instance.pythonvalue("---01+02:00") == (1, pytz.FixedOffset(120)) - assert instance.pythonvalue("---01-04:00") == (1, pytz.FixedOffset(-240)) + assert instance.pythonvalue("---01Z") == (1, datetime.timezone.utc) + assert instance.pythonvalue("---01+02:00") == ( + 1, + datetime.timezone(datetime.timedelta(minutes=120)), + ) + assert instance.pythonvalue("---01-04:00") == ( + 1, + datetime.timezone(datetime.timedelta(minutes=-240)), + ) assert instance.pythonvalue("---15") == (15, None) assert instance.pythonvalue("---31") == (31, None) assert instance.pythonvalue("\r\n \t---31 ") == (31, None)