python-dateutil 2.9.0__py2.py3-none-any.whl → 3.0.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dateutil/__init__.py +7 -5
- dateutil/_tzdata_impl.py +147 -0
- dateutil/_version.py +2 -14
- dateutil/relativedelta.py +0 -3
- dateutil/rrule.py +28 -1
- dateutil/tz/__init__.py +52 -4
- dateutil/tz/_tzfile.py +1428 -0
- dateutil/tz/_tzpath.py +104 -0
- dateutil/tz/tz.py +201 -578
- dateutil/zoneinfo/__init__.py +107 -41
- dateutil/zoneinfo/rebuild.py +31 -64
- {python_dateutil-2.9.0.dist-info → python_dateutil-3.0.0.dist-info}/METADATA +16 -16
- python_dateutil-3.0.0.dist-info/RECORD +27 -0
- {python_dateutil-2.9.0.dist-info → python_dateutil-3.0.0.dist-info}/WHEEL +1 -1
- dateutil/zoneinfo/dateutil-zoneinfo.tar.gz +0 -0
- python_dateutil-2.9.0.dist-info/RECORD +0 -25
- {python_dateutil-2.9.0.dist-info → python_dateutil-3.0.0.dist-info/licenses}/LICENSE +0 -0
- {python_dateutil-2.9.0.dist-info → python_dateutil-3.0.0.dist-info}/top_level.txt +0 -0
- {python_dateutil-2.9.0.dist-info → python_dateutil-3.0.0.dist-info}/zip-safe +0 -0
dateutil/__init__.py
CHANGED
|
@@ -6,19 +6,21 @@ try:
|
|
|
6
6
|
except ImportError:
|
|
7
7
|
__version__ = 'unknown'
|
|
8
8
|
|
|
9
|
-
__all__ = [
|
|
10
|
-
|
|
9
|
+
__all__ = ["easter", "parser", "relativedelta", "rrule", "tz", "utils"]
|
|
10
|
+
|
|
11
11
|
|
|
12
12
|
def __getattr__(name):
|
|
13
13
|
import importlib
|
|
14
14
|
|
|
15
|
-
if name in __all__:
|
|
15
|
+
if name in __all__ or name == "zoneinfo":
|
|
16
16
|
return importlib.import_module("." + name, __name__)
|
|
17
17
|
raise AttributeError(
|
|
18
|
-
"module {!r} has
|
|
18
|
+
"module {!r} has no attribute {!r}".format(__name__, name)
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def __dir__():
|
|
23
23
|
# __dir__ should include all the lazy-importable modules as well.
|
|
24
|
-
return
|
|
24
|
+
return (
|
|
25
|
+
[x for x in globals() if x not in sys.modules] + __all__ + ["zoneinfo"]
|
|
26
|
+
)
|
dateutil/_tzdata_impl.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""This is an implementation of functions that interact with the tzdata module.
|
|
2
|
+
|
|
3
|
+
It will only live as long as :mod:`dateutil.zoneinfo` lives; when the
|
|
4
|
+
``dateutil.zoneinfo`` module is removed, this can all move under :mod:`tz`.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import contextlib
|
|
8
|
+
import importlib
|
|
9
|
+
import io
|
|
10
|
+
import os
|
|
11
|
+
import pkgutil
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
import six
|
|
15
|
+
|
|
16
|
+
if six.PY2:
|
|
17
|
+
_TZDATA_LOAD_EXCEPTIONS = (
|
|
18
|
+
ImportError,
|
|
19
|
+
IOError,
|
|
20
|
+
UnicodeEncodeError,
|
|
21
|
+
ValueError,
|
|
22
|
+
)
|
|
23
|
+
else:
|
|
24
|
+
_TZDATA_LOAD_EXCEPTIONS = (
|
|
25
|
+
ImportError,
|
|
26
|
+
FileNotFoundError,
|
|
27
|
+
UnicodeEncodeError,
|
|
28
|
+
IsADirectoryError,
|
|
29
|
+
ValueError,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if sys.version_info < (3, 8):
|
|
33
|
+
_nullcontext = getattr(contextlib, "nullcontext", None)
|
|
34
|
+
if _nullcontext is None:
|
|
35
|
+
|
|
36
|
+
@contextlib.contextmanager
|
|
37
|
+
def _nullcontext(v):
|
|
38
|
+
yield v
|
|
39
|
+
|
|
40
|
+
def _get_data(package, resource):
|
|
41
|
+
# pkgutil.get_data returns None rather than raising when the package
|
|
42
|
+
# cannot be found (and on Python 2 raises AttributeError if the
|
|
43
|
+
# package has been blocked by setting sys.modules[name] = None), so
|
|
44
|
+
# import the package first to get the ImportError the callers expect
|
|
45
|
+
# from the importlib.resources versions of these functions.
|
|
46
|
+
importlib.import_module(package)
|
|
47
|
+
|
|
48
|
+
pkg_data = pkgutil.get_data(package, resource)
|
|
49
|
+
if pkg_data is None:
|
|
50
|
+
raise ImportError("No package named %r" % package)
|
|
51
|
+
|
|
52
|
+
return pkg_data
|
|
53
|
+
|
|
54
|
+
def _open_text(package, resource):
|
|
55
|
+
str_package_data = _get_data(package, resource).decode("utf-8")
|
|
56
|
+
|
|
57
|
+
return _nullcontext(io.StringIO(str_package_data))
|
|
58
|
+
|
|
59
|
+
def _open_binary(package, resource):
|
|
60
|
+
return io.BytesIO(_get_data(package, resource))
|
|
61
|
+
|
|
62
|
+
else:
|
|
63
|
+
import importlib.resources
|
|
64
|
+
|
|
65
|
+
if sys.version_info >= (3, 9):
|
|
66
|
+
|
|
67
|
+
def _open_text(package, resource):
|
|
68
|
+
return (
|
|
69
|
+
importlib.resources.files(package)
|
|
70
|
+
.joinpath(resource)
|
|
71
|
+
.open("r", encoding="utf-8")
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def _open_binary(package, resource):
|
|
75
|
+
return (
|
|
76
|
+
importlib.resources.files(package).joinpath(resource).open("rb")
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
_open_text = importlib.resources.open_text
|
|
81
|
+
_open_binary = importlib.resources.open_binary
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _is_package_directory(package, resource):
|
|
85
|
+
"""Whether ``resource`` names a directory inside ``package``.
|
|
86
|
+
|
|
87
|
+
Opening a directory raises IsADirectoryError on POSIX but PermissionError
|
|
88
|
+
on Windows, and on Python < 3.9 there is no portable way to ask the
|
|
89
|
+
resource API, so check the package's search path directly (the tzdata
|
|
90
|
+
package is a regular directory-backed package).
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
pkg = importlib.import_module(package)
|
|
94
|
+
except ImportError:
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
for base in getattr(pkg, "__path__", ()):
|
|
98
|
+
if os.path.isdir(os.path.join(base, resource)):
|
|
99
|
+
return True
|
|
100
|
+
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _load_tzdata(key):
|
|
105
|
+
components = key.split("/")
|
|
106
|
+
package_name = ".".join(["tzdata.zoneinfo"] + components[:-1])
|
|
107
|
+
resource_name = components[-1]
|
|
108
|
+
|
|
109
|
+
# Empty or relative path components cannot name a zone, and they produce
|
|
110
|
+
# module names that the import machinery handles inconsistently across
|
|
111
|
+
# versions, so treat them as not found up front. A key naming a directory
|
|
112
|
+
# (a subpackage) is not a zone either, and opening it raises a
|
|
113
|
+
# platform-dependent error, see CPython gh-85702.
|
|
114
|
+
if any(c in ("", ".", "..") for c in components) or _is_package_directory(
|
|
115
|
+
package_name, resource_name
|
|
116
|
+
):
|
|
117
|
+
raise TZFileNotFound("Time zone not found: %s", zone_key=key)
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
return _open_binary(package_name, resource_name)
|
|
121
|
+
except _TZDATA_LOAD_EXCEPTIONS:
|
|
122
|
+
# ImportError: package does not exist (or tzdata is not installed)
|
|
123
|
+
# FileNotFoundError: the key is not a file in the package
|
|
124
|
+
# UnicodeEncodeError: the key is not encodable as a filename
|
|
125
|
+
# IsADirectoryError: the key names a package rather than a resource
|
|
126
|
+
# ValueError: the key is not a valid path (e.g. contains a NUL byte)
|
|
127
|
+
six.raise_from(
|
|
128
|
+
TZFileNotFound("Time zone not found: %s", zone_key=key), None
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _load_tzdata_keys():
|
|
133
|
+
with _open_text("tzdata", "zones") as f:
|
|
134
|
+
return list(filter(None, (l.strip() for l in f)))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class TZFileNotFound(ValueError):
|
|
138
|
+
"""Indicates that a time zone file isn't present in tzdata."""
|
|
139
|
+
|
|
140
|
+
def __init__(self, msg, *args, **kwargs):
|
|
141
|
+
# TODO: Use keyword-only argument when this is Python 3-only
|
|
142
|
+
zone_key = kwargs.pop("zone_key", None)
|
|
143
|
+
if zone_key is None: # pragma: nocover
|
|
144
|
+
raise TypeError("Required keyword argument missing: zone_key")
|
|
145
|
+
|
|
146
|
+
super(TZFileNotFound, self).__init__(msg % zone_key, *args)
|
|
147
|
+
self.zone_key = zone_key
|
dateutil/_version.py
CHANGED
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
# file generated by setuptools_scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
from typing import Tuple, Union
|
|
6
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
-
else:
|
|
8
|
-
VERSION_TUPLE = object
|
|
9
|
-
|
|
10
|
-
version: str
|
|
11
|
-
__version__: str
|
|
12
|
-
__version_tuple__: VERSION_TUPLE
|
|
13
|
-
version_tuple: VERSION_TUPLE
|
|
14
|
-
|
|
15
|
-
__version__ = version = '2.9.0'
|
|
16
|
-
__version_tuple__ = version_tuple = (2, 9, 0)
|
|
3
|
+
__version__ = version = '3.0.0'
|
|
4
|
+
__version_tuple__ = version_tuple = (3, 0, 0)
|
dateutil/relativedelta.py
CHANGED
dateutil/rrule.py
CHANGED
|
@@ -102,6 +102,30 @@ class rrulebase(object):
|
|
|
102
102
|
self._cache_complete = False
|
|
103
103
|
self._len = None
|
|
104
104
|
|
|
105
|
+
def __reduce_ex__(self, protocol):
|
|
106
|
+
rv = super(rrulebase, self).__reduce_ex__(protocol)
|
|
107
|
+
state, slots = rv[2], None
|
|
108
|
+
if isinstance(state, tuple):
|
|
109
|
+
state, slots = state
|
|
110
|
+
if self._cache is not None:
|
|
111
|
+
state = dict(state)
|
|
112
|
+
state.pop("_cache_lock", None)
|
|
113
|
+
state.pop("_cache_gen", None)
|
|
114
|
+
state["_cache"] = []
|
|
115
|
+
if slots is not None:
|
|
116
|
+
state = (state, slots)
|
|
117
|
+
return rv[:2] + (state,) + rv[3:]
|
|
118
|
+
|
|
119
|
+
def __setstate__(self, state):
|
|
120
|
+
if isinstance(state, tuple):
|
|
121
|
+
state, slots = state
|
|
122
|
+
for name, value in slots.items():
|
|
123
|
+
setattr(self, name, value)
|
|
124
|
+
self.__dict__.update(state)
|
|
125
|
+
if self._cache is not None:
|
|
126
|
+
self._cache_lock = _thread.allocate_lock()
|
|
127
|
+
self._invalidate_cache()
|
|
128
|
+
|
|
105
129
|
def __iter__(self):
|
|
106
130
|
if self._cache_complete:
|
|
107
131
|
return iter(self._cache)
|
|
@@ -1672,7 +1696,10 @@ class _rrulestr(object):
|
|
|
1672
1696
|
parms = parms[1:]
|
|
1673
1697
|
if name == "RRULE":
|
|
1674
1698
|
for parm in parms:
|
|
1675
|
-
|
|
1699
|
+
if parm.startswith("X-"):
|
|
1700
|
+
# Experimental random vendor features; safe to ignore
|
|
1701
|
+
continue
|
|
1702
|
+
raise ValueError("unsupported RRULE parm: " + parm)
|
|
1676
1703
|
rrulevals.append(value)
|
|
1677
1704
|
elif name == "RDATE":
|
|
1678
1705
|
for parm in parms:
|
dateutil/tz/__init__.py
CHANGED
|
@@ -1,11 +1,59 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from . import _tzpath
|
|
5
|
+
from ._tzpath import reset_tzpath
|
|
2
6
|
from .tz import *
|
|
3
7
|
from .tz import __doc__
|
|
4
8
|
|
|
5
|
-
__all__ = [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
__all__ = [
|
|
10
|
+
"tzutc",
|
|
11
|
+
"tzoffset",
|
|
12
|
+
"tzlocal",
|
|
13
|
+
"tzfile",
|
|
14
|
+
"tzrange",
|
|
15
|
+
"tzstr",
|
|
16
|
+
"tzical",
|
|
17
|
+
"tzwin",
|
|
18
|
+
"tzwinlocal",
|
|
19
|
+
"gettz",
|
|
20
|
+
"enfold",
|
|
21
|
+
"datetime_ambiguous",
|
|
22
|
+
"datetime_exists",
|
|
23
|
+
"resolve_imaginary",
|
|
24
|
+
"available_iana_timezones",
|
|
25
|
+
"UTC",
|
|
26
|
+
"TZPATH",
|
|
27
|
+
"reset_tzpath",
|
|
28
|
+
"DeprecatedTzFormatWarning",
|
|
29
|
+
"DeprecatedTzKeyWarning",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
if sys.version_info < (3, 7):
|
|
33
|
+
# Module-level __getattr__ was added in Python 3.7, so instead of lazily
|
|
34
|
+
# populating TZPATH on every access, we will register a callback with
|
|
35
|
+
# reset_tzpath to update the top-level tuple.
|
|
36
|
+
TZPATH = _tzpath.TZPATH
|
|
37
|
+
|
|
38
|
+
def _tzpath_callback(new_tzpath):
|
|
39
|
+
global TZPATH
|
|
40
|
+
TZPATH = new_tzpath
|
|
41
|
+
|
|
42
|
+
_tzpath.TZPATH_CALLBACKS.append(_tzpath_callback)
|
|
43
|
+
|
|
44
|
+
else:
|
|
45
|
+
|
|
46
|
+
def __getattr__(name):
|
|
47
|
+
if name == "TZPATH":
|
|
48
|
+
return _tzpath.TZPATH
|
|
49
|
+
else:
|
|
50
|
+
raise AttributeError(
|
|
51
|
+
"Module %s has no attribute %s" % (repr(__name__), repr(name))
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def __dir__():
|
|
56
|
+
return sorted(list(globals()) + ["TZPATH"])
|
|
9
57
|
|
|
10
58
|
|
|
11
59
|
class DeprecatedTzFormatWarning(Warning):
|