Skip to content

Commit

Permalink
Explicitly deprecate zoneinfo, remove from __all__
Browse files Browse the repository at this point in the history
Removing `dateutil.zoneinfo` from `__all__` is a breaking change, but
I suspect that this is better than raising DeprecationWarning for
everyone who does `from dateutil import *`.
  • Loading branch information
pganssle committed Apr 27, 2023
1 parent 5cbb146 commit e362489
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 47 deletions.
10 changes: 6 additions & 4 deletions src/dateutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
except ImportError:
__version__ = 'unknown'

__all__ = ['easter', 'parser', 'relativedelta', 'rrule', 'tz',
'utils', 'zoneinfo']
__all__ = ["easter", "parser", "relativedelta", "rrule", "tz", "utils"]


def __getattr__(name):
import importlib

if name in __all__:
if name in __all__ or name == "zoneinfo":
return importlib.import_module("." + name, __name__)
raise AttributeError(
"module {!r} has not attribute {!r}".format(__name__, name)
Expand All @@ -21,4 +21,6 @@ def __getattr__(name):

def __dir__():
# __dir__ should include all the lazy-importable modules as well.
return [x for x in globals() if x not in sys.modules] + __all__
return (
[x for x in globals() if x not in sys.modules] + __all__ + ["zoneinfo,"]
)
33 changes: 31 additions & 2 deletions src/dateutil/zoneinfo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
# -*- coding: utf-8 -*-
"""
The ``dateutil.zoneinfo`` module was originally designed to work with a tarball
shipped with ``dateutil``. Since ``dateutil`` now uses data from the same
sources as :py:mod:`zoneinfo`, this module is no longer necessary.
.. caution::
This module is deprecated, and its functionality has been dramatically
curtailed. It is recommended that you adopt the standard library module
:py:mod:`zoneinfo` or :func:`dateutil.tz.gettz` instead.
"""
import json
import sys
import warnings
Expand All @@ -11,9 +22,18 @@

__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"]

ZONEFILENAME = "dateutil-zoneinfo.tar.gz"
ZONEFILENAME = None
METADATA_FN = 'METADATA'

warnings.warn(
"The `dateutil.zoneinfo` module has been replaced with a wrapper around "
"the tzdata package, and its use is deprecated, to be removed in a future "
"version. Use the standard library module `zoneinfo` or `dateutil.tz`"
"instead.",
DeprecationWarning,
stacklevel=2,
)


class tzfile(_tzfile):
def __reduce__(self):
Expand All @@ -31,7 +51,16 @@ def __init__(self, zonefile_stream=None):
self._eager_load_tzdata()

def _eager_load_tzdata(self):
import tzdata
try:
import tzdata
except ImportError as e:
six.raise_from(
ImportError(
"The tzdata module is required to use ZoneInfoFile; either add "
"a dependency on tzdata or migrate away from dateutil.zoneinfo."
),
e,
)

zone_dict = {}

Expand Down
2 changes: 0 additions & 2 deletions tests/test_import_star.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ def test_imported_modules():
import dateutil.rrule
import dateutil.tz
import dateutil.utils
import dateutil.zoneinfo

assert dateutil.easter == new_locals.pop("easter")
assert dateutil.parser == new_locals.pop("parser")
assert dateutil.relativedelta == new_locals.pop("relativedelta")
assert dateutil.rrule == new_locals.pop("rrule")
assert dateutil.tz == new_locals.pop("tz")
assert dateutil.utils == new_locals.pop("utils")
assert dateutil.zoneinfo == new_locals.pop("zoneinfo")

assert not new_locals
98 changes: 60 additions & 38 deletions tests/test_imports.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys
import unittest

import pytest
import six

Expand Down Expand Up @@ -49,12 +50,14 @@ def clean_import():
@filter_import_warning
@pytest.mark.parametrize(
"module",
["easter", "parser", "relativedelta", "rrule", "tz", "utils", "zoneinfo"],
["easter", "parser", "relativedelta", "rrule", "tz", "utils"],
)
def test_lazy_import(clean_import, module):
"""Test that dateutil.[submodule] works for py version > 3.7"""

import dateutil, importlib
import importlib

import dateutil

if sys.version_info < (3, 7):
pytest.xfail("Lazy loading does not work for Python < 3.7")
Expand All @@ -66,6 +69,14 @@ def test_lazy_import(clean_import, module):
assert mod_obj is mod_imported


def test_lazy_import_zoneinfo(clean_import):
"""Test that zoneinfo raises a DeprecationWarning when imported lazily."""
import dateutil

with pytest.warns(DeprecationWarning):
assert dateutil.zoneinfo is not None


HOST_IS_WINDOWS = sys.platform.startswith('win')


Expand Down Expand Up @@ -103,11 +114,8 @@ def test_import_parser_from():

def test_import_parser_all():
# All interface
from dateutil.parser import parse
from dateutil.parser import parserinfo

# Other public classes
from dateutil.parser import parser
from dateutil.parser import parse, parser, parserinfo

for var in (parse, parserinfo, parser):
assert var is not None
Expand All @@ -122,8 +130,7 @@ def test_import_relative_delta_from():
from dateutil import relativedelta

def test_import_relative_delta_all():
from dateutil.relativedelta import relativedelta
from dateutil.relativedelta import MO, TU, WE, TH, FR, SA, SU
from dateutil.relativedelta import FR, MO, SA, SU, TH, TU, WE, relativedelta

for var in (relativedelta, MO, TU, WE, TH, FR, SA, SU):
assert var is not None
Expand All @@ -143,12 +150,25 @@ def test_import_rrule_from():


def test_import_rrule_all():
from dateutil.rrule import rrule
from dateutil.rrule import rruleset
from dateutil.rrule import rrulestr
from dateutil.rrule import YEARLY, MONTHLY, WEEKLY, DAILY
from dateutil.rrule import HOURLY, MINUTELY, SECONDLY
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
from dateutil.rrule import (
DAILY,
FR,
HOURLY,
MINUTELY,
MO,
MONTHLY,
SA,
SECONDLY,
SU,
TH,
TU,
WE,
WEEKLY,
YEARLY,
rrule,
rruleset,
rrulestr,
)

rr_all = (rrule, rruleset, rrulestr,
YEARLY, MONTHLY, WEEKLY, DAILY,
Expand All @@ -173,20 +193,22 @@ def test_import_tz_from():


def test_import_tz_all():
from dateutil.tz import tzutc
from dateutil.tz import tzoffset
from dateutil.tz import tzlocal
from dateutil.tz import tzfile
from dateutil.tz import tzrange
from dateutil.tz import tzstr
from dateutil.tz import tzical
from dateutil.tz import gettz
from dateutil.tz import tzwin
from dateutil.tz import tzwinlocal
from dateutil.tz import UTC
from dateutil.tz import datetime_ambiguous
from dateutil.tz import datetime_exists
from dateutil.tz import resolve_imaginary
from dateutil.tz import (
UTC,
datetime_ambiguous,
datetime_exists,
gettz,
resolve_imaginary,
tzfile,
tzical,
tzlocal,
tzoffset,
tzrange,
tzstr,
tzutc,
tzwin,
tzwinlocal,
)

tz_all = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
"tzstr", "tzical", "gettz", "datetime_ambiguous",
Expand All @@ -211,8 +233,7 @@ def test_import_tz_windows_from():

@pytest.mark.skipif(not HOST_IS_WINDOWS, reason="Requires Windows")
def test_import_tz_windows_star():
from dateutil.tzwin import tzwin
from dateutil.tzwin import tzwinlocal
from dateutil.tzwin import tzwin, tzwinlocal

tzwin_all = [tzwin, tzwinlocal]

Expand All @@ -221,18 +242,19 @@ def test_import_tz_windows_star():


# Test imports of Zone Info
def test_import_zone_info_direct():
import dateutil.zoneinfo
def test_import_zone_info_direct(clean_import):
with pytest.warns(DeprecationWarning):
import dateutil.zoneinfo


def test_import_zone_info_from():
from dateutil import zoneinfo
def test_import_zone_info_from(clean_import):
with pytest.warns(DeprecationWarning):
from dateutil import zoneinfo


def test_import_zone_info_star():
from dateutil.zoneinfo import gettz
from dateutil.zoneinfo import gettz_db_metadata
from dateutil.zoneinfo import rebuild
def test_import_zone_info_star(clean_import):
with pytest.warns(DeprecationWarning):
from dateutil.zoneinfo import gettz, gettz_db_metadata, rebuild

zi_all = (gettz, gettz_db_metadata, rebuild)

Expand Down
6 changes: 5 additions & 1 deletion tests/test_tz.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import sys
import threading
import unittest
import warnings
import weakref
from datetime import datetime
from datetime import time as dt_time
Expand All @@ -23,9 +24,12 @@
import pytest

from dateutil import tz as tz
from dateutil import zoneinfo
from dateutil.parser import parse

with warnings.catch_warnings():
warnings.simplefilter("ignore", category=DeprecationWarning)
from dateutil import zoneinfo

# dateutil imports
from dateutil.relativedelta import SU, TH, relativedelta

Expand Down

0 comments on commit e362489

Please sign in to comment.