From 4699706adfb9b951d7669ded4b8c3d8949ed2629 Mon Sep 17 00:00:00 2001 From: Stijn de Gooijer Date: Wed, 28 Feb 2024 12:15:30 +0100 Subject: [PATCH] ZoneInfo --- py-polars/polars/utils/convert.py | 35 ++-- .../unit/constructors/test_constructors.py | 14 +- py-polars/tests/unit/dataframe/test_df.py | 9 +- .../tests/unit/datatypes/test_temporal.py | 150 +++++++++--------- py-polars/tests/unit/expr/test_exprs.py | 15 +- .../functions/as_datatype/test_as_datatype.py | 2 +- .../functions/range/test_datetime_range.py | 16 +- .../tests/unit/namespaces/test_datetime.py | 21 +-- .../tests/unit/namespaces/test_strptime.py | 6 +- .../unit/operations/test_group_by_dynamic.py | 10 +- py-polars/tests/unit/series/test_series.py | 2 +- 11 files changed, 132 insertions(+), 148 deletions(-) diff --git a/py-polars/polars/utils/convert.py b/py-polars/polars/utils/convert.py index b11bb548346ab..a853a3f3e9d3f 100644 --- a/py-polars/polars/utils/convert.py +++ b/py-polars/polars/utils/convert.py @@ -14,22 +14,13 @@ from polars.type_aliases import TimeUnit - # the below shenanigans with ZoneInfo are all to handle a - # typing issue in py < 3.9 while preserving lazy-loading if sys.version_info >= (3, 9): from zoneinfo import ZoneInfo elif _ZONEINFO_AVAILABLE: + # Import from submodule due to typing issue with backports.zoneinfo package: + # https://github.com/pganssle/zoneinfo/issues/125 from backports.zoneinfo._zoneinfo import ZoneInfo - def get_zoneinfo(key: str) -> ZoneInfo: # noqa: D103 - pass - -else: - - @lru_cache(None) - def get_zoneinfo(key: str) -> ZoneInfo: # noqa: D103 - return zoneinfo.ZoneInfo(key) - SECONDS_PER_DAY = 86_400 SECONDS_PER_HOUR = 3_600 @@ -187,14 +178,26 @@ def to_py_datetime( def _localize_datetime(dt: datetime, time_zone: str) -> datetime: # zone info installation should already be checked - _tzinfo: ZoneInfo | tzinfo + tz: ZoneInfo | tzinfo try: - _tzinfo = get_zoneinfo(time_zone) + tz = string_to_zoneinfo(time_zone) except zoneinfo.ZoneInfoNotFoundError: # try fixed offset, which is not supported by ZoneInfo - _tzinfo = _parse_fixed_tz_offset(time_zone) + tz = _parse_fixed_tz_offset(time_zone) + + return dt.astimezone(tz) + + +@lru_cache(None) +def string_to_zoneinfo(key: str) -> ZoneInfo: + """ + Convert a time zone string to a Python ZoneInfo object. - return dt.astimezone(_tzinfo) + This is a simple wrapper for the zoneinfo.ZoneInfo constructor. + The wrapper is useful because zoneinfo is not available on Python 3.8 + and the backports module may not be installed. + """ + return zoneinfo.ZoneInfo(key) # cache here as we have a single tz per column @@ -209,7 +212,7 @@ def _parse_fixed_tz_offset(offset: str) -> tzinfo: # minutes, then we can construct: # tzinfo=timezone(timedelta(hours=..., minutes=...)) except ValueError: - msg = f"offset: {offset!r} not understood" + msg = f"unexpected time zone offset: {offset!r}" raise ValueError(msg) from None return dt_offset.tzinfo # type: ignore[return-value] diff --git a/py-polars/tests/unit/constructors/test_constructors.py b/py-polars/tests/unit/constructors/test_constructors.py index 5e836cb0775bb..ca57a8b6fa130 100644 --- a/py-polars/tests/unit/constructors/test_constructors.py +++ b/py-polars/tests/unit/constructors/test_constructors.py @@ -1,6 +1,5 @@ from __future__ import annotations -import sys from collections import OrderedDict, namedtuple from datetime import date, datetime, time, timedelta, timezone from decimal import Decimal @@ -15,7 +14,7 @@ import polars as pl from polars.datatypes import PolarsDataType, numpy_char_code_to_dtype -from polars.dependencies import _ZONEINFO_AVAILABLE, dataclasses, pydantic +from polars.dependencies import dataclasses, pydantic from polars.exceptions import TimeZoneAwareConstructorWarning from polars.testing import assert_frame_equal, assert_series_equal from polars.utils._construction import type_hints @@ -23,14 +22,11 @@ if TYPE_CHECKING: from collections.abc import Callable - from polars.datatypes import PolarsDataType - -if sys.version_info >= (3, 9): from zoneinfo import ZoneInfo -elif _ZONEINFO_AVAILABLE: - # Import from submodule due to typing issue with backports.zoneinfo package: - # https://github.com/pganssle/zoneinfo/issues/125 - from backports.zoneinfo._zoneinfo import ZoneInfo + + from polars.datatypes import PolarsDataType +else: + from polars.utils.convert import string_to_zoneinfo as ZoneInfo # ----------------------------------------------------------------------------------- diff --git a/py-polars/tests/unit/dataframe/test_df.py b/py-polars/tests/unit/dataframe/test_df.py index 339c2a6ab0382..0de867b519b85 100644 --- a/py-polars/tests/unit/dataframe/test_df.py +++ b/py-polars/tests/unit/dataframe/test_df.py @@ -27,14 +27,11 @@ from polars.utils._construction import iterable_to_pydf if TYPE_CHECKING: - from polars.type_aliases import JoinStrategy, UniqueKeepStrategy - -if sys.version_info >= (3, 9): from zoneinfo import ZoneInfo + + from polars.type_aliases import JoinStrategy, UniqueKeepStrategy else: - # Import from submodule due to typing issue with backports.zoneinfo package: - # https://github.com/pganssle/zoneinfo/issues/125 - from backports.zoneinfo._zoneinfo import ZoneInfo + from polars.utils.convert import string_to_zoneinfo as ZoneInfo def test_version() -> None: diff --git a/py-polars/tests/unit/datatypes/test_temporal.py b/py-polars/tests/unit/datatypes/test_temporal.py index 3cddc1d7aaee0..e3af046ad233d 100644 --- a/py-polars/tests/unit/datatypes/test_temporal.py +++ b/py-polars/tests/unit/datatypes/test_temporal.py @@ -28,7 +28,7 @@ from polars.type_aliases import Ambiguous, PolarsTemporalType, TimeUnit else: - from polars.utils.convert import get_zoneinfo as ZoneInfo + from polars.utils.convert import string_to_zoneinfo as ZoneInfo def test_fill_null() -> None: @@ -1406,7 +1406,7 @@ def test_replace_time_zone() -> None: @pytest.mark.parametrize( ("to_tz", "tzinfo"), [ - ("America/Barbados", ZoneInfo(key="America/Barbados")), + ("America/Barbados", ZoneInfo("America/Barbados")), (None, None), ], ) @@ -1430,7 +1430,7 @@ def test_strptime_with_tz() -> None: .str.strptime(pl.Datetime("us", "Africa/Monrovia")) .item() ) - assert result == datetime(2020, 1, 1, 3, tzinfo=ZoneInfo(key="Africa/Monrovia")) + assert result == datetime(2020, 1, 1, 3, tzinfo=ZoneInfo("Africa/Monrovia")) @pytest.mark.parametrize( @@ -1496,7 +1496,7 @@ def test_convert_time_zone_lazy_schema() -> None: def test_convert_time_zone_on_tz_naive() -> None: ts = pl.Series(["2020-01-01"]).str.strptime(pl.Datetime) result = ts.dt.convert_time_zone("Asia/Kathmandu").item() - expected = datetime(2020, 1, 1, 5, 45, tzinfo=ZoneInfo(key="Asia/Kathmandu")) + expected = datetime(2020, 1, 1, 5, 45, tzinfo=ZoneInfo("Asia/Kathmandu")) assert result == expected result = ( ts.dt.replace_time_zone("UTC").dt.convert_time_zone("Asia/Kathmandu").item() @@ -1582,8 +1582,8 @@ def test_replace_time_zone_from_naive() -> None: pl.col("date").cast(pl.Datetime).dt.replace_time_zone("America/New_York") ).to_dict(as_series=False) == { "date": [ - datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 1, 2, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), + datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 1, 2, 0, 0, tzinfo=ZoneInfo("America/New_York")), ] } @@ -1854,22 +1854,22 @@ def test_tz_aware_truncate() -> None: result = df.with_columns(pl.col("dt").dt.truncate("1d").alias("trunced")) expected = { "dt": [ - datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 1, 12, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 2, 12, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 3, 12, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 4, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), + datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 1, 12, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 2, 12, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 3, 12, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 4, 0, 0, tzinfo=ZoneInfo("America/New_York")), ], "trunced": [ - datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 4, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), + datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 4, 0, 0, tzinfo=ZoneInfo("America/New_York")), ], } assert result.to_dict(as_series=False) == expected @@ -1900,34 +1900,34 @@ def test_tz_aware_truncate() -> None: datetime(2022, 1, 1, 6, 0), ], "UTC": [ - datetime(2021, 12, 31, 23, 0, tzinfo=ZoneInfo(key="UTC")), - datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo(key="UTC")), - datetime(2022, 1, 1, 1, 0, tzinfo=ZoneInfo(key="UTC")), - datetime(2022, 1, 1, 2, 0, tzinfo=ZoneInfo(key="UTC")), - datetime(2022, 1, 1, 3, 0, tzinfo=ZoneInfo(key="UTC")), - datetime(2022, 1, 1, 4, 0, tzinfo=ZoneInfo(key="UTC")), - datetime(2022, 1, 1, 5, 0, tzinfo=ZoneInfo(key="UTC")), - datetime(2022, 1, 1, 6, 0, tzinfo=ZoneInfo(key="UTC")), + datetime(2021, 12, 31, 23, 0, tzinfo=ZoneInfo("UTC")), + datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo("UTC")), + datetime(2022, 1, 1, 1, 0, tzinfo=ZoneInfo("UTC")), + datetime(2022, 1, 1, 2, 0, tzinfo=ZoneInfo("UTC")), + datetime(2022, 1, 1, 3, 0, tzinfo=ZoneInfo("UTC")), + datetime(2022, 1, 1, 4, 0, tzinfo=ZoneInfo("UTC")), + datetime(2022, 1, 1, 5, 0, tzinfo=ZoneInfo("UTC")), + datetime(2022, 1, 1, 6, 0, tzinfo=ZoneInfo("UTC")), ], "CST": [ - datetime(2021, 12, 31, 17, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 18, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 19, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 20, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 21, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 22, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 23, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo(key="US/Central")), + datetime(2021, 12, 31, 17, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 18, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 19, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 20, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 21, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 22, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 23, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo("US/Central")), ], "CST truncated": [ - datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo(key="US/Central")), - datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo(key="US/Central")), + datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2021, 12, 31, 0, 0, tzinfo=ZoneInfo("US/Central")), + datetime(2022, 1, 1, 0, 0, tzinfo=ZoneInfo("US/Central")), ], } @@ -1956,10 +1956,10 @@ def test_tz_aware_to_string() -> None: result = df.with_columns(pl.col("dt").dt.to_string("%c").alias("fmt")) expected = { "dt": [ - datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(2022, 11, 4, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), + datetime(2022, 11, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 2, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 3, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(2022, 11, 4, 0, 0, tzinfo=ZoneInfo("America/New_York")), ], "fmt": [ "Tue Nov 1 00:00:00 2022", @@ -2017,12 +2017,12 @@ def test_tz_aware_filter_lit() -> None: datetime(1970, 1, 1, 5, 0), ], "nyc": [ - datetime(1970, 1, 1, 0, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(1970, 1, 1, 1, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(1970, 1, 1, 2, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(1970, 1, 1, 3, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(1970, 1, 1, 4, 0, tzinfo=ZoneInfo(key="America/New_York")), - datetime(1970, 1, 1, 5, 0, tzinfo=ZoneInfo(key="America/New_York")), + datetime(1970, 1, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(1970, 1, 1, 1, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(1970, 1, 1, 2, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(1970, 1, 1, 3, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(1970, 1, 1, 4, 0, tzinfo=ZoneInfo("America/New_York")), + datetime(1970, 1, 1, 5, 0, tzinfo=ZoneInfo("America/New_York")), ], } @@ -2097,26 +2097,26 @@ def test_truncate_expr() -> None: ambiguous_expr = df.select(pl.col("date").dt.truncate(every=pl.lit("30m"))) assert ambiguous_expr.to_dict(as_series=False) == { "date": [ - datetime(2020, 10, 25, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 0, 30, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 2, 0, tzinfo=ZoneInfo(key="Europe/London")), + datetime(2020, 10, 25, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 0, 30, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 2, 0, tzinfo=ZoneInfo("Europe/London")), ] } all_expr = df.select(pl.col("date").dt.truncate(every=pl.col("every"))) assert all_expr.to_dict(as_series=False) == { "date": [ - datetime(2020, 10, 25, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 0, 45, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 45, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 45, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 2, 0, tzinfo=ZoneInfo(key="Europe/London")), + datetime(2020, 10, 25, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 0, 45, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 45, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 0, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 45, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 2, 0, tzinfo=ZoneInfo("Europe/London")), ] } @@ -2352,13 +2352,13 @@ def test_round_ambiguous() -> None: df = df.select(pl.col("date").dt.round("30m", ambiguous=pl.col("ambiguous"))) assert df.to_dict(as_series=False) == { "date": [ - datetime(2020, 10, 25, 0, 30, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 2, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 25, 2, 30, tzinfo=ZoneInfo(key="Europe/London")), + datetime(2020, 10, 25, 0, 30, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 1, 30, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 2, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 25, 2, 30, tzinfo=ZoneInfo("Europe/London")), ] } diff --git a/py-polars/tests/unit/expr/test_exprs.py b/py-polars/tests/unit/expr/test_exprs.py index 6e0be82f15572..fc5453035128e 100644 --- a/py-polars/tests/unit/expr/test_exprs.py +++ b/py-polars/tests/unit/expr/test_exprs.py @@ -1,16 +1,8 @@ from __future__ import annotations -import sys from datetime import date, datetime, timedelta, timezone from itertools import permutations -from typing import Any, cast - -if sys.version_info >= (3, 9): - from zoneinfo import ZoneInfo -else: - # Import from submodule due to typing issue with backports.zoneinfo package: - # https://github.com/pganssle/zoneinfo/issues/125 - from backports.zoneinfo._zoneinfo import ZoneInfo +from typing import TYPE_CHECKING, Any, cast import numpy as np import pytest @@ -26,6 +18,11 @@ ) from polars.testing import assert_frame_equal, assert_series_equal +if TYPE_CHECKING: + from zoneinfo import ZoneInfo +else: + from polars.utils.convert import string_to_zoneinfo as ZoneInfo + def test_arg_true() -> None: df = pl.DataFrame({"a": [1, 1, 2, 1]}) diff --git a/py-polars/tests/unit/functions/as_datatype/test_as_datatype.py b/py-polars/tests/unit/functions/as_datatype/test_as_datatype.py index c1e266933f841..d0cafb850a610 100644 --- a/py-polars/tests/unit/functions/as_datatype/test_as_datatype.py +++ b/py-polars/tests/unit/functions/as_datatype/test_as_datatype.py @@ -13,7 +13,7 @@ from polars.type_aliases import TimeUnit else: - from polars.utils.convert import get_zoneinfo as ZoneInfo + from polars.utils.convert import string_to_zoneinfo as ZoneInfo def test_date_datetime() -> None: diff --git a/py-polars/tests/unit/functions/range/test_datetime_range.py b/py-polars/tests/unit/functions/range/test_datetime_range.py index 70d1cdda0c047..02150992d9106 100644 --- a/py-polars/tests/unit/functions/range/test_datetime_range.py +++ b/py-polars/tests/unit/functions/range/test_datetime_range.py @@ -16,7 +16,7 @@ from polars.datatypes import PolarsDataType from polars.type_aliases import ClosedInterval, TimeUnit else: - from polars.utils.convert import get_zoneinfo as ZoneInfo + from polars.utils.convert import string_to_zoneinfo as ZoneInfo def test_datetime_range() -> None: @@ -166,13 +166,13 @@ def test_timezone_aware_datetime_range() -> None: assert pl.datetime_range( low, high, interval=timedelta(days=5), eager=True ).to_list() == [ - datetime(2022, 10, 17, 10, 0, tzinfo=ZoneInfo(key="Asia/Shanghai")), - datetime(2022, 10, 22, 10, 0, tzinfo=ZoneInfo(key="Asia/Shanghai")), - datetime(2022, 10, 27, 10, 0, tzinfo=ZoneInfo(key="Asia/Shanghai")), - datetime(2022, 11, 1, 10, 0, tzinfo=ZoneInfo(key="Asia/Shanghai")), - datetime(2022, 11, 6, 10, 0, tzinfo=ZoneInfo(key="Asia/Shanghai")), - datetime(2022, 11, 11, 10, 0, tzinfo=ZoneInfo(key="Asia/Shanghai")), - datetime(2022, 11, 16, 10, 0, tzinfo=ZoneInfo(key="Asia/Shanghai")), + datetime(2022, 10, 17, 10, 0, tzinfo=ZoneInfo("Asia/Shanghai")), + datetime(2022, 10, 22, 10, 0, tzinfo=ZoneInfo("Asia/Shanghai")), + datetime(2022, 10, 27, 10, 0, tzinfo=ZoneInfo("Asia/Shanghai")), + datetime(2022, 11, 1, 10, 0, tzinfo=ZoneInfo("Asia/Shanghai")), + datetime(2022, 11, 6, 10, 0, tzinfo=ZoneInfo("Asia/Shanghai")), + datetime(2022, 11, 11, 10, 0, tzinfo=ZoneInfo("Asia/Shanghai")), + datetime(2022, 11, 16, 10, 0, tzinfo=ZoneInfo("Asia/Shanghai")), ] with pytest.raises( diff --git a/py-polars/tests/unit/namespaces/test_datetime.py b/py-polars/tests/unit/namespaces/test_datetime.py index fd733b228b696..1f6fc91385815 100644 --- a/py-polars/tests/unit/namespaces/test_datetime.py +++ b/py-polars/tests/unit/namespaces/test_datetime.py @@ -1,6 +1,5 @@ from __future__ import annotations -import sys from datetime import date, datetime, time, timedelta from typing import TYPE_CHECKING @@ -8,19 +7,15 @@ import polars as pl from polars.datatypes import DTYPE_TEMPORAL_UNITS -from polars.dependencies import _ZONEINFO_AVAILABLE from polars.exceptions import ComputeError, InvalidOperationError from polars.testing import assert_frame_equal, assert_series_equal -if sys.version_info >= (3, 9): +if TYPE_CHECKING: from zoneinfo import ZoneInfo -elif _ZONEINFO_AVAILABLE: - # Import from submodule due to typing issue with backports.zoneinfo package: - # https://github.com/pganssle/zoneinfo/issues/125 - from backports.zoneinfo._zoneinfo import ZoneInfo -if TYPE_CHECKING: from polars.type_aliases import TemporalLiteral, TimeUnit +else: + from polars.utils.convert import string_to_zoneinfo as ZoneInfo @pytest.fixture() @@ -782,9 +777,9 @@ def test_offset_by_broadcasting() -> None: None, ], "d3": [ - datetime(2020, 10, 26, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 11, 4, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2020, 10, 28, tzinfo=ZoneInfo(key="Europe/London")), + datetime(2020, 10, 26, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 11, 4, tzinfo=ZoneInfo("Europe/London")), + datetime(2020, 10, 28, tzinfo=ZoneInfo("Europe/London")), None, ], "d4": [ @@ -811,8 +806,8 @@ def test_offset_by_broadcasting() -> None: "d1": [datetime(2020, 11, 28), datetime(2021, 2, 5), None], "d2": [datetime(2021, 11, 25), datetime(2022, 2, 2), None], "d3": [ - datetime(2020, 10, 28, tzinfo=ZoneInfo(key="Europe/London")), - datetime(2021, 1, 5, tzinfo=ZoneInfo(key="Europe/London")), + datetime(2020, 10, 28, tzinfo=ZoneInfo("Europe/London")), + datetime(2021, 1, 5, tzinfo=ZoneInfo("Europe/London")), None, ], "d4": [datetime(2021, 11, 26).date(), datetime(2022, 2, 3).date(), None], diff --git a/py-polars/tests/unit/namespaces/test_strptime.py b/py-polars/tests/unit/namespaces/test_strptime.py index cba398d2d7d78..0d7a8fba89144 100644 --- a/py-polars/tests/unit/namespaces/test_strptime.py +++ b/py-polars/tests/unit/namespaces/test_strptime.py @@ -20,7 +20,7 @@ from polars.type_aliases import PolarsTemporalType, TimeUnit else: - from polars.utils.convert import get_zoneinfo as ZoneInfo + from polars.utils.convert import string_to_zoneinfo as ZoneInfo def test_str_strptime() -> None: @@ -505,8 +505,8 @@ def test_to_datetime_tz_aware_strptime(ts: str, fmt: str, expected: datetime) -> def test_crossing_dst(format: str) -> None: ts = ["2021-03-27T23:59:59+01:00", "2021-03-28T23:59:59+02:00"] result = pl.Series(ts).str.to_datetime(format) - assert result[0] == datetime(2021, 3, 27, 22, 59, 59, tzinfo=ZoneInfo(key="UTC")) - assert result[1] == datetime(2021, 3, 28, 21, 59, 59, tzinfo=ZoneInfo(key="UTC")) + assert result[0] == datetime(2021, 3, 27, 22, 59, 59, tzinfo=ZoneInfo("UTC")) + assert result[1] == datetime(2021, 3, 28, 21, 59, 59, tzinfo=ZoneInfo("UTC")) @pytest.mark.parametrize("format", ["%+", "%Y-%m-%dT%H:%M:%S%z"]) diff --git a/py-polars/tests/unit/operations/test_group_by_dynamic.py b/py-polars/tests/unit/operations/test_group_by_dynamic.py index 9404b22ea52a9..bb3b5fa1f5149 100644 --- a/py-polars/tests/unit/operations/test_group_by_dynamic.py +++ b/py-polars/tests/unit/operations/test_group_by_dynamic.py @@ -1,6 +1,5 @@ from __future__ import annotations -import sys from datetime import date, datetime, timedelta from typing import TYPE_CHECKING, Any @@ -10,15 +9,12 @@ import polars as pl from polars.testing import assert_frame_equal -if sys.version_info >= (3, 9): +if TYPE_CHECKING: from zoneinfo import ZoneInfo -else: - # Import from submodule due to typing issue with backports.zoneinfo package: - # https://github.com/pganssle/zoneinfo/issues/125 - from backports.zoneinfo._zoneinfo import ZoneInfo -if TYPE_CHECKING: from polars.type_aliases import Label, StartBy +else: + from polars.utils.convert import string_to_zoneinfo as ZoneInfo @pytest.mark.parametrize( diff --git a/py-polars/tests/unit/series/test_series.py b/py-polars/tests/unit/series/test_series.py index 32e60e8dfc5e9..8b48beb5edce0 100644 --- a/py-polars/tests/unit/series/test_series.py +++ b/py-polars/tests/unit/series/test_series.py @@ -36,7 +36,7 @@ from polars.type_aliases import EpochTimeUnit, PolarsDataType, TimeUnit else: - from polars.utils.convert import get_zoneinfo as ZoneInfo + from polars.utils.convert import string_to_zoneinfo as ZoneInfo def test_cum_agg() -> None: