Skip to content

Commit

Permalink
Remove instances of pytz in favor of the builtin zoneinfo lib and dat…
Browse files Browse the repository at this point in the history
…etime.timezone (#12673)

GitOrigin-RevId: b66ffede716af3d48b2e51b0b1937df981b0fc97
  • Loading branch information
mat-savage authored and Descartes Labs Build committed Sep 24, 2024
1 parent c33a9d0 commit ac86ba8
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 34 deletions.
9 changes: 4 additions & 5 deletions descarteslabs/core/catalog/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
import re

from collections.abc import Iterable, Mapping, MutableMapping, MutableSequence
from datetime import datetime
from datetime import datetime, timezone
from enum import Enum

from strenum import StrEnum
from pytz import utc

from ..common.shapely_support import (
geometry_like_to_shapely,
Expand All @@ -35,12 +34,12 @@ def parse_iso_datetime(date_str):
if len(date_str) > 27: # len(YYYY-MM-DDTHH:MM:SS.mmmmmmZ) == 27
date_str = date_str[0:26] + date_str[-1]
date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%fZ")
return date.replace(tzinfo=utc)
return date.replace(tzinfo=timezone.utc)
except ValueError:
# it's possible that a utc formatted time string from the server won't have
# a fractional seconds component
date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")
return date.replace(tzinfo=utc)
return date.replace(tzinfo=timezone.utc)


def serialize_datetime(value):
Expand Down Expand Up @@ -585,7 +584,7 @@ def deserialize(self, value, validate=True):
return value
elif isinstance(value, datetime):
if value.tzinfo is None:
return value.replace(tzinfo=utc)
return value.replace(tzinfo=timezone.utc)
else:
return value
else:
Expand Down
36 changes: 23 additions & 13 deletions descarteslabs/core/catalog/tests/test_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import unittest
import textwrap
from copy import deepcopy
from datetime import datetime
from datetime import datetime, timezone
from enum import Enum

from strenum import StrEnum
Expand All @@ -27,7 +27,6 @@
TypedAttribute,
Timestamp,
EnumAttribute,
utc,
MappingAttribute,
ListAttribute,
DocumentState,
Expand Down Expand Up @@ -76,16 +75,17 @@ def test_immutabletimestamp(self):
assert date.deserialize(None) is None

assert (
date.deserialize("2019-02-01T00:00:00.0000Z", validate=False).tzinfo == utc
date.deserialize("2019-02-01T00:00:00.0000Z", validate=False).tzinfo
== timezone.utc
)
assert date.deserialize(
"2019-02-01T00:00:00.0000Z", validate=False
) == datetime(2019, 2, 1, tzinfo=utc)
) == datetime(2019, 2, 1, tzinfo=timezone.utc)

date = Timestamp(readonly=True)
assert date.deserialize(
datetime(2013, 12, 31, 23, 59, 59), validate=False
) == datetime(2013, 12, 31, 23, 59, 59, tzinfo=utc)
) == datetime(2013, 12, 31, 23, 59, 59, tzinfo=timezone.utc)
value = date.deserialize(datetime(2013, 12, 31, 23, 59, 59), validate=False)
assert date.serialize(value) == "2013-12-31T23:59:59+00:00"

Expand All @@ -94,7 +94,7 @@ def test_mutable_timestamp(self):
assert mutable_date.deserialize(None) is None
assert (
mutable_date.deserialize("2019-02-01T00:00:00.0000Z", validate=False).tzinfo
== utc
== timezone.utc
)

class TimeObj(CatalogObject):
Expand Down Expand Up @@ -154,7 +154,9 @@ def test_mapping_attributes(self):
model_object = FakeCatalogObject(id="id", mapping=mapping)

assert model_object.mapping.nested.foo == "foo"
assert model_object.mapping.nested.dt == datetime(2019, 2, 1, tzinfo=utc)
assert model_object.mapping.nested.dt == datetime(
2019, 2, 1, tzinfo=timezone.utc
)
assert model_object.mapping is mapping
assert model_object.mapping.nested is nested

Expand Down Expand Up @@ -183,12 +185,14 @@ def test_mapping_change_tracking(self):

# assigning a new attribute value to the model does propagate state changes
new_mapping = Mapping(
nested=Nested(foo="bar", dt=datetime(2019, 3, 1, tzinfo=utc))
nested=Nested(foo="bar", dt=datetime(2019, 3, 1, tzinfo=timezone.utc))
)
model_object.mapping = new_mapping
assert model_object.is_modified
assert model_object.mapping.nested.foo == "bar"
assert model_object.mapping.nested.dt == datetime(2019, 3, 1, tzinfo=utc)
assert model_object.mapping.nested.dt == datetime(
2019, 3, 1, tzinfo=timezone.utc
)
assert model_object.mapping is new_mapping
assert len(mapping._model_objects) == 0

Expand Down Expand Up @@ -306,8 +310,12 @@ def test_list_attributes(self):

assert model_object.listmapping[0].nested.foo == "zap"
assert model_object.listmapping[1].nested.foo == "zip"
assert model_object.listmapping[0].nested.dt == datetime(2019, 2, 1, tzinfo=utc)
assert model_object.listmapping[1].nested.dt == datetime(2019, 2, 2, tzinfo=utc)
assert model_object.listmapping[0].nested.dt == datetime(
2019, 2, 1, tzinfo=timezone.utc
)
assert model_object.listmapping[1].nested.dt == datetime(
2019, 2, 2, tzinfo=timezone.utc
)
assert model_object.listmapping is not [mapping1, mapping2]
assert model_object.listmapping[0] is mapping1
assert model_object.listattribute[0] == 12
Expand Down Expand Up @@ -356,12 +364,14 @@ def test_listattribute_change_tracking(self):

# assigning a new attribute value to the model does propagate state changes
new_mapping = Mapping(
nested=Nested(foo="meep", dt=datetime(2019, 3, 1, tzinfo=utc))
nested=Nested(foo="meep", dt=datetime(2019, 3, 1, tzinfo=timezone.utc))
)
model_object.listmapping = [new_mapping]
assert model_object.is_modified
assert model_object.listmapping[0].nested.foo == "meep"
assert model_object.listmapping[0].nested.dt == datetime(2019, 3, 1, tzinfo=utc)
assert model_object.listmapping[0].nested.dt == datetime(
2019, 3, 1, tzinfo=timezone.utc
)

def test_listattribute_deserialization(self):
# Creation with valid enum should be fine
Expand Down
6 changes: 3 additions & 3 deletions descarteslabs/core/catalog/tests/test_catalog_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

import pytest
import responses
from datetime import datetime
from pytz import utc
from datetime import datetime, timezone


from descarteslabs.exceptions import (
NotFoundError,
Expand Down Expand Up @@ -537,7 +537,7 @@ def test_update(self):
assert c.is_modified

def test_update_immutable_attr(self):
timestamp = datetime.now(utc)
timestamp = datetime.now(timezone.utc)
c = CatalogObject(id="id", created=timestamp, _saved=True)
assert not c.is_modified
assert c.state == DocumentState.SAVED
Expand Down
3 changes: 1 addition & 2 deletions descarteslabs/core/catalog/tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import responses
import shapely.geometry
from unittest.mock import patch
from pytz import utc

from ...common.geo import AOI
from ...common.property_filtering import Properties
Expand Down Expand Up @@ -256,7 +255,7 @@ def test_nanosecond_timestamp(self):
assert (
datetime.datetime.strptime(
"2019-08-20T08:08:16.123456Z", "%Y-%m-%dT%H:%M:%S.%fZ"
).replace(tzinfo=utc)
).replace(tzinfo=datetime.timezone.utc)
== i.acquired
)

Expand Down
15 changes: 9 additions & 6 deletions descarteslabs/core/catalog/tests/test_image_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import responses
from unittest.mock import patch

from datetime import datetime
from datetime import datetime, timezone

from .base import ClientTestCase
from ..catalog_base import DocumentState
Expand All @@ -29,7 +29,6 @@
ImageUploadEventSeverity,
)
from ..image import Image
from ..attributes import utc


class TestImageUpload(ClientTestCase):
Expand Down Expand Up @@ -222,8 +221,8 @@ def test_save(self):
u.save()

assert u.id == "1"
assert u.created == datetime(2020, 1, 1, 0, 0, 0, tzinfo=utc)
assert u.modified == datetime(2020, 1, 1, 0, 0, 0, tzinfo=utc)
assert u.created == datetime(2020, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
assert u.modified == datetime(2020, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
assert u.product_id == "product_id"
assert u.image_id == "product_id:image_name"
assert u.image_upload_options.upload_type == ImageUploadType.FILE
Expand All @@ -239,7 +238,9 @@ def test_save(self):
assert u.status == ImageUploadStatus.PENDING
assert u.state == DocumentState.SAVED
assert len(u.events) == 1
assert u.events[0].event_datetime == datetime(2020, 1, 1, 0, 0, 0, tzinfo=utc)
assert u.events[0].event_datetime == datetime(
2020, 1, 1, 0, 0, 0, tzinfo=timezone.utc
)
assert u.events[0].event_type == ImageUploadEventType.QUEUE
assert u.events[0].severity == ImageUploadEventSeverity.INFO

Expand All @@ -248,7 +249,9 @@ def test_save(self):
assert u.status == ImageUploadStatus.CANCELED
assert u.state == DocumentState.SAVED
assert len(u.events) == 2
assert u.events[1].event_datetime == datetime(2020, 1, 1, 0, 0, 0, tzinfo=utc)
assert u.events[1].event_datetime == datetime(
2020, 1, 1, 0, 0, 0, tzinfo=timezone.utc
)
assert u.events[1].event_type == ImageUploadEventType.CANCEL
assert u.events[1].severity == ImageUploadEventSeverity.INFO

Expand Down
8 changes: 4 additions & 4 deletions descarteslabs/core/common/client/tests/test_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import unittest
from datetime import datetime, timezone

import pytz
from zoneinfo import ZoneInfo

from .. import Attribute, DatetimeAttribute, Document, DocumentState, ListAttribute

Expand Down Expand Up @@ -163,11 +163,11 @@ def test_deleted(self):
class TestDatetimeAttribute(unittest.TestCase):
def test_local_time(self):
class TzTest(Document):
date: datetime = DatetimeAttribute(timezone=pytz.timezone("MST"))
date: datetime = DatetimeAttribute(timezone=ZoneInfo("MST"))

now = datetime.utcnow()
doc = TzTest(date=now.isoformat())
assert doc.date.tzinfo == pytz.timezone("MST")
assert doc.date.tzinfo == ZoneInfo("MST")
assert doc.date.astimezone(tz=timezone.utc) == now.replace(tzinfo=timezone.utc)

assert doc.to_dict()["date"] == now.replace(tzinfo=timezone.utc).isoformat()
Expand All @@ -181,7 +181,7 @@ class TrailingTest(Document):
doc.date == now.replace(tzinfo=timezone.utc)

def test_assign_instance(self):
tz = pytz.timezone("MST")
tz = ZoneInfo("MST")

class InstanceTest(Document):
date: datetime = DatetimeAttribute(timezone=tz)
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ def do_setup():
"Pillow>=9.2.0",
"pyarrow>=14.0.1",
"pydantic>=2.4.0",
"pytz>=2021.1,<2024.2",
"requests>=2.32.3,<3",
# It is not obvious but dynaconf requires pkg_resources from setuptools.
"setuptools>=70.0.0",
Expand Down

0 comments on commit ac86ba8

Please sign in to comment.