mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-14 02:26:58 -07:00
Bump apscheduler from 3.8.0 to 3.9.1 (#1675)
* Bump apscheduler from 3.8.0 to 3.9.1 Bumps [apscheduler](https://github.com/agronholm/apscheduler) from 3.8.0 to 3.9.1. - [Release notes](https://github.com/agronholm/apscheduler/releases) - [Changelog](https://github.com/agronholm/apscheduler/blob/3.9.1/docs/versionhistory.rst) - [Commits](https://github.com/agronholm/apscheduler/compare/3.8.0...3.9.1) --- updated-dependencies: - dependency-name: apscheduler dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update apscheduler==3.9.1 * Update pytz==2022.1 * Add pytz-deprecation-shim==0.1.0.post0 * Update tzdata==2022.1 * Update tzlocal==4.2 * Update requirements.txt Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
942e09e59e
commit
54c9214b03
46 changed files with 1029 additions and 223 deletions
34
lib/pytz_deprecation_shim/__init__.py
Normal file
34
lib/pytz_deprecation_shim/__init__.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
__all__ = [
|
||||
"AmbiguousTimeError",
|
||||
"NonExistentTimeError",
|
||||
"InvalidTimeError",
|
||||
"UnknownTimeZoneError",
|
||||
"PytzUsageWarning",
|
||||
"FixedOffset",
|
||||
"UTC",
|
||||
"utc",
|
||||
"build_tzinfo",
|
||||
"timezone",
|
||||
"fixed_offset_timezone",
|
||||
"wrap_zone",
|
||||
]
|
||||
|
||||
from . import helpers
|
||||
from ._exceptions import (
|
||||
AmbiguousTimeError,
|
||||
InvalidTimeError,
|
||||
NonExistentTimeError,
|
||||
PytzUsageWarning,
|
||||
UnknownTimeZoneError,
|
||||
)
|
||||
from ._impl import (
|
||||
UTC,
|
||||
build_tzinfo,
|
||||
fixed_offset_timezone,
|
||||
timezone,
|
||||
wrap_zone,
|
||||
)
|
||||
|
||||
# Compatibility aliases
|
||||
utc = UTC
|
||||
FixedOffset = fixed_offset_timezone
|
13
lib/pytz_deprecation_shim/_common.py
Normal file
13
lib/pytz_deprecation_shim/_common.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import sys
|
||||
|
||||
_PYTZ_IMPORTED = False
|
||||
|
||||
|
||||
def pytz_imported():
|
||||
"""Detects whether or not pytz has been imported without importing pytz."""
|
||||
global _PYTZ_IMPORTED
|
||||
|
||||
if not _PYTZ_IMPORTED and "pytz" in sys.modules:
|
||||
_PYTZ_IMPORTED = True
|
||||
|
||||
return _PYTZ_IMPORTED
|
15
lib/pytz_deprecation_shim/_compat.py
Normal file
15
lib/pytz_deprecation_shim/_compat.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import sys
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
from . import _compat_py2 as _compat_impl
|
||||
else:
|
||||
from . import _compat_py3 as _compat_impl
|
||||
|
||||
UTC = _compat_impl.UTC
|
||||
get_timezone = _compat_impl.get_timezone
|
||||
get_timezone_file = _compat_impl.get_timezone_file
|
||||
get_fixed_offset_zone = _compat_impl.get_fixed_offset_zone
|
||||
is_ambiguous = _compat_impl.is_ambiguous
|
||||
is_imaginary = _compat_impl.is_imaginary
|
||||
enfold = _compat_impl.enfold
|
||||
get_fold = _compat_impl.get_fold
|
43
lib/pytz_deprecation_shim/_compat_py2.py
Normal file
43
lib/pytz_deprecation_shim/_compat_py2.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from datetime import timedelta
|
||||
|
||||
from dateutil import tz
|
||||
|
||||
UTC = tz.UTC
|
||||
|
||||
|
||||
def get_timezone(key):
|
||||
if not key:
|
||||
raise KeyError("Unknown time zone: %s" % key)
|
||||
|
||||
try:
|
||||
rv = tz.gettz(key)
|
||||
except Exception:
|
||||
rv = None
|
||||
|
||||
if rv is None or not isinstance(rv, (tz.tzutc, tz.tzfile)):
|
||||
raise KeyError("Unknown time zone: %s" % key)
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def get_timezone_file(f, key=None):
|
||||
return tz.tzfile(f)
|
||||
|
||||
|
||||
def get_fixed_offset_zone(offset):
|
||||
return tz.tzoffset(None, timedelta(minutes=offset))
|
||||
|
||||
|
||||
def is_ambiguous(dt):
|
||||
return tz.datetime_ambiguous(dt)
|
||||
|
||||
|
||||
def is_imaginary(dt):
|
||||
return not tz.datetime_exists(dt)
|
||||
|
||||
|
||||
enfold = tz.enfold
|
||||
|
||||
|
||||
def get_fold(dt):
|
||||
return getattr(dt, "fold", 0)
|
58
lib/pytz_deprecation_shim/_compat_py3.py
Normal file
58
lib/pytz_deprecation_shim/_compat_py3.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Note: This file could use Python 3-only syntax, but at the moment this breaks
|
||||
# the coverage job on Python 2. Until we make it so that coverage can ignore
|
||||
# this file only on Python 2, we'll have to stick to 2/3-compatible syntax.
|
||||
try:
|
||||
import zoneinfo
|
||||
except ImportError:
|
||||
from backports import zoneinfo
|
||||
|
||||
import datetime
|
||||
|
||||
UTC = datetime.timezone.utc
|
||||
|
||||
|
||||
def get_timezone(key):
|
||||
try:
|
||||
return zoneinfo.ZoneInfo(key)
|
||||
except (ValueError, OSError):
|
||||
# TODO: Use `from e` when this file can use Python 3 syntax
|
||||
raise KeyError(key)
|
||||
|
||||
|
||||
def get_timezone_file(f, key=None):
|
||||
return zoneinfo.ZoneInfo.from_file(f, key=key)
|
||||
|
||||
|
||||
def get_fixed_offset_zone(offset):
|
||||
return datetime.timezone(datetime.timedelta(minutes=offset))
|
||||
|
||||
|
||||
def is_imaginary(dt):
|
||||
dt_rt = dt.astimezone(UTC).astimezone(dt.tzinfo)
|
||||
|
||||
return not (dt == dt_rt)
|
||||
|
||||
|
||||
def is_ambiguous(dt):
|
||||
if is_imaginary(dt):
|
||||
return False
|
||||
|
||||
wall_0 = dt
|
||||
wall_1 = dt.replace(fold=not dt.fold)
|
||||
|
||||
# Ambiguous datetimes can only exist if the offset changes, so we don't
|
||||
# actually have to check whether dst() or tzname() are different.
|
||||
same_offset = wall_0.utcoffset() == wall_1.utcoffset()
|
||||
|
||||
return not same_offset
|
||||
|
||||
|
||||
def enfold(dt, fold=1):
|
||||
if dt.fold != fold:
|
||||
return dt.replace(fold=fold)
|
||||
else:
|
||||
return dt
|
||||
|
||||
|
||||
def get_fold(dt):
|
||||
return dt.fold
|
75
lib/pytz_deprecation_shim/_exceptions.py
Normal file
75
lib/pytz_deprecation_shim/_exceptions.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
from ._common import pytz_imported
|
||||
|
||||
|
||||
class PytzUsageWarning(RuntimeWarning):
|
||||
"""Warning raised when accessing features specific to ``pytz``'s interface.
|
||||
|
||||
This warning is used to direct users of ``pytz``-specific features like the
|
||||
``localize`` and ``normalize`` methods towards using the standard
|
||||
``tzinfo`` interface, so that these shims can be replaced with one of the
|
||||
underlying libraries they are wrapping.
|
||||
"""
|
||||
|
||||
|
||||
class UnknownTimeZoneError(KeyError):
|
||||
"""Raised when no time zone is found for a specified key."""
|
||||
|
||||
|
||||
class InvalidTimeError(Exception):
|
||||
"""The base class for exceptions related to folds and gaps."""
|
||||
|
||||
|
||||
class AmbiguousTimeError(InvalidTimeError):
|
||||
"""Exception raised when ``is_dst=None`` for an ambiguous time (fold)."""
|
||||
|
||||
|
||||
class NonExistentTimeError(InvalidTimeError):
|
||||
"""Exception raised when ``is_dst=None`` for a non-existent time (gap)."""
|
||||
|
||||
|
||||
PYTZ_BASE_ERROR_MAPPING = {}
|
||||
|
||||
|
||||
def _make_pytz_derived_errors(
|
||||
InvalidTimeError_=InvalidTimeError,
|
||||
AmbiguousTimeError_=AmbiguousTimeError,
|
||||
NonExistentTimeError_=NonExistentTimeError,
|
||||
UnknownTimeZoneError_=UnknownTimeZoneError,
|
||||
):
|
||||
if PYTZ_BASE_ERROR_MAPPING or not pytz_imported():
|
||||
return
|
||||
|
||||
import pytz
|
||||
|
||||
class InvalidTimeError(InvalidTimeError_, pytz.InvalidTimeError):
|
||||
pass
|
||||
|
||||
class AmbiguousTimeError(AmbiguousTimeError_, pytz.AmbiguousTimeError):
|
||||
pass
|
||||
|
||||
class NonExistentTimeError(
|
||||
NonExistentTimeError_, pytz.NonExistentTimeError
|
||||
):
|
||||
pass
|
||||
|
||||
class UnknownTimeZoneError(
|
||||
UnknownTimeZoneError_, pytz.UnknownTimeZoneError
|
||||
):
|
||||
pass
|
||||
|
||||
PYTZ_BASE_ERROR_MAPPING.update(
|
||||
{
|
||||
InvalidTimeError_: InvalidTimeError,
|
||||
AmbiguousTimeError_: AmbiguousTimeError,
|
||||
NonExistentTimeError_: NonExistentTimeError,
|
||||
UnknownTimeZoneError_: UnknownTimeZoneError,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def get_exception(exc_type, msg):
|
||||
_make_pytz_derived_errors()
|
||||
|
||||
out_exc_type = PYTZ_BASE_ERROR_MAPPING.get(exc_type, exc_type)
|
||||
|
||||
return out_exc_type(msg)
|
296
lib/pytz_deprecation_shim/_impl.py
Normal file
296
lib/pytz_deprecation_shim/_impl.py
Normal file
|
@ -0,0 +1,296 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import warnings
|
||||
from datetime import tzinfo
|
||||
|
||||
from . import _compat
|
||||
from ._exceptions import (
|
||||
AmbiguousTimeError,
|
||||
NonExistentTimeError,
|
||||
PytzUsageWarning,
|
||||
UnknownTimeZoneError,
|
||||
get_exception,
|
||||
)
|
||||
|
||||
IS_DST_SENTINEL = object()
|
||||
KEY_SENTINEL = object()
|
||||
|
||||
|
||||
def timezone(key, _cache={}):
|
||||
"""Builds an IANA database time zone shim.
|
||||
|
||||
This is the equivalent of ``pytz.timezone``.
|
||||
|
||||
:param key:
|
||||
A valid key from the IANA time zone database.
|
||||
|
||||
:raises UnknownTimeZoneError:
|
||||
If an unknown value is passed, this will raise an exception that can be
|
||||
caught by :exc:`pytz_deprecation_shim.UnknownTimeZoneError` or
|
||||
``pytz.UnknownTimeZoneError``. Like
|
||||
:exc:`zoneinfo.ZoneInfoNotFoundError`, both of those are subclasses of
|
||||
:exc:`KeyError`.
|
||||
"""
|
||||
instance = _cache.get(key, None)
|
||||
if instance is None:
|
||||
if len(key) == 3 and key.lower() == "utc":
|
||||
instance = _cache.setdefault(key, UTC)
|
||||
else:
|
||||
try:
|
||||
zone = _compat.get_timezone(key)
|
||||
except KeyError:
|
||||
raise get_exception(UnknownTimeZoneError, key)
|
||||
instance = _cache.setdefault(key, wrap_zone(zone, key=key))
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
def fixed_offset_timezone(offset, _cache={}):
|
||||
"""Builds a fixed offset time zone shim.
|
||||
|
||||
This is the equivalent of ``pytz.FixedOffset``. An alias is available as
|
||||
``pytz_deprecation_shim.FixedOffset`` as well.
|
||||
|
||||
:param offset:
|
||||
A fixed offset from UTC, in minutes. This must be in the range ``-1439
|
||||
<= offset <= 1439``.
|
||||
|
||||
:raises ValueError:
|
||||
For offsets whose absolute value is greater than or equal to 24 hours.
|
||||
|
||||
:return:
|
||||
A shim time zone.
|
||||
"""
|
||||
if not (-1440 < offset < 1440):
|
||||
raise ValueError("absolute offset is too large", offset)
|
||||
|
||||
instance = _cache.get(offset, None)
|
||||
if instance is None:
|
||||
if offset == 0:
|
||||
instance = _cache.setdefault(offset, UTC)
|
||||
else:
|
||||
zone = _compat.get_fixed_offset_zone(offset)
|
||||
instance = _cache.setdefault(offset, wrap_zone(zone, key=None))
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
def build_tzinfo(zone, fp):
|
||||
"""Builds a shim object from a TZif file.
|
||||
|
||||
This is a shim for ``pytz.build_tzinfo``. Given a value to use as the zone
|
||||
IANA key and a file-like object containing a valid TZif file (i.e.
|
||||
conforming to :rfc:`8536`), this builds a time zone object and wraps it in
|
||||
a shim class.
|
||||
|
||||
The argument names are chosen to match those in ``pytz.build_tzinfo``.
|
||||
|
||||
:param zone:
|
||||
A string to be used as the time zone object's IANA key.
|
||||
|
||||
:param fp:
|
||||
A readable file-like object emitting bytes, pointing to a valid TZif
|
||||
file.
|
||||
|
||||
:return:
|
||||
A shim time zone.
|
||||
"""
|
||||
zone_file = _compat.get_timezone_file(fp)
|
||||
|
||||
return wrap_zone(zone_file, key=zone)
|
||||
|
||||
|
||||
def wrap_zone(tz, key=KEY_SENTINEL, _cache={}):
|
||||
"""Wrap an existing time zone object in a shim class.
|
||||
|
||||
This is likely to be useful if you would like to work internally with
|
||||
non-``pytz`` zones, but you expose an interface to callers relying on
|
||||
``pytz``'s interface. It may also be useful for passing non-``pytz`` zones
|
||||
to libraries expecting to use ``pytz``'s interface.
|
||||
|
||||
:param tz:
|
||||
A :pep:`495`-compatible time zone, such as those provided by
|
||||
:mod:`dateutil.tz` or :mod:`zoneinfo`.
|
||||
|
||||
:param key:
|
||||
The value for the IANA time zone key. This is optional for ``zoneinfo``
|
||||
zones, but required for ``dateutil.tz`` zones.
|
||||
|
||||
:return:
|
||||
A shim time zone.
|
||||
"""
|
||||
if key is KEY_SENTINEL:
|
||||
key = getattr(tz, "key", KEY_SENTINEL)
|
||||
|
||||
if key is KEY_SENTINEL:
|
||||
raise TypeError(
|
||||
"The `key` argument is required when wrapping zones that do not "
|
||||
+ "have a `key` attribute."
|
||||
)
|
||||
|
||||
instance = _cache.get((id(tz), key), None)
|
||||
if instance is None:
|
||||
instance = _cache.setdefault((id(tz), key), _PytzShimTimezone(tz, key))
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
class _PytzShimTimezone(tzinfo):
|
||||
# Add instance variables for _zone and _key because this will make error
|
||||
# reporting with partially-initialized _BasePytzShimTimezone objects
|
||||
# work better.
|
||||
_zone = None
|
||||
_key = None
|
||||
|
||||
def __init__(self, zone, key):
|
||||
self._key = key
|
||||
self._zone = zone
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self._zone.utcoffset(dt)
|
||||
|
||||
def dst(self, dt):
|
||||
return self._zone.dst(dt)
|
||||
|
||||
def tzname(self, dt):
|
||||
return self._zone.tzname(dt)
|
||||
|
||||
def fromutc(self, dt):
|
||||
# The default fromutc implementation only works if tzinfo is "self"
|
||||
dt_base = dt.replace(tzinfo=self._zone)
|
||||
dt_out = self._zone.fromutc(dt_base)
|
||||
|
||||
return dt_out.replace(tzinfo=self)
|
||||
|
||||
def __str__(self):
|
||||
if self._key is not None:
|
||||
return str(self._key)
|
||||
else:
|
||||
return repr(self)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%s, %s)" % (
|
||||
self.__class__.__name__,
|
||||
repr(self._zone),
|
||||
repr(self._key),
|
||||
)
|
||||
|
||||
def unwrap_shim(self):
|
||||
"""Returns the underlying class that the shim is a wrapper for.
|
||||
|
||||
This is a shim-specific method equivalent to
|
||||
:func:`pytz_deprecation_shim.helpers.upgrade_tzinfo`. It is provided as
|
||||
a method to allow end-users to upgrade shim timezones without requiring
|
||||
an explicit dependency on ``pytz_deprecation_shim``, e.g.:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if getattr(tz, "unwrap_shim", None) is None:
|
||||
tz = tz.unwrap_shim()
|
||||
"""
|
||||
return self._zone
|
||||
|
||||
@property
|
||||
def zone(self):
|
||||
warnings.warn(
|
||||
"The zone attribute is specific to pytz's interface; "
|
||||
+ "please migrate to a new time zone provider. "
|
||||
+ "For more details on how to do so, see %s"
|
||||
% PYTZ_MIGRATION_GUIDE_URL,
|
||||
PytzUsageWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
return self._key
|
||||
|
||||
def localize(self, dt, is_dst=IS_DST_SENTINEL):
|
||||
warnings.warn(
|
||||
"The localize method is no longer necessary, as this "
|
||||
+ "time zone supports the fold attribute (PEP 495). "
|
||||
+ "For more details on migrating to a PEP 495-compliant "
|
||||
+ "implementation, see %s" % PYTZ_MIGRATION_GUIDE_URL,
|
||||
PytzUsageWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
if dt.tzinfo is not None:
|
||||
raise ValueError("Not naive datetime (tzinfo is already set)")
|
||||
|
||||
dt_out = dt.replace(tzinfo=self)
|
||||
|
||||
if is_dst is IS_DST_SENTINEL:
|
||||
return dt_out
|
||||
|
||||
dt_ambiguous = _compat.is_ambiguous(dt_out)
|
||||
dt_imaginary = (
|
||||
_compat.is_imaginary(dt_out) if not dt_ambiguous else False
|
||||
)
|
||||
|
||||
if is_dst is None:
|
||||
if dt_imaginary:
|
||||
raise get_exception(
|
||||
NonExistentTimeError, dt.replace(tzinfo=None)
|
||||
)
|
||||
|
||||
if dt_ambiguous:
|
||||
raise get_exception(AmbiguousTimeError, dt.replace(tzinfo=None))
|
||||
|
||||
elif dt_ambiguous or dt_imaginary:
|
||||
# Start by normalizing the folds; dt_out may have fold=0 or fold=1,
|
||||
# but we need to know the DST offset on both sides anyway, so we
|
||||
# will get one datetime representing each side of the fold, then
|
||||
# decide which one we're going to return.
|
||||
if _compat.get_fold(dt_out):
|
||||
dt_enfolded = dt_out
|
||||
dt_out = _compat.enfold(dt_out, fold=0)
|
||||
else:
|
||||
dt_enfolded = _compat.enfold(dt_out, fold=1)
|
||||
|
||||
# Now we want to decide whether the fold=0 or fold=1 represents
|
||||
# what pytz would return for `is_dst=True`
|
||||
enfolded_dst = bool(dt_enfolded.dst())
|
||||
if bool(dt_out.dst()) == enfolded_dst:
|
||||
# If this is not a transition between standard time and
|
||||
# daylight saving time, pytz will consider the larger offset
|
||||
# the DST offset.
|
||||
enfolded_dst = dt_enfolded.utcoffset() > dt_out.utcoffset()
|
||||
|
||||
# The default we've established is that dt_out is fold=0; swap it
|
||||
# for the fold=1 datetime if is_dst == True and the enfolded side
|
||||
# is DST or if is_dst == False and the enfolded side is *not* DST.
|
||||
if is_dst == enfolded_dst:
|
||||
dt_out = dt_enfolded
|
||||
|
||||
return dt_out
|
||||
|
||||
def normalize(self, dt):
|
||||
warnings.warn(
|
||||
"The normalize method is no longer necessary, as this "
|
||||
+ "time zone supports the fold attribute (PEP 495). "
|
||||
+ "For more details on migrating to a PEP 495-compliant "
|
||||
+ "implementation, see %s" % PYTZ_MIGRATION_GUIDE_URL,
|
||||
PytzUsageWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
if dt.tzinfo is None:
|
||||
raise ValueError("Naive time - no tzinfo set")
|
||||
|
||||
if dt.tzinfo is self:
|
||||
return dt
|
||||
|
||||
return dt.astimezone(self)
|
||||
|
||||
def __copy__(self):
|
||||
return self
|
||||
|
||||
def __deepcopy__(self, memo=None):
|
||||
return self
|
||||
|
||||
def __reduce__(self):
|
||||
return wrap_zone, (self._zone, self._key)
|
||||
|
||||
|
||||
UTC = wrap_zone(_compat.UTC, "UTC")
|
||||
PYTZ_MIGRATION_GUIDE_URL = (
|
||||
"https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html"
|
||||
)
|
90
lib/pytz_deprecation_shim/helpers.py
Normal file
90
lib/pytz_deprecation_shim/helpers.py
Normal file
|
@ -0,0 +1,90 @@
|
|||
"""
|
||||
This module contains helper functions to ease the transition from ``pytz`` to
|
||||
another :pep:`495`-compatible library.
|
||||
"""
|
||||
from . import _common, _compat
|
||||
from ._impl import _PytzShimTimezone
|
||||
|
||||
_PYTZ_BASE_CLASSES = None
|
||||
|
||||
|
||||
def is_pytz_zone(tz):
|
||||
"""Check if a time zone is a ``pytz`` time zone.
|
||||
|
||||
This will only import ``pytz`` if it has already been imported, and does
|
||||
not rely on the existence of the ``localize`` or ``normalize`` methods
|
||||
(since the shim classes also have these methods, but are not ``pytz``
|
||||
zones).
|
||||
"""
|
||||
|
||||
# If pytz is not in sys.modules, then we will assume the time zone is not a
|
||||
# pytz zone. It is possible that someone has manipulated sys.modules to
|
||||
# remove pytz, but that's the kind of thing that causes all kinds of other
|
||||
# problems anyway, so we'll call that an unsupported configuration.
|
||||
if not _common.pytz_imported():
|
||||
return False
|
||||
|
||||
if _PYTZ_BASE_CLASSES is None:
|
||||
_populate_pytz_base_classes()
|
||||
|
||||
return isinstance(tz, _PYTZ_BASE_CLASSES)
|
||||
|
||||
|
||||
def upgrade_tzinfo(tz):
|
||||
"""Convert a ``pytz`` or shim timezone into its modern equivalent.
|
||||
|
||||
The shim classes are thin wrappers around :mod:`zoneinfo` or
|
||||
:mod:`dateutil.tz` implementations of the :class:`datetime.tzinfo` base
|
||||
class. This function removes the shim and returns the underlying "upgraded"
|
||||
time zone.
|
||||
|
||||
When passed a ``pytz`` zone (not a shim), this returns the non-``pytz``
|
||||
equivalent. This may fail if ``pytz`` is using a data source incompatible
|
||||
with the upgraded provider's data source, or if the ``pytz`` zone was built
|
||||
from a file rather than an IANA key.
|
||||
|
||||
When passed an object that is not a shim or a ``pytz`` zone, this returns
|
||||
the original object.
|
||||
|
||||
:param tz:
|
||||
A :class:`datetime.tzinfo` object.
|
||||
|
||||
:raises KeyError:
|
||||
If a ``pytz`` zone is passed to the function with no equivalent in the
|
||||
:pep:`495`-compatible library's version of the Olson database.
|
||||
|
||||
:return:
|
||||
A :pep:`495`-compatible equivalent of any ``pytz`` or shim
|
||||
class, or the original object.
|
||||
"""
|
||||
if isinstance(tz, _PytzShimTimezone):
|
||||
return tz._zone
|
||||
|
||||
if is_pytz_zone(tz):
|
||||
if tz.zone is None:
|
||||
# This is a fixed offset zone
|
||||
offset = tz.utcoffset(None)
|
||||
offset_minutes = offset.total_seconds() / 60
|
||||
|
||||
return _compat.get_fixed_offset_zone(offset_minutes)
|
||||
|
||||
if tz.zone == "UTC":
|
||||
return _compat.UTC
|
||||
|
||||
return _compat.get_timezone(tz.zone)
|
||||
|
||||
return tz
|
||||
|
||||
|
||||
def _populate_pytz_base_classes():
|
||||
import pytz
|
||||
from pytz.tzinfo import BaseTzInfo
|
||||
|
||||
base_classes = (BaseTzInfo, pytz._FixedOffset)
|
||||
|
||||
# In releases prior to 2018.4, pytz.UTC was not a subclass of BaseTzInfo
|
||||
if not isinstance(pytz.UTC, BaseTzInfo): # pragma: nocover
|
||||
base_classes = base_classes + (type(pytz.UTC),)
|
||||
|
||||
global _PYTZ_BASE_CLASSES
|
||||
_PYTZ_BASE_CLASSES = base_classes
|
Loading…
Add table
Add a link
Reference in a new issue