Skip to content

Commit 3ecf731

Browse files
authored
fix(deps): drop pytz from dependencies (ibis-project#10976)
## Description of changes Hi! This PR proposes dropping `pytz` from primary dependencies and replacing it with stdlib equivalents, as recommended by `pytz` [docs](https://github.com/stub42/pytz/blob/master/src/README.rst): > Projects using Python 3.9 or later should be using the support now included as part of the standard library, and third party packages work with it such as tzdata. pytz offers no advantages beyond backwards compatibility with code written for earlier versions of Python. Given that Ibis only supports Python 3.9 and higher, this should be pretty safe.
1 parent 0edbab9 commit 3ecf731

File tree

15 files changed

+33
-41
lines changed

15 files changed

+33
-41
lines changed

conda/environment-arm64-flink.yml

-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ dependencies:
3838
- python-dateutil >=2.8.2
3939
- python-duckdb >=0.8.1
4040
- python-graphviz >=0.16
41-
- pytz >=2022.7
4241
- regex >=2021.7.6
4342
- requests >=2
4443
- rich >=13.8.0

conda/environment-arm64.yml

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ dependencies:
3939
- python-dateutil >=2.8.2
4040
- python-duckdb >=0.8.1
4141
- python-graphviz >=0.16
42-
- pytz >=2022.7
4342
- regex >=2021.7.6
4443
- requests >=2
4544
- rich >=13.8.0

conda/environment.yml

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ dependencies:
4040
- python-dateutil >=2.8.2
4141
- python-duckdb >=0.8.1
4242
- python-graphviz >=0.16
43-
- pytz >=2022.7
4443
- regex >=2021.7.6
4544
- requests >=2
4645
- rich >=13.8.0

ibis/backends/bigquery/tests/system/test_client.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import pandas.testing as tm
1111
import pyarrow as pa
1212
import pytest
13-
import pytz
1413
from google.api_core.exceptions import Forbidden
1514

1615
import ibis
@@ -256,15 +255,15 @@ def test_multiple_project_queries_execute(con):
256255

257256
def test_string_as_timestamp(con):
258257
timestamp = pd.Timestamp(
259-
datetime.datetime(year=2017, month=2, day=6), tz=pytz.timezone("UTC")
258+
datetime.datetime(year=2017, month=2, day=6), tz=datetime.timezone.utc
260259
)
261260
expr = ibis.literal("2017-02-06").as_timestamp("%F")
262261
result = con.execute(expr)
263262
assert result == timestamp
264263

265264
timestamp_tz = pd.Timestamp(
266265
datetime.datetime(year=2017, month=2, day=6, hour=5),
267-
tz=pytz.timezone("UTC"),
266+
tz=datetime.timezone.utc,
268267
)
269268
expr_tz = ibis.literal("2017-02-06 America/New_York").as_timestamp("%F %Z")
270269
result_tz = con.execute(expr_tz)

ibis/backends/flink/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import itertools
44
import re
5+
import zoneinfo
56
from typing import TYPE_CHECKING, Any
67

78
import sqlglot as sg
@@ -1055,7 +1056,6 @@ def _from_pyflink_table_to_pyarrow_batches(
10551056
):
10561057
import pyarrow as pa
10571058
import pyarrow_hotfix # noqa: F401
1058-
import pytz
10591059
from pyflink.java_gateway import get_gateway
10601060
from pyflink.table.serializers import ArrowSerializer
10611061
from pyflink.table.types import create_arrow_schema
@@ -1084,7 +1084,7 @@ def _from_pyflink_table_to_pyarrow_batches(
10841084
pyflink_schema.get_field_names(), get_field_data_types(pyflink_schema)
10851085
)
10861086

1087-
timezone = pytz.timezone(
1087+
timezone = zoneinfo.ZoneInfo(
10881088
table._j_table.getTableEnvironment().getConfig().getLocalTimeZone().getId()
10891089
)
10901090
serializer = ArrowSerializer(

ibis/backends/impala/tests/test_client.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import pandas as pd
77
import pytest
8-
import pytz
98

109
import ibis
1110
import ibis.expr.datatypes as dt
@@ -220,7 +219,9 @@ def test_day_of_week(con):
220219

221220

222221
def test_datetime_to_int_cast(con):
223-
timestamp = pytz.utc.localize(datetime.datetime(2021, 9, 12, 14, 45, 33, 0))
222+
timestamp = datetime.datetime(
223+
2021, 9, 12, 14, 45, 33, 0, tzinfo=datetime.timezone.utc
224+
)
224225
d = ibis.literal(timestamp)
225226
result = con.execute(d.cast("int64"))
226227
assert result == pd.Timestamp(timestamp).value // 1000

ibis/backends/tests/test_array.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
import math
44
import statistics
55
from collections import Counter
6-
from datetime import datetime
6+
from datetime import datetime, timezone
77
from functools import partial
88

99
import pytest
10-
import pytz
1110
import toolz
1211
from pytest import param
1312

@@ -1474,7 +1473,7 @@ def swap(token):
14741473
),
14751474
),
14761475
param(
1477-
pytz.UTC,
1476+
timezone.utc,
14781477
id="utc",
14791478
marks=pytest.mark.notyet(
14801479
["trino"],
@@ -1569,8 +1568,8 @@ def test_timestamp_range(con, start, stop, step, freq, tzinfo):
15691568
("start", "stop", "step"),
15701569
[
15711570
param(
1572-
datetime(2017, 1, 1, tzinfo=pytz.UTC),
1573-
datetime(2017, 1, 2, tzinfo=pytz.UTC),
1571+
datetime(2017, 1, 1, tzinfo=timezone.utc),
1572+
datetime(2017, 1, 2, tzinfo=timezone.utc),
15741573
ibis.interval(hours=0),
15751574
id="pos",
15761575
marks=[
@@ -1587,8 +1586,8 @@ def test_timestamp_range(con, start, stop, step, freq, tzinfo):
15871586
],
15881587
),
15891588
param(
1590-
datetime(2017, 1, 1, tzinfo=pytz.UTC),
1591-
datetime(2017, 1, 2, tzinfo=pytz.UTC),
1589+
datetime(2017, 1, 1, tzinfo=timezone.utc),
1590+
datetime(2017, 1, 2, tzinfo=timezone.utc),
15921591
-ibis.interval(hours=0),
15931592
id="neg",
15941593
marks=[

ibis/common/temporal.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import dateutil.parser
1010
import dateutil.tz
11-
import pytz
1211
from public import public
1312

1413
from ibis import util
@@ -199,7 +198,7 @@ def normalize_timezone(tz):
199198
return dateutil.tz.gettz(tz)
200199
elif isinstance(tz, (int, float)):
201200
return datetime.timezone(datetime.timedelta(hours=tz))
202-
elif isinstance(tz, (dateutil.tz.tzoffset, pytz._FixedOffset)):
201+
elif isinstance(tz, dateutil.tz.tzoffset):
203202
# this way we have a proper tzname() output, e.g. "UTC+01:00"
204203
return datetime.timezone(tz.utcoffset(None))
205204
elif isinstance(tz, datetime.tzinfo):

ibis/common/tests/test_temporal.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import dateutil
77
import pytest
8-
import pytz
98

109
from ibis.common.patterns import CoercedTo
1110
from ibis.common.temporal import (
@@ -125,7 +124,7 @@ def test_interval_unit_compatibility():
125124
("value", "expected"),
126125
[
127126
(None, None),
128-
(pytz.UTC, pytz.UTC),
127+
(timezone.utc, timezone.utc),
129128
("UTC", dateutil.tz.tzutc()),
130129
("Europe/Budapest", dateutil.tz.gettz("Europe/Budapest")),
131130
(+2, timezone(timedelta(seconds=7200))),

ibis/expr/datatypes/tests/test_value.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
import enum
55
import json
66
from collections import OrderedDict
7-
from datetime import date, datetime, timedelta
7+
from datetime import date, datetime, timedelta, timezone
88

99
import pytest
10-
import pytz
1110

1211
import ibis.expr.datatypes as dt
1312

@@ -94,9 +93,9 @@ def test_infer_mixed_type_fails():
9493

9594

9695
def test_infer_timestamp_with_tz():
97-
now_utc = datetime.now(pytz.UTC)
98-
assert now_utc.tzinfo == pytz.UTC
99-
assert dt.infer(now_utc).timezone == str(pytz.UTC)
96+
now_utc = datetime.now(timezone.utc)
97+
assert now_utc.tzinfo == timezone.utc
98+
assert dt.infer(now_utc).timezone == str(timezone.utc)
10099

101100

102101
def test_infer_timedelta():
@@ -127,19 +126,19 @@ def test_infer_timedelta():
127126
("2019-01-01 01:02:03.000004", datetime(2019, 1, 1, 1, 2, 3, 4)),
128127
(
129128
"2019-01-01 01:02:03.000004+00:00",
130-
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=pytz.utc),
129+
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=timezone.utc),
131130
),
132131
(
133132
"2019-01-01 01:02:03.000004+01:00",
134-
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=pytz.FixedOffset(60)),
133+
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=timezone(timedelta(hours=1))),
135134
),
136135
(
137136
"2019-01-01 01:02:03.000004-01:00",
138-
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=pytz.FixedOffset(-60)),
137+
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=timezone(timedelta(hours=-1))),
139138
),
140139
(
141140
"2019-01-01 01:02:03.000004+01",
142-
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=pytz.FixedOffset(60)),
141+
datetime(2019, 1, 1, 1, 2, 3, 4, tzinfo=timezone(timedelta(hours=1))),
143142
),
144143
(datetime(2019, 1, 1), datetime(2019, 1, 1)),
145144
(datetime(2019, 1, 1, 1, 2, 3, 4), datetime(2019, 1, 1, 1, 2, 3, 4)),

ibis/tests/benchmarks/test_benchmarks.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import string
1414

1515
import pytest
16-
import pytz
1716
from pytest import param
1817

1918
import ibis
@@ -977,8 +976,8 @@ def test_wide_relocate(benchmark, input, column, relative, cols):
977976

978977

979978
def test_duckdb_timestamp_conversion(benchmark, con):
980-
start = datetime.datetime(2000, 1, 1, tzinfo=pytz.UTC)
981-
stop = datetime.datetime(2000, 2, 1, tzinfo=pytz.UTC)
979+
start = datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc)
980+
stop = datetime.datetime(2000, 2, 1, tzinfo=datetime.timezone.utc)
982981
expr = ibis.range(start, stop, ibis.interval(seconds=1)).unnest()
983982

984983
series = benchmark(con.execute, expr)

ibis/tests/expr/test_value_exprs.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
import operator
66
import uuid
77
from collections import OrderedDict
8-
from datetime import date, datetime, time
8+
from datetime import date, datetime, time, timezone
99
from decimal import Decimal
1010
from operator import attrgetter, methodcaller
1111

1212
import pytest
13-
import pytz
1413
import toolz
1514
from pytest import param
1615

@@ -1116,7 +1115,7 @@ def test_timestamp_with_timezone():
11161115
assert expr.op().value == expected
11171116

11181117
expr = ibis.timestamp("2017-01-01", timezone="UTC")
1119-
expected = datetime(2017, 1, 1, tzinfo=pytz.timezone("UTC"))
1118+
expected = datetime(2017, 1, 1, tzinfo=timezone.utc)
11201119
assert expr.op().value == expected
11211120

11221121

ibis/tests/strategies.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import warnings
44

55
import hypothesis as h
6-
import hypothesis.extra.pytz as tzst
76
import hypothesis.strategies as st
87
import pytest
98

@@ -115,7 +114,7 @@ def time_dtype(nullable=_nullable):
115114
return st.builds(dt.Time, nullable=nullable)
116115

117116

118-
_timezone = st.none() | tzst.timezones().map(str)
117+
_timezone = st.none() | st.timezones().map(str)
119118
_interval = st.sampled_from(list(IntervalUnit))
120119
_timestamp_scale = st.none() | st.integers(min_value=0, max_value=9)
121120

pyproject.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ dependencies = [
5151
"atpublic>=2.3",
5252
"parsy>=2",
5353
"python-dateutil>=2.8.2",
54-
"pytz>=2022.7",
5554
"sqlglot>=23.4",
5655
"toolz>=0.11",
5756
"typing-extensions>=4.3.0",
57+
"tzdata>=2022.7", # fallback time zone data on Windows
5858
]
5959

6060
[project.urls]
@@ -138,6 +138,8 @@ exasol = [
138138
"rich>=12.4.4",
139139
]
140140
flink = [
141+
# adding apache-flink would lock pyarrow to an old version (for all backends),
142+
# due to the transitional dependency apache-beam imposing a low upper bound.
141143
"pyarrow>=10.0.1",
142144
"pyarrow-hotfix>=0.4",
143145
"numpy>=1.23.2,<3",

uv.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)