mirror of
https://gitlab.com/octtspacc/staticoso
synced 2025-04-17 19:37:22 +02:00
Add dependencies
This commit is contained in:
parent
477a217c57
commit
ec73b69eed
54
Source/Libs/dateutil/LICENSE
Normal file
54
Source/Libs/dateutil/LICENSE
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
Copyright 2017- Paul Ganssle <paul@ganssle.io>
|
||||||
|
Copyright 2017- dateutil contributors (see AUTHORS file)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
The above license applies to all contributions after 2017-12-01, as well as
|
||||||
|
all contributions that have been re-licensed (see AUTHORS file for the list of
|
||||||
|
contributors who have re-licensed their code).
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
dateutil - Extensions to the standard Python datetime module.
|
||||||
|
|
||||||
|
Copyright (c) 2003-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
Copyright (c) 2012-2014 - Tomi Pieviläinen <tomi.pievilainen@iki.fi>
|
||||||
|
Copyright (c) 2014-2016 - Yaron de Leeuw <me@jarondl.net>
|
||||||
|
Copyright (c) 2015- - Paul Ganssle <paul@ganssle.io>
|
||||||
|
Copyright (c) 2015- - dateutil contributors (see AUTHORS file)
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
The above BSD License Applies to all code, even that also covered by Apache 2.0.
|
8
Source/Libs/dateutil/__init__.py
Normal file
8
Source/Libs/dateutil/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
try:
|
||||||
|
from ._version import version as __version__
|
||||||
|
except ImportError:
|
||||||
|
__version__ = 'unknown'
|
||||||
|
|
||||||
|
__all__ = ['easter', 'parser', 'relativedelta', 'rrule', 'tz',
|
||||||
|
'utils', 'zoneinfo']
|
43
Source/Libs/dateutil/_common.py
Normal file
43
Source/Libs/dateutil/_common.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
Common code used in multiple modules.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class weekday(object):
|
||||||
|
__slots__ = ["weekday", "n"]
|
||||||
|
|
||||||
|
def __init__(self, weekday, n=None):
|
||||||
|
self.weekday = weekday
|
||||||
|
self.n = n
|
||||||
|
|
||||||
|
def __call__(self, n):
|
||||||
|
if n == self.n:
|
||||||
|
return self
|
||||||
|
else:
|
||||||
|
return self.__class__(self.weekday, n)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
try:
|
||||||
|
if self.weekday != other.weekday or self.n != other.n:
|
||||||
|
return False
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((
|
||||||
|
self.weekday,
|
||||||
|
self.n,
|
||||||
|
))
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not (self == other)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday]
|
||||||
|
if not self.n:
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return "%s(%+d)" % (s, self.n)
|
||||||
|
|
||||||
|
# vim:ts=4:sw=4:et
|
5
Source/Libs/dateutil/_version.py
Normal file
5
Source/Libs/dateutil/_version.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
# file generated by setuptools_scm
|
||||||
|
# don't change, don't track in version control
|
||||||
|
version = '2.8.2'
|
||||||
|
version_tuple = (2, 8, 2)
|
89
Source/Libs/dateutil/easter.py
Normal file
89
Source/Libs/dateutil/easter.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
This module offers a generic Easter computing method for any given year, using
|
||||||
|
Western, Orthodox or Julian algorithms.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"]
|
||||||
|
|
||||||
|
EASTER_JULIAN = 1
|
||||||
|
EASTER_ORTHODOX = 2
|
||||||
|
EASTER_WESTERN = 3
|
||||||
|
|
||||||
|
|
||||||
|
def easter(year, method=EASTER_WESTERN):
|
||||||
|
"""
|
||||||
|
This method was ported from the work done by GM Arts,
|
||||||
|
on top of the algorithm by Claus Tondering, which was
|
||||||
|
based in part on the algorithm of Ouding (1940), as
|
||||||
|
quoted in "Explanatory Supplement to the Astronomical
|
||||||
|
Almanac", P. Kenneth Seidelmann, editor.
|
||||||
|
|
||||||
|
This algorithm implements three different Easter
|
||||||
|
calculation methods:
|
||||||
|
|
||||||
|
1. Original calculation in Julian calendar, valid in
|
||||||
|
dates after 326 AD
|
||||||
|
2. Original method, with date converted to Gregorian
|
||||||
|
calendar, valid in years 1583 to 4099
|
||||||
|
3. Revised method, in Gregorian calendar, valid in
|
||||||
|
years 1583 to 4099 as well
|
||||||
|
|
||||||
|
These methods are represented by the constants:
|
||||||
|
|
||||||
|
* ``EASTER_JULIAN = 1``
|
||||||
|
* ``EASTER_ORTHODOX = 2``
|
||||||
|
* ``EASTER_WESTERN = 3``
|
||||||
|
|
||||||
|
The default method is method 3.
|
||||||
|
|
||||||
|
More about the algorithm may be found at:
|
||||||
|
|
||||||
|
`GM Arts: Easter Algorithms <http://www.gmarts.org/index.php?go=415>`_
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
`The Calendar FAQ: Easter <https://www.tondering.dk/claus/cal/easter.php>`_
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not (1 <= method <= 3):
|
||||||
|
raise ValueError("invalid method")
|
||||||
|
|
||||||
|
# g - Golden year - 1
|
||||||
|
# c - Century
|
||||||
|
# h - (23 - Epact) mod 30
|
||||||
|
# i - Number of days from March 21 to Paschal Full Moon
|
||||||
|
# j - Weekday for PFM (0=Sunday, etc)
|
||||||
|
# p - Number of days from March 21 to Sunday on or before PFM
|
||||||
|
# (-6 to 28 methods 1 & 3, to 56 for method 2)
|
||||||
|
# e - Extra days to add for method 2 (converting Julian
|
||||||
|
# date to Gregorian date)
|
||||||
|
|
||||||
|
y = year
|
||||||
|
g = y % 19
|
||||||
|
e = 0
|
||||||
|
if method < 3:
|
||||||
|
# Old method
|
||||||
|
i = (19*g + 15) % 30
|
||||||
|
j = (y + y//4 + i) % 7
|
||||||
|
if method == 2:
|
||||||
|
# Extra dates to convert Julian to Gregorian date
|
||||||
|
e = 10
|
||||||
|
if y > 1600:
|
||||||
|
e = e + y//100 - 16 - (y//100 - 16)//4
|
||||||
|
else:
|
||||||
|
# New method
|
||||||
|
c = y//100
|
||||||
|
h = (c - c//4 - (8*c + 13)//25 + 19*g + 15) % 30
|
||||||
|
i = h - (h//28)*(1 - (h//28)*(29//(h + 1))*((21 - g)//11))
|
||||||
|
j = (y + y//4 + i + 2 - c + c//4) % 7
|
||||||
|
|
||||||
|
# p can be from -6 to 56 corresponding to dates 22 March to 23 May
|
||||||
|
# (later dates apply to method 2, although 23 May never actually occurs)
|
||||||
|
p = i - j + e
|
||||||
|
d = 1 + (p + 27 + (p + 6)//40) % 31
|
||||||
|
m = 3 + (p + 26)//30
|
||||||
|
return datetime.date(int(y), int(m), int(d))
|
61
Source/Libs/dateutil/parser/__init__.py
Normal file
61
Source/Libs/dateutil/parser/__init__.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from ._parser import parse, parser, parserinfo, ParserError
|
||||||
|
from ._parser import DEFAULTPARSER, DEFAULTTZPARSER
|
||||||
|
from ._parser import UnknownTimezoneWarning
|
||||||
|
|
||||||
|
from ._parser import __doc__
|
||||||
|
|
||||||
|
from .isoparser import isoparser, isoparse
|
||||||
|
|
||||||
|
__all__ = ['parse', 'parser', 'parserinfo',
|
||||||
|
'isoparse', 'isoparser',
|
||||||
|
'ParserError',
|
||||||
|
'UnknownTimezoneWarning']
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# Deprecate portions of the private interface so that downstream code that
|
||||||
|
# is improperly relying on it is given *some* notice.
|
||||||
|
|
||||||
|
|
||||||
|
def __deprecated_private_func(f):
|
||||||
|
from functools import wraps
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
msg = ('{name} is a private function and may break without warning, '
|
||||||
|
'it will be moved and or renamed in future versions.')
|
||||||
|
msg = msg.format(name=f.__name__)
|
||||||
|
|
||||||
|
@wraps(f)
|
||||||
|
def deprecated_func(*args, **kwargs):
|
||||||
|
warnings.warn(msg, DeprecationWarning)
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
|
return deprecated_func
|
||||||
|
|
||||||
|
def __deprecate_private_class(c):
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
msg = ('{name} is a private class and may break without warning, '
|
||||||
|
'it will be moved and or renamed in future versions.')
|
||||||
|
msg = msg.format(name=c.__name__)
|
||||||
|
|
||||||
|
class private_class(c):
|
||||||
|
__doc__ = c.__doc__
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
warnings.warn(msg, DeprecationWarning)
|
||||||
|
super(private_class, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
private_class.__name__ = c.__name__
|
||||||
|
|
||||||
|
return private_class
|
||||||
|
|
||||||
|
|
||||||
|
from ._parser import _timelex, _resultbase
|
||||||
|
from ._parser import _tzparser, _parsetz
|
||||||
|
|
||||||
|
_timelex = __deprecate_private_class(_timelex)
|
||||||
|
_tzparser = __deprecate_private_class(_tzparser)
|
||||||
|
_resultbase = __deprecate_private_class(_resultbase)
|
||||||
|
_parsetz = __deprecated_private_func(_parsetz)
|
1613
Source/Libs/dateutil/parser/_parser.py
Normal file
1613
Source/Libs/dateutil/parser/_parser.py
Normal file
File diff suppressed because it is too large
Load Diff
416
Source/Libs/dateutil/parser/isoparser.py
Normal file
416
Source/Libs/dateutil/parser/isoparser.py
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
This module offers a parser for ISO-8601 strings
|
||||||
|
|
||||||
|
It is intended to support all valid date, time and datetime formats per the
|
||||||
|
ISO-8601 specification.
|
||||||
|
|
||||||
|
..versionadded:: 2.7.0
|
||||||
|
"""
|
||||||
|
from datetime import datetime, timedelta, time, date
|
||||||
|
import calendar
|
||||||
|
from dateutil import tz
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
import re
|
||||||
|
import six
|
||||||
|
|
||||||
|
__all__ = ["isoparse", "isoparser"]
|
||||||
|
|
||||||
|
|
||||||
|
def _takes_ascii(f):
|
||||||
|
@wraps(f)
|
||||||
|
def func(self, str_in, *args, **kwargs):
|
||||||
|
# If it's a stream, read the whole thing
|
||||||
|
str_in = getattr(str_in, 'read', lambda: str_in)()
|
||||||
|
|
||||||
|
# If it's unicode, turn it into bytes, since ISO-8601 only covers ASCII
|
||||||
|
if isinstance(str_in, six.text_type):
|
||||||
|
# ASCII is the same in UTF-8
|
||||||
|
try:
|
||||||
|
str_in = str_in.encode('ascii')
|
||||||
|
except UnicodeEncodeError as e:
|
||||||
|
msg = 'ISO-8601 strings should contain only ASCII characters'
|
||||||
|
six.raise_from(ValueError(msg), e)
|
||||||
|
|
||||||
|
return f(self, str_in, *args, **kwargs)
|
||||||
|
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
class isoparser(object):
|
||||||
|
def __init__(self, sep=None):
|
||||||
|
"""
|
||||||
|
:param sep:
|
||||||
|
A single character that separates date and time portions. If
|
||||||
|
``None``, the parser will accept any single character.
|
||||||
|
For strict ISO-8601 adherence, pass ``'T'``.
|
||||||
|
"""
|
||||||
|
if sep is not None:
|
||||||
|
if (len(sep) != 1 or ord(sep) >= 128 or sep in '0123456789'):
|
||||||
|
raise ValueError('Separator must be a single, non-numeric ' +
|
||||||
|
'ASCII character')
|
||||||
|
|
||||||
|
sep = sep.encode('ascii')
|
||||||
|
|
||||||
|
self._sep = sep
|
||||||
|
|
||||||
|
@_takes_ascii
|
||||||
|
def isoparse(self, dt_str):
|
||||||
|
"""
|
||||||
|
Parse an ISO-8601 datetime string into a :class:`datetime.datetime`.
|
||||||
|
|
||||||
|
An ISO-8601 datetime string consists of a date portion, followed
|
||||||
|
optionally by a time portion - the date and time portions are separated
|
||||||
|
by a single character separator, which is ``T`` in the official
|
||||||
|
standard. Incomplete date formats (such as ``YYYY-MM``) may *not* be
|
||||||
|
combined with a time portion.
|
||||||
|
|
||||||
|
Supported date formats are:
|
||||||
|
|
||||||
|
Common:
|
||||||
|
|
||||||
|
- ``YYYY``
|
||||||
|
- ``YYYY-MM`` or ``YYYYMM``
|
||||||
|
- ``YYYY-MM-DD`` or ``YYYYMMDD``
|
||||||
|
|
||||||
|
Uncommon:
|
||||||
|
|
||||||
|
- ``YYYY-Www`` or ``YYYYWww`` - ISO week (day defaults to 0)
|
||||||
|
- ``YYYY-Www-D`` or ``YYYYWwwD`` - ISO week and day
|
||||||
|
|
||||||
|
The ISO week and day numbering follows the same logic as
|
||||||
|
:func:`datetime.date.isocalendar`.
|
||||||
|
|
||||||
|
Supported time formats are:
|
||||||
|
|
||||||
|
- ``hh``
|
||||||
|
- ``hh:mm`` or ``hhmm``
|
||||||
|
- ``hh:mm:ss`` or ``hhmmss``
|
||||||
|
- ``hh:mm:ss.ssssss`` (Up to 6 sub-second digits)
|
||||||
|
|
||||||
|
Midnight is a special case for `hh`, as the standard supports both
|
||||||
|
00:00 and 24:00 as a representation. The decimal separator can be
|
||||||
|
either a dot or a comma.
|
||||||
|
|
||||||
|
|
||||||
|
.. caution::
|
||||||
|
|
||||||
|
Support for fractional components other than seconds is part of the
|
||||||
|
ISO-8601 standard, but is not currently implemented in this parser.
|
||||||
|
|
||||||
|
Supported time zone offset formats are:
|
||||||
|
|
||||||
|
- `Z` (UTC)
|
||||||
|
- `±HH:MM`
|
||||||
|
- `±HHMM`
|
||||||
|
- `±HH`
|
||||||
|
|
||||||
|
Offsets will be represented as :class:`dateutil.tz.tzoffset` objects,
|
||||||
|
with the exception of UTC, which will be represented as
|
||||||
|
:class:`dateutil.tz.tzutc`. Time zone offsets equivalent to UTC (such
|
||||||
|
as `+00:00`) will also be represented as :class:`dateutil.tz.tzutc`.
|
||||||
|
|
||||||
|
:param dt_str:
|
||||||
|
A string or stream containing only an ISO-8601 datetime string
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`datetime.datetime` representing the string.
|
||||||
|
Unspecified components default to their lowest value.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
As of version 2.7.0, the strictness of the parser should not be
|
||||||
|
considered a stable part of the contract. Any valid ISO-8601 string
|
||||||
|
that parses correctly with the default settings will continue to
|
||||||
|
parse correctly in future versions, but invalid strings that
|
||||||
|
currently fail (e.g. ``2017-01-01T00:00+00:00:00``) are not
|
||||||
|
guaranteed to continue failing in future versions if they encode
|
||||||
|
a valid date.
|
||||||
|
|
||||||
|
.. versionadded:: 2.7.0
|
||||||
|
"""
|
||||||
|
components, pos = self._parse_isodate(dt_str)
|
||||||
|
|
||||||
|
if len(dt_str) > pos:
|
||||||
|
if self._sep is None or dt_str[pos:pos + 1] == self._sep:
|
||||||
|
components += self._parse_isotime(dt_str[pos + 1:])
|
||||||
|
else:
|
||||||
|
raise ValueError('String contains unknown ISO components')
|
||||||
|
|
||||||
|
if len(components) > 3 and components[3] == 24:
|
||||||
|
components[3] = 0
|
||||||
|
return datetime(*components) + timedelta(days=1)
|
||||||
|
|
||||||
|
return datetime(*components)
|
||||||
|
|
||||||
|
@_takes_ascii
|
||||||
|
def parse_isodate(self, datestr):
|
||||||
|
"""
|
||||||
|
Parse the date portion of an ISO string.
|
||||||
|
|
||||||
|
:param datestr:
|
||||||
|
The string portion of an ISO string, without a separator
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`datetime.date` object
|
||||||
|
"""
|
||||||
|
components, pos = self._parse_isodate(datestr)
|
||||||
|
if pos < len(datestr):
|
||||||
|
raise ValueError('String contains unknown ISO ' +
|
||||||
|
'components: {!r}'.format(datestr.decode('ascii')))
|
||||||
|
return date(*components)
|
||||||
|
|
||||||
|
@_takes_ascii
|
||||||
|
def parse_isotime(self, timestr):
|
||||||
|
"""
|
||||||
|
Parse the time portion of an ISO string.
|
||||||
|
|
||||||
|
:param timestr:
|
||||||
|
The time portion of an ISO string, without a separator
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`datetime.time` object
|
||||||
|
"""
|
||||||
|
components = self._parse_isotime(timestr)
|
||||||
|
if components[0] == 24:
|
||||||
|
components[0] = 0
|
||||||
|
return time(*components)
|
||||||
|
|
||||||
|
@_takes_ascii
|
||||||
|
def parse_tzstr(self, tzstr, zero_as_utc=True):
|
||||||
|
"""
|
||||||
|
Parse a valid ISO time zone string.
|
||||||
|
|
||||||
|
See :func:`isoparser.isoparse` for details on supported formats.
|
||||||
|
|
||||||
|
:param tzstr:
|
||||||
|
A string representing an ISO time zone offset
|
||||||
|
|
||||||
|
:param zero_as_utc:
|
||||||
|
Whether to return :class:`dateutil.tz.tzutc` for zero-offset zones
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns :class:`dateutil.tz.tzoffset` for offsets and
|
||||||
|
:class:`dateutil.tz.tzutc` for ``Z`` and (if ``zero_as_utc`` is
|
||||||
|
specified) offsets equivalent to UTC.
|
||||||
|
"""
|
||||||
|
return self._parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
_DATE_SEP = b'-'
|
||||||
|
_TIME_SEP = b':'
|
||||||
|
_FRACTION_REGEX = re.compile(b'[\\.,]([0-9]+)')
|
||||||
|
|
||||||
|
def _parse_isodate(self, dt_str):
|
||||||
|
try:
|
||||||
|
return self._parse_isodate_common(dt_str)
|
||||||
|
except ValueError:
|
||||||
|
return self._parse_isodate_uncommon(dt_str)
|
||||||
|
|
||||||
|
def _parse_isodate_common(self, dt_str):
|
||||||
|
len_str = len(dt_str)
|
||||||
|
components = [1, 1, 1]
|
||||||
|
|
||||||
|
if len_str < 4:
|
||||||
|
raise ValueError('ISO string too short')
|
||||||
|
|
||||||
|
# Year
|
||||||
|
components[0] = int(dt_str[0:4])
|
||||||
|
pos = 4
|
||||||
|
if pos >= len_str:
|
||||||
|
return components, pos
|
||||||
|
|
||||||
|
has_sep = dt_str[pos:pos + 1] == self._DATE_SEP
|
||||||
|
if has_sep:
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
# Month
|
||||||
|
if len_str - pos < 2:
|
||||||
|
raise ValueError('Invalid common month')
|
||||||
|
|
||||||
|
components[1] = int(dt_str[pos:pos + 2])
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
if pos >= len_str:
|
||||||
|
if has_sep:
|
||||||
|
return components, pos
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid ISO format')
|
||||||
|
|
||||||
|
if has_sep:
|
||||||
|
if dt_str[pos:pos + 1] != self._DATE_SEP:
|
||||||
|
raise ValueError('Invalid separator in ISO string')
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
# Day
|
||||||
|
if len_str - pos < 2:
|
||||||
|
raise ValueError('Invalid common day')
|
||||||
|
components[2] = int(dt_str[pos:pos + 2])
|
||||||
|
return components, pos + 2
|
||||||
|
|
||||||
|
def _parse_isodate_uncommon(self, dt_str):
|
||||||
|
if len(dt_str) < 4:
|
||||||
|
raise ValueError('ISO string too short')
|
||||||
|
|
||||||
|
# All ISO formats start with the year
|
||||||
|
year = int(dt_str[0:4])
|
||||||
|
|
||||||
|
has_sep = dt_str[4:5] == self._DATE_SEP
|
||||||
|
|
||||||
|
pos = 4 + has_sep # Skip '-' if it's there
|
||||||
|
if dt_str[pos:pos + 1] == b'W':
|
||||||
|
# YYYY-?Www-?D?
|
||||||
|
pos += 1
|
||||||
|
weekno = int(dt_str[pos:pos + 2])
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
dayno = 1
|
||||||
|
if len(dt_str) > pos:
|
||||||
|
if (dt_str[pos:pos + 1] == self._DATE_SEP) != has_sep:
|
||||||
|
raise ValueError('Inconsistent use of dash separator')
|
||||||
|
|
||||||
|
pos += has_sep
|
||||||
|
|
||||||
|
dayno = int(dt_str[pos:pos + 1])
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
base_date = self._calculate_weekdate(year, weekno, dayno)
|
||||||
|
else:
|
||||||
|
# YYYYDDD or YYYY-DDD
|
||||||
|
if len(dt_str) - pos < 3:
|
||||||
|
raise ValueError('Invalid ordinal day')
|
||||||
|
|
||||||
|
ordinal_day = int(dt_str[pos:pos + 3])
|
||||||
|
pos += 3
|
||||||
|
|
||||||
|
if ordinal_day < 1 or ordinal_day > (365 + calendar.isleap(year)):
|
||||||
|
raise ValueError('Invalid ordinal day' +
|
||||||
|
' {} for year {}'.format(ordinal_day, year))
|
||||||
|
|
||||||
|
base_date = date(year, 1, 1) + timedelta(days=ordinal_day - 1)
|
||||||
|
|
||||||
|
components = [base_date.year, base_date.month, base_date.day]
|
||||||
|
return components, pos
|
||||||
|
|
||||||
|
def _calculate_weekdate(self, year, week, day):
|
||||||
|
"""
|
||||||
|
Calculate the day of corresponding to the ISO year-week-day calendar.
|
||||||
|
|
||||||
|
This function is effectively the inverse of
|
||||||
|
:func:`datetime.date.isocalendar`.
|
||||||
|
|
||||||
|
:param year:
|
||||||
|
The year in the ISO calendar
|
||||||
|
|
||||||
|
:param week:
|
||||||
|
The week in the ISO calendar - range is [1, 53]
|
||||||
|
|
||||||
|
:param day:
|
||||||
|
The day in the ISO calendar - range is [1 (MON), 7 (SUN)]
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`datetime.date`
|
||||||
|
"""
|
||||||
|
if not 0 < week < 54:
|
||||||
|
raise ValueError('Invalid week: {}'.format(week))
|
||||||
|
|
||||||
|
if not 0 < day < 8: # Range is 1-7
|
||||||
|
raise ValueError('Invalid weekday: {}'.format(day))
|
||||||
|
|
||||||
|
# Get week 1 for the specific year:
|
||||||
|
jan_4 = date(year, 1, 4) # Week 1 always has January 4th in it
|
||||||
|
week_1 = jan_4 - timedelta(days=jan_4.isocalendar()[2] - 1)
|
||||||
|
|
||||||
|
# Now add the specific number of weeks and days to get what we want
|
||||||
|
week_offset = (week - 1) * 7 + (day - 1)
|
||||||
|
return week_1 + timedelta(days=week_offset)
|
||||||
|
|
||||||
|
def _parse_isotime(self, timestr):
|
||||||
|
len_str = len(timestr)
|
||||||
|
components = [0, 0, 0, 0, None]
|
||||||
|
pos = 0
|
||||||
|
comp = -1
|
||||||
|
|
||||||
|
if len_str < 2:
|
||||||
|
raise ValueError('ISO time too short')
|
||||||
|
|
||||||
|
has_sep = False
|
||||||
|
|
||||||
|
while pos < len_str and comp < 5:
|
||||||
|
comp += 1
|
||||||
|
|
||||||
|
if timestr[pos:pos + 1] in b'-+Zz':
|
||||||
|
# Detect time zone boundary
|
||||||
|
components[-1] = self._parse_tzstr(timestr[pos:])
|
||||||
|
pos = len_str
|
||||||
|
break
|
||||||
|
|
||||||
|
if comp == 1 and timestr[pos:pos+1] == self._TIME_SEP:
|
||||||
|
has_sep = True
|
||||||
|
pos += 1
|
||||||
|
elif comp == 2 and has_sep:
|
||||||
|
if timestr[pos:pos+1] != self._TIME_SEP:
|
||||||
|
raise ValueError('Inconsistent use of colon separator')
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
if comp < 3:
|
||||||
|
# Hour, minute, second
|
||||||
|
components[comp] = int(timestr[pos:pos + 2])
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
if comp == 3:
|
||||||
|
# Fraction of a second
|
||||||
|
frac = self._FRACTION_REGEX.match(timestr[pos:])
|
||||||
|
if not frac:
|
||||||
|
continue
|
||||||
|
|
||||||
|
us_str = frac.group(1)[:6] # Truncate to microseconds
|
||||||
|
components[comp] = int(us_str) * 10**(6 - len(us_str))
|
||||||
|
pos += len(frac.group())
|
||||||
|
|
||||||
|
if pos < len_str:
|
||||||
|
raise ValueError('Unused components in ISO string')
|
||||||
|
|
||||||
|
if components[0] == 24:
|
||||||
|
# Standard supports 00:00 and 24:00 as representations of midnight
|
||||||
|
if any(component != 0 for component in components[1:4]):
|
||||||
|
raise ValueError('Hour may only be 24 at 24:00:00.000')
|
||||||
|
|
||||||
|
return components
|
||||||
|
|
||||||
|
def _parse_tzstr(self, tzstr, zero_as_utc=True):
|
||||||
|
if tzstr == b'Z' or tzstr == b'z':
|
||||||
|
return tz.UTC
|
||||||
|
|
||||||
|
if len(tzstr) not in {3, 5, 6}:
|
||||||
|
raise ValueError('Time zone offset must be 1, 3, 5 or 6 characters')
|
||||||
|
|
||||||
|
if tzstr[0:1] == b'-':
|
||||||
|
mult = -1
|
||||||
|
elif tzstr[0:1] == b'+':
|
||||||
|
mult = 1
|
||||||
|
else:
|
||||||
|
raise ValueError('Time zone offset requires sign')
|
||||||
|
|
||||||
|
hours = int(tzstr[1:3])
|
||||||
|
if len(tzstr) == 3:
|
||||||
|
minutes = 0
|
||||||
|
else:
|
||||||
|
minutes = int(tzstr[(4 if tzstr[3:4] == self._TIME_SEP else 3):])
|
||||||
|
|
||||||
|
if zero_as_utc and hours == 0 and minutes == 0:
|
||||||
|
return tz.UTC
|
||||||
|
else:
|
||||||
|
if minutes > 59:
|
||||||
|
raise ValueError('Invalid minutes in time zone offset')
|
||||||
|
|
||||||
|
if hours > 23:
|
||||||
|
raise ValueError('Invalid hours in time zone offset')
|
||||||
|
|
||||||
|
return tz.tzoffset(None, mult * (hours * 60 + minutes) * 60)
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_ISOPARSER = isoparser()
|
||||||
|
isoparse = DEFAULT_ISOPARSER.isoparse
|
599
Source/Libs/dateutil/relativedelta.py
Normal file
599
Source/Libs/dateutil/relativedelta.py
Normal file
@ -0,0 +1,599 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
|
import calendar
|
||||||
|
|
||||||
|
import operator
|
||||||
|
from math import copysign
|
||||||
|
|
||||||
|
from six import integer_types
|
||||||
|
from warnings import warn
|
||||||
|
|
||||||
|
from ._common import weekday
|
||||||
|
|
||||||
|
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple(weekday(x) for x in range(7))
|
||||||
|
|
||||||
|
__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
|
||||||
|
|
||||||
|
|
||||||
|
class relativedelta(object):
|
||||||
|
"""
|
||||||
|
The relativedelta type is designed to be applied to an existing datetime and
|
||||||
|
can replace specific components of that datetime, or represents an interval
|
||||||
|
of time.
|
||||||
|
|
||||||
|
It is based on the specification of the excellent work done by M.-A. Lemburg
|
||||||
|
in his
|
||||||
|
`mx.DateTime <https://www.egenix.com/products/python/mxBase/mxDateTime/>`_ extension.
|
||||||
|
However, notice that this type does *NOT* implement the same algorithm as
|
||||||
|
his work. Do *NOT* expect it to behave like mx.DateTime's counterpart.
|
||||||
|
|
||||||
|
There are two different ways to build a relativedelta instance. The
|
||||||
|
first one is passing it two date/datetime classes::
|
||||||
|
|
||||||
|
relativedelta(datetime1, datetime2)
|
||||||
|
|
||||||
|
The second one is passing it any number of the following keyword arguments::
|
||||||
|
|
||||||
|
relativedelta(arg1=x,arg2=y,arg3=z...)
|
||||||
|
|
||||||
|
year, month, day, hour, minute, second, microsecond:
|
||||||
|
Absolute information (argument is singular); adding or subtracting a
|
||||||
|
relativedelta with absolute information does not perform an arithmetic
|
||||||
|
operation, but rather REPLACES the corresponding value in the
|
||||||
|
original datetime with the value(s) in relativedelta.
|
||||||
|
|
||||||
|
years, months, weeks, days, hours, minutes, seconds, microseconds:
|
||||||
|
Relative information, may be negative (argument is plural); adding
|
||||||
|
or subtracting a relativedelta with relative information performs
|
||||||
|
the corresponding arithmetic operation on the original datetime value
|
||||||
|
with the information in the relativedelta.
|
||||||
|
|
||||||
|
weekday:
|
||||||
|
One of the weekday instances (MO, TU, etc) available in the
|
||||||
|
relativedelta module. These instances may receive a parameter N,
|
||||||
|
specifying the Nth weekday, which could be positive or negative
|
||||||
|
(like MO(+1) or MO(-2)). Not specifying it is the same as specifying
|
||||||
|
+1. You can also use an integer, where 0=MO. This argument is always
|
||||||
|
relative e.g. if the calculated date is already Monday, using MO(1)
|
||||||
|
or MO(-1) won't change the day. To effectively make it absolute, use
|
||||||
|
it in combination with the day argument (e.g. day=1, MO(1) for first
|
||||||
|
Monday of the month).
|
||||||
|
|
||||||
|
leapdays:
|
||||||
|
Will add given days to the date found, if year is a leap
|
||||||
|
year, and the date found is post 28 of february.
|
||||||
|
|
||||||
|
yearday, nlyearday:
|
||||||
|
Set the yearday or the non-leap year day (jump leap days).
|
||||||
|
These are converted to day/month/leapdays information.
|
||||||
|
|
||||||
|
There are relative and absolute forms of the keyword
|
||||||
|
arguments. The plural is relative, and the singular is
|
||||||
|
absolute. For each argument in the order below, the absolute form
|
||||||
|
is applied first (by setting each attribute to that value) and
|
||||||
|
then the relative form (by adding the value to the attribute).
|
||||||
|
|
||||||
|
The order of attributes considered when this relativedelta is
|
||||||
|
added to a datetime is:
|
||||||
|
|
||||||
|
1. Year
|
||||||
|
2. Month
|
||||||
|
3. Day
|
||||||
|
4. Hours
|
||||||
|
5. Minutes
|
||||||
|
6. Seconds
|
||||||
|
7. Microseconds
|
||||||
|
|
||||||
|
Finally, weekday is applied, using the rule described above.
|
||||||
|
|
||||||
|
For example
|
||||||
|
|
||||||
|
>>> from datetime import datetime
|
||||||
|
>>> from dateutil.relativedelta import relativedelta, MO
|
||||||
|
>>> dt = datetime(2018, 4, 9, 13, 37, 0)
|
||||||
|
>>> delta = relativedelta(hours=25, day=1, weekday=MO(1))
|
||||||
|
>>> dt + delta
|
||||||
|
datetime.datetime(2018, 4, 2, 14, 37)
|
||||||
|
|
||||||
|
First, the day is set to 1 (the first of the month), then 25 hours
|
||||||
|
are added, to get to the 2nd day and 14th hour, finally the
|
||||||
|
weekday is applied, but since the 2nd is already a Monday there is
|
||||||
|
no effect.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, dt1=None, dt2=None,
|
||||||
|
years=0, months=0, days=0, leapdays=0, weeks=0,
|
||||||
|
hours=0, minutes=0, seconds=0, microseconds=0,
|
||||||
|
year=None, month=None, day=None, weekday=None,
|
||||||
|
yearday=None, nlyearday=None,
|
||||||
|
hour=None, minute=None, second=None, microsecond=None):
|
||||||
|
|
||||||
|
if dt1 and dt2:
|
||||||
|
# datetime is a subclass of date. So both must be date
|
||||||
|
if not (isinstance(dt1, datetime.date) and
|
||||||
|
isinstance(dt2, datetime.date)):
|
||||||
|
raise TypeError("relativedelta only diffs datetime/date")
|
||||||
|
|
||||||
|
# We allow two dates, or two datetimes, so we coerce them to be
|
||||||
|
# of the same type
|
||||||
|
if (isinstance(dt1, datetime.datetime) !=
|
||||||
|
isinstance(dt2, datetime.datetime)):
|
||||||
|
if not isinstance(dt1, datetime.datetime):
|
||||||
|
dt1 = datetime.datetime.fromordinal(dt1.toordinal())
|
||||||
|
elif not isinstance(dt2, datetime.datetime):
|
||||||
|
dt2 = datetime.datetime.fromordinal(dt2.toordinal())
|
||||||
|
|
||||||
|
self.years = 0
|
||||||
|
self.months = 0
|
||||||
|
self.days = 0
|
||||||
|
self.leapdays = 0
|
||||||
|
self.hours = 0
|
||||||
|
self.minutes = 0
|
||||||
|
self.seconds = 0
|
||||||
|
self.microseconds = 0
|
||||||
|
self.year = None
|
||||||
|
self.month = None
|
||||||
|
self.day = None
|
||||||
|
self.weekday = None
|
||||||
|
self.hour = None
|
||||||
|
self.minute = None
|
||||||
|
self.second = None
|
||||||
|
self.microsecond = None
|
||||||
|
self._has_time = 0
|
||||||
|
|
||||||
|
# Get year / month delta between the two
|
||||||
|
months = (dt1.year - dt2.year) * 12 + (dt1.month - dt2.month)
|
||||||
|
self._set_months(months)
|
||||||
|
|
||||||
|
# Remove the year/month delta so the timedelta is just well-defined
|
||||||
|
# time units (seconds, days and microseconds)
|
||||||
|
dtm = self.__radd__(dt2)
|
||||||
|
|
||||||
|
# If we've overshot our target, make an adjustment
|
||||||
|
if dt1 < dt2:
|
||||||
|
compare = operator.gt
|
||||||
|
increment = 1
|
||||||
|
else:
|
||||||
|
compare = operator.lt
|
||||||
|
increment = -1
|
||||||
|
|
||||||
|
while compare(dt1, dtm):
|
||||||
|
months += increment
|
||||||
|
self._set_months(months)
|
||||||
|
dtm = self.__radd__(dt2)
|
||||||
|
|
||||||
|
# Get the timedelta between the "months-adjusted" date and dt1
|
||||||
|
delta = dt1 - dtm
|
||||||
|
self.seconds = delta.seconds + delta.days * 86400
|
||||||
|
self.microseconds = delta.microseconds
|
||||||
|
else:
|
||||||
|
# Check for non-integer values in integer-only quantities
|
||||||
|
if any(x is not None and x != int(x) for x in (years, months)):
|
||||||
|
raise ValueError("Non-integer years and months are "
|
||||||
|
"ambiguous and not currently supported.")
|
||||||
|
|
||||||
|
# Relative information
|
||||||
|
self.years = int(years)
|
||||||
|
self.months = int(months)
|
||||||
|
self.days = days + weeks * 7
|
||||||
|
self.leapdays = leapdays
|
||||||
|
self.hours = hours
|
||||||
|
self.minutes = minutes
|
||||||
|
self.seconds = seconds
|
||||||
|
self.microseconds = microseconds
|
||||||
|
|
||||||
|
# Absolute information
|
||||||
|
self.year = year
|
||||||
|
self.month = month
|
||||||
|
self.day = day
|
||||||
|
self.hour = hour
|
||||||
|
self.minute = minute
|
||||||
|
self.second = second
|
||||||
|
self.microsecond = microsecond
|
||||||
|
|
||||||
|
if any(x is not None and int(x) != x
|
||||||
|
for x in (year, month, day, hour,
|
||||||
|
minute, second, microsecond)):
|
||||||
|
# For now we'll deprecate floats - later it'll be an error.
|
||||||
|
warn("Non-integer value passed as absolute information. " +
|
||||||
|
"This is not a well-defined condition and will raise " +
|
||||||
|
"errors in future versions.", DeprecationWarning)
|
||||||
|
|
||||||
|
if isinstance(weekday, integer_types):
|
||||||
|
self.weekday = weekdays[weekday]
|
||||||
|
else:
|
||||||
|
self.weekday = weekday
|
||||||
|
|
||||||
|
yday = 0
|
||||||
|
if nlyearday:
|
||||||
|
yday = nlyearday
|
||||||
|
elif yearday:
|
||||||
|
yday = yearday
|
||||||
|
if yearday > 59:
|
||||||
|
self.leapdays = -1
|
||||||
|
if yday:
|
||||||
|
ydayidx = [31, 59, 90, 120, 151, 181, 212,
|
||||||
|
243, 273, 304, 334, 366]
|
||||||
|
for idx, ydays in enumerate(ydayidx):
|
||||||
|
if yday <= ydays:
|
||||||
|
self.month = idx+1
|
||||||
|
if idx == 0:
|
||||||
|
self.day = yday
|
||||||
|
else:
|
||||||
|
self.day = yday-ydayidx[idx-1]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("invalid year day (%d)" % yday)
|
||||||
|
|
||||||
|
self._fix()
|
||||||
|
|
||||||
|
def _fix(self):
|
||||||
|
if abs(self.microseconds) > 999999:
|
||||||
|
s = _sign(self.microseconds)
|
||||||
|
div, mod = divmod(self.microseconds * s, 1000000)
|
||||||
|
self.microseconds = mod * s
|
||||||
|
self.seconds += div * s
|
||||||
|
if abs(self.seconds) > 59:
|
||||||
|
s = _sign(self.seconds)
|
||||||
|
div, mod = divmod(self.seconds * s, 60)
|
||||||
|
self.seconds = mod * s
|
||||||
|
self.minutes += div * s
|
||||||
|
if abs(self.minutes) > 59:
|
||||||
|
s = _sign(self.minutes)
|
||||||
|
div, mod = divmod(self.minutes * s, 60)
|
||||||
|
self.minutes = mod * s
|
||||||
|
self.hours += div * s
|
||||||
|
if abs(self.hours) > 23:
|
||||||
|
s = _sign(self.hours)
|
||||||
|
div, mod = divmod(self.hours * s, 24)
|
||||||
|
self.hours = mod * s
|
||||||
|
self.days += div * s
|
||||||
|
if abs(self.months) > 11:
|
||||||
|
s = _sign(self.months)
|
||||||
|
div, mod = divmod(self.months * s, 12)
|
||||||
|
self.months = mod * s
|
||||||
|
self.years += div * s
|
||||||
|
if (self.hours or self.minutes or self.seconds or self.microseconds
|
||||||
|
or self.hour is not None or self.minute is not None or
|
||||||
|
self.second is not None or self.microsecond is not None):
|
||||||
|
self._has_time = 1
|
||||||
|
else:
|
||||||
|
self._has_time = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def weeks(self):
|
||||||
|
return int(self.days / 7.0)
|
||||||
|
|
||||||
|
@weeks.setter
|
||||||
|
def weeks(self, value):
|
||||||
|
self.days = self.days - (self.weeks * 7) + value * 7
|
||||||
|
|
||||||
|
def _set_months(self, months):
|
||||||
|
self.months = months
|
||||||
|
if abs(self.months) > 11:
|
||||||
|
s = _sign(self.months)
|
||||||
|
div, mod = divmod(self.months * s, 12)
|
||||||
|
self.months = mod * s
|
||||||
|
self.years = div * s
|
||||||
|
else:
|
||||||
|
self.years = 0
|
||||||
|
|
||||||
|
def normalized(self):
|
||||||
|
"""
|
||||||
|
Return a version of this object represented entirely using integer
|
||||||
|
values for the relative attributes.
|
||||||
|
|
||||||
|
>>> relativedelta(days=1.5, hours=2).normalized()
|
||||||
|
relativedelta(days=+1, hours=+14)
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`dateutil.relativedelta.relativedelta` object.
|
||||||
|
"""
|
||||||
|
# Cascade remainders down (rounding each to roughly nearest microsecond)
|
||||||
|
days = int(self.days)
|
||||||
|
|
||||||
|
hours_f = round(self.hours + 24 * (self.days - days), 11)
|
||||||
|
hours = int(hours_f)
|
||||||
|
|
||||||
|
minutes_f = round(self.minutes + 60 * (hours_f - hours), 10)
|
||||||
|
minutes = int(minutes_f)
|
||||||
|
|
||||||
|
seconds_f = round(self.seconds + 60 * (minutes_f - minutes), 8)
|
||||||
|
seconds = int(seconds_f)
|
||||||
|
|
||||||
|
microseconds = round(self.microseconds + 1e6 * (seconds_f - seconds))
|
||||||
|
|
||||||
|
# Constructor carries overflow back up with call to _fix()
|
||||||
|
return self.__class__(years=self.years, months=self.months,
|
||||||
|
days=days, hours=hours, minutes=minutes,
|
||||||
|
seconds=seconds, microseconds=microseconds,
|
||||||
|
leapdays=self.leapdays, year=self.year,
|
||||||
|
month=self.month, day=self.day,
|
||||||
|
weekday=self.weekday, hour=self.hour,
|
||||||
|
minute=self.minute, second=self.second,
|
||||||
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
if isinstance(other, relativedelta):
|
||||||
|
return self.__class__(years=other.years + self.years,
|
||||||
|
months=other.months + self.months,
|
||||||
|
days=other.days + self.days,
|
||||||
|
hours=other.hours + self.hours,
|
||||||
|
minutes=other.minutes + self.minutes,
|
||||||
|
seconds=other.seconds + self.seconds,
|
||||||
|
microseconds=(other.microseconds +
|
||||||
|
self.microseconds),
|
||||||
|
leapdays=other.leapdays or self.leapdays,
|
||||||
|
year=(other.year if other.year is not None
|
||||||
|
else self.year),
|
||||||
|
month=(other.month if other.month is not None
|
||||||
|
else self.month),
|
||||||
|
day=(other.day if other.day is not None
|
||||||
|
else self.day),
|
||||||
|
weekday=(other.weekday if other.weekday is not None
|
||||||
|
else self.weekday),
|
||||||
|
hour=(other.hour if other.hour is not None
|
||||||
|
else self.hour),
|
||||||
|
minute=(other.minute if other.minute is not None
|
||||||
|
else self.minute),
|
||||||
|
second=(other.second if other.second is not None
|
||||||
|
else self.second),
|
||||||
|
microsecond=(other.microsecond if other.microsecond
|
||||||
|
is not None else
|
||||||
|
self.microsecond))
|
||||||
|
if isinstance(other, datetime.timedelta):
|
||||||
|
return self.__class__(years=self.years,
|
||||||
|
months=self.months,
|
||||||
|
days=self.days + other.days,
|
||||||
|
hours=self.hours,
|
||||||
|
minutes=self.minutes,
|
||||||
|
seconds=self.seconds + other.seconds,
|
||||||
|
microseconds=self.microseconds + other.microseconds,
|
||||||
|
leapdays=self.leapdays,
|
||||||
|
year=self.year,
|
||||||
|
month=self.month,
|
||||||
|
day=self.day,
|
||||||
|
weekday=self.weekday,
|
||||||
|
hour=self.hour,
|
||||||
|
minute=self.minute,
|
||||||
|
second=self.second,
|
||||||
|
microsecond=self.microsecond)
|
||||||
|
if not isinstance(other, datetime.date):
|
||||||
|
return NotImplemented
|
||||||
|
elif self._has_time and not isinstance(other, datetime.datetime):
|
||||||
|
other = datetime.datetime.fromordinal(other.toordinal())
|
||||||
|
year = (self.year or other.year)+self.years
|
||||||
|
month = self.month or other.month
|
||||||
|
if self.months:
|
||||||
|
assert 1 <= abs(self.months) <= 12
|
||||||
|
month += self.months
|
||||||
|
if month > 12:
|
||||||
|
year += 1
|
||||||
|
month -= 12
|
||||||
|
elif month < 1:
|
||||||
|
year -= 1
|
||||||
|
month += 12
|
||||||
|
day = min(calendar.monthrange(year, month)[1],
|
||||||
|
self.day or other.day)
|
||||||
|
repl = {"year": year, "month": month, "day": day}
|
||||||
|
for attr in ["hour", "minute", "second", "microsecond"]:
|
||||||
|
value = getattr(self, attr)
|
||||||
|
if value is not None:
|
||||||
|
repl[attr] = value
|
||||||
|
days = self.days
|
||||||
|
if self.leapdays and month > 2 and calendar.isleap(year):
|
||||||
|
days += self.leapdays
|
||||||
|
ret = (other.replace(**repl)
|
||||||
|
+ datetime.timedelta(days=days,
|
||||||
|
hours=self.hours,
|
||||||
|
minutes=self.minutes,
|
||||||
|
seconds=self.seconds,
|
||||||
|
microseconds=self.microseconds))
|
||||||
|
if self.weekday:
|
||||||
|
weekday, nth = self.weekday.weekday, self.weekday.n or 1
|
||||||
|
jumpdays = (abs(nth) - 1) * 7
|
||||||
|
if nth > 0:
|
||||||
|
jumpdays += (7 - ret.weekday() + weekday) % 7
|
||||||
|
else:
|
||||||
|
jumpdays += (ret.weekday() - weekday) % 7
|
||||||
|
jumpdays *= -1
|
||||||
|
ret += datetime.timedelta(days=jumpdays)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
return self.__add__(other)
|
||||||
|
|
||||||
|
def __rsub__(self, other):
|
||||||
|
return self.__neg__().__radd__(other)
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
if not isinstance(other, relativedelta):
|
||||||
|
return NotImplemented # In case the other object defines __rsub__
|
||||||
|
return self.__class__(years=self.years - other.years,
|
||||||
|
months=self.months - other.months,
|
||||||
|
days=self.days - other.days,
|
||||||
|
hours=self.hours - other.hours,
|
||||||
|
minutes=self.minutes - other.minutes,
|
||||||
|
seconds=self.seconds - other.seconds,
|
||||||
|
microseconds=self.microseconds - other.microseconds,
|
||||||
|
leapdays=self.leapdays or other.leapdays,
|
||||||
|
year=(self.year if self.year is not None
|
||||||
|
else other.year),
|
||||||
|
month=(self.month if self.month is not None else
|
||||||
|
other.month),
|
||||||
|
day=(self.day if self.day is not None else
|
||||||
|
other.day),
|
||||||
|
weekday=(self.weekday if self.weekday is not None else
|
||||||
|
other.weekday),
|
||||||
|
hour=(self.hour if self.hour is not None else
|
||||||
|
other.hour),
|
||||||
|
minute=(self.minute if self.minute is not None else
|
||||||
|
other.minute),
|
||||||
|
second=(self.second if self.second is not None else
|
||||||
|
other.second),
|
||||||
|
microsecond=(self.microsecond if self.microsecond
|
||||||
|
is not None else
|
||||||
|
other.microsecond))
|
||||||
|
|
||||||
|
def __abs__(self):
|
||||||
|
return self.__class__(years=abs(self.years),
|
||||||
|
months=abs(self.months),
|
||||||
|
days=abs(self.days),
|
||||||
|
hours=abs(self.hours),
|
||||||
|
minutes=abs(self.minutes),
|
||||||
|
seconds=abs(self.seconds),
|
||||||
|
microseconds=abs(self.microseconds),
|
||||||
|
leapdays=self.leapdays,
|
||||||
|
year=self.year,
|
||||||
|
month=self.month,
|
||||||
|
day=self.day,
|
||||||
|
weekday=self.weekday,
|
||||||
|
hour=self.hour,
|
||||||
|
minute=self.minute,
|
||||||
|
second=self.second,
|
||||||
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
return self.__class__(years=-self.years,
|
||||||
|
months=-self.months,
|
||||||
|
days=-self.days,
|
||||||
|
hours=-self.hours,
|
||||||
|
minutes=-self.minutes,
|
||||||
|
seconds=-self.seconds,
|
||||||
|
microseconds=-self.microseconds,
|
||||||
|
leapdays=self.leapdays,
|
||||||
|
year=self.year,
|
||||||
|
month=self.month,
|
||||||
|
day=self.day,
|
||||||
|
weekday=self.weekday,
|
||||||
|
hour=self.hour,
|
||||||
|
minute=self.minute,
|
||||||
|
second=self.second,
|
||||||
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
return not (not self.years and
|
||||||
|
not self.months and
|
||||||
|
not self.days and
|
||||||
|
not self.hours and
|
||||||
|
not self.minutes and
|
||||||
|
not self.seconds and
|
||||||
|
not self.microseconds and
|
||||||
|
not self.leapdays and
|
||||||
|
self.year is None and
|
||||||
|
self.month is None and
|
||||||
|
self.day is None and
|
||||||
|
self.weekday is None and
|
||||||
|
self.hour is None and
|
||||||
|
self.minute is None and
|
||||||
|
self.second is None and
|
||||||
|
self.microsecond is None)
|
||||||
|
# Compatibility with Python 2.x
|
||||||
|
__nonzero__ = __bool__
|
||||||
|
|
||||||
|
def __mul__(self, other):
|
||||||
|
try:
|
||||||
|
f = float(other)
|
||||||
|
except TypeError:
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return self.__class__(years=int(self.years * f),
|
||||||
|
months=int(self.months * f),
|
||||||
|
days=int(self.days * f),
|
||||||
|
hours=int(self.hours * f),
|
||||||
|
minutes=int(self.minutes * f),
|
||||||
|
seconds=int(self.seconds * f),
|
||||||
|
microseconds=int(self.microseconds * f),
|
||||||
|
leapdays=self.leapdays,
|
||||||
|
year=self.year,
|
||||||
|
month=self.month,
|
||||||
|
day=self.day,
|
||||||
|
weekday=self.weekday,
|
||||||
|
hour=self.hour,
|
||||||
|
minute=self.minute,
|
||||||
|
second=self.second,
|
||||||
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
|
__rmul__ = __mul__
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, relativedelta):
|
||||||
|
return NotImplemented
|
||||||
|
if self.weekday or other.weekday:
|
||||||
|
if not self.weekday or not other.weekday:
|
||||||
|
return False
|
||||||
|
if self.weekday.weekday != other.weekday.weekday:
|
||||||
|
return False
|
||||||
|
n1, n2 = self.weekday.n, other.weekday.n
|
||||||
|
if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)):
|
||||||
|
return False
|
||||||
|
return (self.years == other.years and
|
||||||
|
self.months == other.months and
|
||||||
|
self.days == other.days and
|
||||||
|
self.hours == other.hours and
|
||||||
|
self.minutes == other.minutes and
|
||||||
|
self.seconds == other.seconds and
|
||||||
|
self.microseconds == other.microseconds and
|
||||||
|
self.leapdays == other.leapdays and
|
||||||
|
self.year == other.year and
|
||||||
|
self.month == other.month and
|
||||||
|
self.day == other.day and
|
||||||
|
self.hour == other.hour and
|
||||||
|
self.minute == other.minute and
|
||||||
|
self.second == other.second and
|
||||||
|
self.microsecond == other.microsecond)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((
|
||||||
|
self.weekday,
|
||||||
|
self.years,
|
||||||
|
self.months,
|
||||||
|
self.days,
|
||||||
|
self.hours,
|
||||||
|
self.minutes,
|
||||||
|
self.seconds,
|
||||||
|
self.microseconds,
|
||||||
|
self.leapdays,
|
||||||
|
self.year,
|
||||||
|
self.month,
|
||||||
|
self.day,
|
||||||
|
self.hour,
|
||||||
|
self.minute,
|
||||||
|
self.second,
|
||||||
|
self.microsecond,
|
||||||
|
))
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
def __div__(self, other):
|
||||||
|
try:
|
||||||
|
reciprocal = 1 / float(other)
|
||||||
|
except TypeError:
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return self.__mul__(reciprocal)
|
||||||
|
|
||||||
|
__truediv__ = __div__
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
l = []
|
||||||
|
for attr in ["years", "months", "days", "leapdays",
|
||||||
|
"hours", "minutes", "seconds", "microseconds"]:
|
||||||
|
value = getattr(self, attr)
|
||||||
|
if value:
|
||||||
|
l.append("{attr}={value:+g}".format(attr=attr, value=value))
|
||||||
|
for attr in ["year", "month", "day", "weekday",
|
||||||
|
"hour", "minute", "second", "microsecond"]:
|
||||||
|
value = getattr(self, attr)
|
||||||
|
if value is not None:
|
||||||
|
l.append("{attr}={value}".format(attr=attr, value=repr(value)))
|
||||||
|
return "{classname}({attrs})".format(classname=self.__class__.__name__,
|
||||||
|
attrs=", ".join(l))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign(x):
|
||||||
|
return int(copysign(1, x))
|
||||||
|
|
||||||
|
# vim:ts=4:sw=4:et
|
1737
Source/Libs/dateutil/rrule.py
Normal file
1737
Source/Libs/dateutil/rrule.py
Normal file
File diff suppressed because it is too large
Load Diff
12
Source/Libs/dateutil/tz/__init__.py
Normal file
12
Source/Libs/dateutil/tz/__init__.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from .tz import *
|
||||||
|
from .tz import __doc__
|
||||||
|
|
||||||
|
__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
|
||||||
|
"tzstr", "tzical", "tzwin", "tzwinlocal", "gettz",
|
||||||
|
"enfold", "datetime_ambiguous", "datetime_exists",
|
||||||
|
"resolve_imaginary", "UTC", "DeprecatedTzFormatWarning"]
|
||||||
|
|
||||||
|
|
||||||
|
class DeprecatedTzFormatWarning(Warning):
|
||||||
|
"""Warning raised when time zones are parsed from deprecated formats."""
|
419
Source/Libs/dateutil/tz/_common.py
Normal file
419
Source/Libs/dateutil/tz/_common.py
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
from six import PY2
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta, tzinfo
|
||||||
|
|
||||||
|
|
||||||
|
ZERO = timedelta(0)
|
||||||
|
|
||||||
|
__all__ = ['tzname_in_python2', 'enfold']
|
||||||
|
|
||||||
|
|
||||||
|
def tzname_in_python2(namefunc):
|
||||||
|
"""Change unicode output into bytestrings in Python 2
|
||||||
|
|
||||||
|
tzname() API changed in Python 3. It used to return bytes, but was changed
|
||||||
|
to unicode strings
|
||||||
|
"""
|
||||||
|
if PY2:
|
||||||
|
@wraps(namefunc)
|
||||||
|
def adjust_encoding(*args, **kwargs):
|
||||||
|
name = namefunc(*args, **kwargs)
|
||||||
|
if name is not None:
|
||||||
|
name = name.encode()
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
|
return adjust_encoding
|
||||||
|
else:
|
||||||
|
return namefunc
|
||||||
|
|
||||||
|
|
||||||
|
# The following is adapted from Alexander Belopolsky's tz library
|
||||||
|
# https://github.com/abalkin/tz
|
||||||
|
if hasattr(datetime, 'fold'):
|
||||||
|
# This is the pre-python 3.6 fold situation
|
||||||
|
def enfold(dt, fold=1):
|
||||||
|
"""
|
||||||
|
Provides a unified interface for assigning the ``fold`` attribute to
|
||||||
|
datetimes both before and after the implementation of PEP-495.
|
||||||
|
|
||||||
|
:param fold:
|
||||||
|
The value for the ``fold`` attribute in the returned datetime. This
|
||||||
|
should be either 0 or 1.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns an object for which ``getattr(dt, 'fold', 0)`` returns
|
||||||
|
``fold`` for all versions of Python. In versions prior to
|
||||||
|
Python 3.6, this is a ``_DatetimeWithFold`` object, which is a
|
||||||
|
subclass of :py:class:`datetime.datetime` with the ``fold``
|
||||||
|
attribute added, if ``fold`` is 1.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6.0
|
||||||
|
"""
|
||||||
|
return dt.replace(fold=fold)
|
||||||
|
|
||||||
|
else:
|
||||||
|
class _DatetimeWithFold(datetime):
|
||||||
|
"""
|
||||||
|
This is a class designed to provide a PEP 495-compliant interface for
|
||||||
|
Python versions before 3.6. It is used only for dates in a fold, so
|
||||||
|
the ``fold`` attribute is fixed at ``1``.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6.0
|
||||||
|
"""
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def replace(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Return a datetime with the same attributes, except for those
|
||||||
|
attributes given new values by whichever keyword arguments are
|
||||||
|
specified. Note that tzinfo=None can be specified to create a naive
|
||||||
|
datetime from an aware datetime with no conversion of date and time
|
||||||
|
data.
|
||||||
|
|
||||||
|
This is reimplemented in ``_DatetimeWithFold`` because pypy3 will
|
||||||
|
return a ``datetime.datetime`` even if ``fold`` is unchanged.
|
||||||
|
"""
|
||||||
|
argnames = (
|
||||||
|
'year', 'month', 'day', 'hour', 'minute', 'second',
|
||||||
|
'microsecond', 'tzinfo'
|
||||||
|
)
|
||||||
|
|
||||||
|
for arg, argname in zip(args, argnames):
|
||||||
|
if argname in kwargs:
|
||||||
|
raise TypeError('Duplicate argument: {}'.format(argname))
|
||||||
|
|
||||||
|
kwargs[argname] = arg
|
||||||
|
|
||||||
|
for argname in argnames:
|
||||||
|
if argname not in kwargs:
|
||||||
|
kwargs[argname] = getattr(self, argname)
|
||||||
|
|
||||||
|
dt_class = self.__class__ if kwargs.get('fold', 1) else datetime
|
||||||
|
|
||||||
|
return dt_class(**kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fold(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def enfold(dt, fold=1):
|
||||||
|
"""
|
||||||
|
Provides a unified interface for assigning the ``fold`` attribute to
|
||||||
|
datetimes both before and after the implementation of PEP-495.
|
||||||
|
|
||||||
|
:param fold:
|
||||||
|
The value for the ``fold`` attribute in the returned datetime. This
|
||||||
|
should be either 0 or 1.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns an object for which ``getattr(dt, 'fold', 0)`` returns
|
||||||
|
``fold`` for all versions of Python. In versions prior to
|
||||||
|
Python 3.6, this is a ``_DatetimeWithFold`` object, which is a
|
||||||
|
subclass of :py:class:`datetime.datetime` with the ``fold``
|
||||||
|
attribute added, if ``fold`` is 1.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6.0
|
||||||
|
"""
|
||||||
|
if getattr(dt, 'fold', 0) == fold:
|
||||||
|
return dt
|
||||||
|
|
||||||
|
args = dt.timetuple()[:6]
|
||||||
|
args += (dt.microsecond, dt.tzinfo)
|
||||||
|
|
||||||
|
if fold:
|
||||||
|
return _DatetimeWithFold(*args)
|
||||||
|
else:
|
||||||
|
return datetime(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_fromutc_inputs(f):
|
||||||
|
"""
|
||||||
|
The CPython version of ``fromutc`` checks that the input is a ``datetime``
|
||||||
|
object and that ``self`` is attached as its ``tzinfo``.
|
||||||
|
"""
|
||||||
|
@wraps(f)
|
||||||
|
def fromutc(self, dt):
|
||||||
|
if not isinstance(dt, datetime):
|
||||||
|
raise TypeError("fromutc() requires a datetime argument")
|
||||||
|
if dt.tzinfo is not self:
|
||||||
|
raise ValueError("dt.tzinfo is not self")
|
||||||
|
|
||||||
|
return f(self, dt)
|
||||||
|
|
||||||
|
return fromutc
|
||||||
|
|
||||||
|
|
||||||
|
class _tzinfo(tzinfo):
|
||||||
|
"""
|
||||||
|
Base class for all ``dateutil`` ``tzinfo`` objects.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def is_ambiguous(self, dt):
|
||||||
|
"""
|
||||||
|
Whether or not the "wall time" of a given datetime is ambiguous in this
|
||||||
|
zone.
|
||||||
|
|
||||||
|
:param dt:
|
||||||
|
A :py:class:`datetime.datetime`, naive or time zone aware.
|
||||||
|
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns ``True`` if ambiguous, ``False`` otherwise.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
dt = dt.replace(tzinfo=self)
|
||||||
|
|
||||||
|
wall_0 = enfold(dt, fold=0)
|
||||||
|
wall_1 = enfold(dt, fold=1)
|
||||||
|
|
||||||
|
same_offset = wall_0.utcoffset() == wall_1.utcoffset()
|
||||||
|
same_dt = wall_0.replace(tzinfo=None) == wall_1.replace(tzinfo=None)
|
||||||
|
|
||||||
|
return same_dt and not same_offset
|
||||||
|
|
||||||
|
def _fold_status(self, dt_utc, dt_wall):
|
||||||
|
"""
|
||||||
|
Determine the fold status of a "wall" datetime, given a representation
|
||||||
|
of the same datetime as a (naive) UTC datetime. This is calculated based
|
||||||
|
on the assumption that ``dt.utcoffset() - dt.dst()`` is constant for all
|
||||||
|
datetimes, and that this offset is the actual number of hours separating
|
||||||
|
``dt_utc`` and ``dt_wall``.
|
||||||
|
|
||||||
|
:param dt_utc:
|
||||||
|
Representation of the datetime as UTC
|
||||||
|
|
||||||
|
:param dt_wall:
|
||||||
|
Representation of the datetime as "wall time". This parameter must
|
||||||
|
either have a `fold` attribute or have a fold-naive
|
||||||
|
:class:`datetime.tzinfo` attached, otherwise the calculation may
|
||||||
|
fail.
|
||||||
|
"""
|
||||||
|
if self.is_ambiguous(dt_wall):
|
||||||
|
delta_wall = dt_wall - dt_utc
|
||||||
|
_fold = int(delta_wall == (dt_utc.utcoffset() - dt_utc.dst()))
|
||||||
|
else:
|
||||||
|
_fold = 0
|
||||||
|
|
||||||
|
return _fold
|
||||||
|
|
||||||
|
def _fold(self, dt):
|
||||||
|
return getattr(dt, 'fold', 0)
|
||||||
|
|
||||||
|
def _fromutc(self, dt):
|
||||||
|
"""
|
||||||
|
Given a timezone-aware datetime in a given timezone, calculates a
|
||||||
|
timezone-aware datetime in a new timezone.
|
||||||
|
|
||||||
|
Since this is the one time that we *know* we have an unambiguous
|
||||||
|
datetime object, we take this opportunity to determine whether the
|
||||||
|
datetime is ambiguous and in a "fold" state (e.g. if it's the first
|
||||||
|
occurrence, chronologically, of the ambiguous datetime).
|
||||||
|
|
||||||
|
:param dt:
|
||||||
|
A timezone-aware :class:`datetime.datetime` object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Re-implement the algorithm from Python's datetime.py
|
||||||
|
dtoff = dt.utcoffset()
|
||||||
|
if dtoff is None:
|
||||||
|
raise ValueError("fromutc() requires a non-None utcoffset() "
|
||||||
|
"result")
|
||||||
|
|
||||||
|
# The original datetime.py code assumes that `dst()` defaults to
|
||||||
|
# zero during ambiguous times. PEP 495 inverts this presumption, so
|
||||||
|
# for pre-PEP 495 versions of python, we need to tweak the algorithm.
|
||||||
|
dtdst = dt.dst()
|
||||||
|
if dtdst is None:
|
||||||
|
raise ValueError("fromutc() requires a non-None dst() result")
|
||||||
|
delta = dtoff - dtdst
|
||||||
|
|
||||||
|
dt += delta
|
||||||
|
# Set fold=1 so we can default to being in the fold for
|
||||||
|
# ambiguous dates.
|
||||||
|
dtdst = enfold(dt, fold=1).dst()
|
||||||
|
if dtdst is None:
|
||||||
|
raise ValueError("fromutc(): dt.dst gave inconsistent "
|
||||||
|
"results; cannot convert")
|
||||||
|
return dt + dtdst
|
||||||
|
|
||||||
|
@_validate_fromutc_inputs
|
||||||
|
def fromutc(self, dt):
|
||||||
|
"""
|
||||||
|
Given a timezone-aware datetime in a given timezone, calculates a
|
||||||
|
timezone-aware datetime in a new timezone.
|
||||||
|
|
||||||
|
Since this is the one time that we *know* we have an unambiguous
|
||||||
|
datetime object, we take this opportunity to determine whether the
|
||||||
|
datetime is ambiguous and in a "fold" state (e.g. if it's the first
|
||||||
|
occurrence, chronologically, of the ambiguous datetime).
|
||||||
|
|
||||||
|
:param dt:
|
||||||
|
A timezone-aware :class:`datetime.datetime` object.
|
||||||
|
"""
|
||||||
|
dt_wall = self._fromutc(dt)
|
||||||
|
|
||||||
|
# Calculate the fold status given the two datetimes.
|
||||||
|
_fold = self._fold_status(dt, dt_wall)
|
||||||
|
|
||||||
|
# Set the default fold value for ambiguous dates
|
||||||
|
return enfold(dt_wall, fold=_fold)
|
||||||
|
|
||||||
|
|
||||||
|
class tzrangebase(_tzinfo):
|
||||||
|
"""
|
||||||
|
This is an abstract base class for time zones represented by an annual
|
||||||
|
transition into and out of DST. Child classes should implement the following
|
||||||
|
methods:
|
||||||
|
|
||||||
|
* ``__init__(self, *args, **kwargs)``
|
||||||
|
* ``transitions(self, year)`` - this is expected to return a tuple of
|
||||||
|
datetimes representing the DST on and off transitions in standard
|
||||||
|
time.
|
||||||
|
|
||||||
|
A fully initialized ``tzrangebase`` subclass should also provide the
|
||||||
|
following attributes:
|
||||||
|
* ``hasdst``: Boolean whether or not the zone uses DST.
|
||||||
|
* ``_dst_offset`` / ``_std_offset``: :class:`datetime.timedelta` objects
|
||||||
|
representing the respective UTC offsets.
|
||||||
|
* ``_dst_abbr`` / ``_std_abbr``: Strings representing the timezone short
|
||||||
|
abbreviations in DST and STD, respectively.
|
||||||
|
* ``_hasdst``: Whether or not the zone has DST.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6.0
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
raise NotImplementedError('tzrangebase is an abstract base class')
|
||||||
|
|
||||||
|
def utcoffset(self, dt):
|
||||||
|
isdst = self._isdst(dt)
|
||||||
|
|
||||||
|
if isdst is None:
|
||||||
|
return None
|
||||||
|
elif isdst:
|
||||||
|
return self._dst_offset
|
||||||
|
else:
|
||||||
|
return self._std_offset
|
||||||
|
|
||||||
|
def dst(self, dt):
|
||||||
|
isdst = self._isdst(dt)
|
||||||
|
|
||||||
|
if isdst is None:
|
||||||
|
return None
|
||||||
|
elif isdst:
|
||||||
|
return self._dst_base_offset
|
||||||
|
else:
|
||||||
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
|
def tzname(self, dt):
|
||||||
|
if self._isdst(dt):
|
||||||
|
return self._dst_abbr
|
||||||
|
else:
|
||||||
|
return self._std_abbr
|
||||||
|
|
||||||
|
def fromutc(self, dt):
|
||||||
|
""" Given a datetime in UTC, return local time """
|
||||||
|
if not isinstance(dt, datetime):
|
||||||
|
raise TypeError("fromutc() requires a datetime argument")
|
||||||
|
|
||||||
|
if dt.tzinfo is not self:
|
||||||
|
raise ValueError("dt.tzinfo is not self")
|
||||||
|
|
||||||
|
# Get transitions - if there are none, fixed offset
|
||||||
|
transitions = self.transitions(dt.year)
|
||||||
|
if transitions is None:
|
||||||
|
return dt + self.utcoffset(dt)
|
||||||
|
|
||||||
|
# Get the transition times in UTC
|
||||||
|
dston, dstoff = transitions
|
||||||
|
|
||||||
|
dston -= self._std_offset
|
||||||
|
dstoff -= self._std_offset
|
||||||
|
|
||||||
|
utc_transitions = (dston, dstoff)
|
||||||
|
dt_utc = dt.replace(tzinfo=None)
|
||||||
|
|
||||||
|
isdst = self._naive_isdst(dt_utc, utc_transitions)
|
||||||
|
|
||||||
|
if isdst:
|
||||||
|
dt_wall = dt + self._dst_offset
|
||||||
|
else:
|
||||||
|
dt_wall = dt + self._std_offset
|
||||||
|
|
||||||
|
_fold = int(not isdst and self.is_ambiguous(dt_wall))
|
||||||
|
|
||||||
|
return enfold(dt_wall, fold=_fold)
|
||||||
|
|
||||||
|
def is_ambiguous(self, dt):
|
||||||
|
"""
|
||||||
|
Whether or not the "wall time" of a given datetime is ambiguous in this
|
||||||
|
zone.
|
||||||
|
|
||||||
|
:param dt:
|
||||||
|
A :py:class:`datetime.datetime`, naive or time zone aware.
|
||||||
|
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns ``True`` if ambiguous, ``False`` otherwise.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6.0
|
||||||
|
"""
|
||||||
|
if not self.hasdst:
|
||||||
|
return False
|
||||||
|
|
||||||
|
start, end = self.transitions(dt.year)
|
||||||
|
|
||||||
|
dt = dt.replace(tzinfo=None)
|
||||||
|
return (end <= dt < end + self._dst_base_offset)
|
||||||
|
|
||||||
|
def _isdst(self, dt):
|
||||||
|
if not self.hasdst:
|
||||||
|
return False
|
||||||
|
elif dt is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
transitions = self.transitions(dt.year)
|
||||||
|
|
||||||
|
if transitions is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
dt = dt.replace(tzinfo=None)
|
||||||
|
|
||||||
|
isdst = self._naive_isdst(dt, transitions)
|
||||||
|
|
||||||
|
# Handle ambiguous dates
|
||||||
|
if not isdst and self.is_ambiguous(dt):
|
||||||
|
return not self._fold(dt)
|
||||||
|
else:
|
||||||
|
return isdst
|
||||||
|
|
||||||
|
def _naive_isdst(self, dt, transitions):
|
||||||
|
dston, dstoff = transitions
|
||||||
|
|
||||||
|
dt = dt.replace(tzinfo=None)
|
||||||
|
|
||||||
|
if dston < dstoff:
|
||||||
|
isdst = dston <= dt < dstoff
|
||||||
|
else:
|
||||||
|
isdst = not dstoff <= dt < dston
|
||||||
|
|
||||||
|
return isdst
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _dst_base_offset(self):
|
||||||
|
return self._dst_offset - self._std_offset
|
||||||
|
|
||||||
|
__hash__ = None
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not (self == other)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(...)" % self.__class__.__name__
|
||||||
|
|
||||||
|
__reduce__ = object.__reduce__
|
80
Source/Libs/dateutil/tz/_factories.py
Normal file
80
Source/Libs/dateutil/tz/_factories.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
from datetime import timedelta
|
||||||
|
import weakref
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from six.moves import _thread
|
||||||
|
|
||||||
|
|
||||||
|
class _TzSingleton(type):
|
||||||
|
def __init__(cls, *args, **kwargs):
|
||||||
|
cls.__instance = None
|
||||||
|
super(_TzSingleton, cls).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def __call__(cls):
|
||||||
|
if cls.__instance is None:
|
||||||
|
cls.__instance = super(_TzSingleton, cls).__call__()
|
||||||
|
return cls.__instance
|
||||||
|
|
||||||
|
|
||||||
|
class _TzFactory(type):
|
||||||
|
def instance(cls, *args, **kwargs):
|
||||||
|
"""Alternate constructor that returns a fresh instance"""
|
||||||
|
return type.__call__(cls, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class _TzOffsetFactory(_TzFactory):
|
||||||
|
def __init__(cls, *args, **kwargs):
|
||||||
|
cls.__instances = weakref.WeakValueDictionary()
|
||||||
|
cls.__strong_cache = OrderedDict()
|
||||||
|
cls.__strong_cache_size = 8
|
||||||
|
|
||||||
|
cls._cache_lock = _thread.allocate_lock()
|
||||||
|
|
||||||
|
def __call__(cls, name, offset):
|
||||||
|
if isinstance(offset, timedelta):
|
||||||
|
key = (name, offset.total_seconds())
|
||||||
|
else:
|
||||||
|
key = (name, offset)
|
||||||
|
|
||||||
|
instance = cls.__instances.get(key, None)
|
||||||
|
if instance is None:
|
||||||
|
instance = cls.__instances.setdefault(key,
|
||||||
|
cls.instance(name, offset))
|
||||||
|
|
||||||
|
# This lock may not be necessary in Python 3. See GH issue #901
|
||||||
|
with cls._cache_lock:
|
||||||
|
cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
|
||||||
|
|
||||||
|
# Remove an item if the strong cache is overpopulated
|
||||||
|
if len(cls.__strong_cache) > cls.__strong_cache_size:
|
||||||
|
cls.__strong_cache.popitem(last=False)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
class _TzStrFactory(_TzFactory):
|
||||||
|
def __init__(cls, *args, **kwargs):
|
||||||
|
cls.__instances = weakref.WeakValueDictionary()
|
||||||
|
cls.__strong_cache = OrderedDict()
|
||||||
|
cls.__strong_cache_size = 8
|
||||||
|
|
||||||
|
cls.__cache_lock = _thread.allocate_lock()
|
||||||
|
|
||||||
|
def __call__(cls, s, posix_offset=False):
|
||||||
|
key = (s, posix_offset)
|
||||||
|
instance = cls.__instances.get(key, None)
|
||||||
|
|
||||||
|
if instance is None:
|
||||||
|
instance = cls.__instances.setdefault(key,
|
||||||
|
cls.instance(s, posix_offset))
|
||||||
|
|
||||||
|
# This lock may not be necessary in Python 3. See GH issue #901
|
||||||
|
with cls.__cache_lock:
|
||||||
|
cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
|
||||||
|
|
||||||
|
# Remove an item if the strong cache is overpopulated
|
||||||
|
if len(cls.__strong_cache) > cls.__strong_cache_size:
|
||||||
|
cls.__strong_cache.popitem(last=False)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
1849
Source/Libs/dateutil/tz/tz.py
Normal file
1849
Source/Libs/dateutil/tz/tz.py
Normal file
File diff suppressed because it is too large
Load Diff
370
Source/Libs/dateutil/tz/win.py
Normal file
370
Source/Libs/dateutil/tz/win.py
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
This module provides an interface to the native time zone data on Windows,
|
||||||
|
including :py:class:`datetime.tzinfo` implementations.
|
||||||
|
|
||||||
|
Attempting to import this module on a non-Windows platform will raise an
|
||||||
|
:py:obj:`ImportError`.
|
||||||
|
"""
|
||||||
|
# This code was originally contributed by Jeffrey Harris.
|
||||||
|
import datetime
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from six.moves import winreg
|
||||||
|
from six import text_type
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ctypes
|
||||||
|
from ctypes import wintypes
|
||||||
|
except ValueError:
|
||||||
|
# ValueError is raised on non-Windows systems for some horrible reason.
|
||||||
|
raise ImportError("Running tzwin on non-Windows system")
|
||||||
|
|
||||||
|
from ._common import tzrangebase
|
||||||
|
|
||||||
|
__all__ = ["tzwin", "tzwinlocal", "tzres"]
|
||||||
|
|
||||||
|
ONEWEEK = datetime.timedelta(7)
|
||||||
|
|
||||||
|
TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
|
||||||
|
TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
|
||||||
|
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
|
||||||
|
|
||||||
|
|
||||||
|
def _settzkeyname():
|
||||||
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
|
try:
|
||||||
|
winreg.OpenKey(handle, TZKEYNAMENT).Close()
|
||||||
|
TZKEYNAME = TZKEYNAMENT
|
||||||
|
except WindowsError:
|
||||||
|
TZKEYNAME = TZKEYNAME9X
|
||||||
|
handle.Close()
|
||||||
|
return TZKEYNAME
|
||||||
|
|
||||||
|
|
||||||
|
TZKEYNAME = _settzkeyname()
|
||||||
|
|
||||||
|
|
||||||
|
class tzres(object):
|
||||||
|
"""
|
||||||
|
Class for accessing ``tzres.dll``, which contains timezone name related
|
||||||
|
resources.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5.0
|
||||||
|
"""
|
||||||
|
p_wchar = ctypes.POINTER(wintypes.WCHAR) # Pointer to a wide char
|
||||||
|
|
||||||
|
def __init__(self, tzres_loc='tzres.dll'):
|
||||||
|
# Load the user32 DLL so we can load strings from tzres
|
||||||
|
user32 = ctypes.WinDLL('user32')
|
||||||
|
|
||||||
|
# Specify the LoadStringW function
|
||||||
|
user32.LoadStringW.argtypes = (wintypes.HINSTANCE,
|
||||||
|
wintypes.UINT,
|
||||||
|
wintypes.LPWSTR,
|
||||||
|
ctypes.c_int)
|
||||||
|
|
||||||
|
self.LoadStringW = user32.LoadStringW
|
||||||
|
self._tzres = ctypes.WinDLL(tzres_loc)
|
||||||
|
self.tzres_loc = tzres_loc
|
||||||
|
|
||||||
|
def load_name(self, offset):
|
||||||
|
"""
|
||||||
|
Load a timezone name from a DLL offset (integer).
|
||||||
|
|
||||||
|
>>> from dateutil.tzwin import tzres
|
||||||
|
>>> tzr = tzres()
|
||||||
|
>>> print(tzr.load_name(112))
|
||||||
|
'Eastern Standard Time'
|
||||||
|
|
||||||
|
:param offset:
|
||||||
|
A positive integer value referring to a string from the tzres dll.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Offsets found in the registry are generally of the form
|
||||||
|
``@tzres.dll,-114``. The offset in this case is 114, not -114.
|
||||||
|
|
||||||
|
"""
|
||||||
|
resource = self.p_wchar()
|
||||||
|
lpBuffer = ctypes.cast(ctypes.byref(resource), wintypes.LPWSTR)
|
||||||
|
nchar = self.LoadStringW(self._tzres._handle, offset, lpBuffer, 0)
|
||||||
|
return resource[:nchar]
|
||||||
|
|
||||||
|
def name_from_string(self, tzname_str):
|
||||||
|
"""
|
||||||
|
Parse strings as returned from the Windows registry into the time zone
|
||||||
|
name as defined in the registry.
|
||||||
|
|
||||||
|
>>> from dateutil.tzwin import tzres
|
||||||
|
>>> tzr = tzres()
|
||||||
|
>>> print(tzr.name_from_string('@tzres.dll,-251'))
|
||||||
|
'Dateline Daylight Time'
|
||||||
|
>>> print(tzr.name_from_string('Eastern Standard Time'))
|
||||||
|
'Eastern Standard Time'
|
||||||
|
|
||||||
|
:param tzname_str:
|
||||||
|
A timezone name string as returned from a Windows registry key.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns the localized timezone string from tzres.dll if the string
|
||||||
|
is of the form `@tzres.dll,-offset`, else returns the input string.
|
||||||
|
"""
|
||||||
|
if not tzname_str.startswith('@'):
|
||||||
|
return tzname_str
|
||||||
|
|
||||||
|
name_splt = tzname_str.split(',-')
|
||||||
|
try:
|
||||||
|
offset = int(name_splt[1])
|
||||||
|
except:
|
||||||
|
raise ValueError("Malformed timezone string.")
|
||||||
|
|
||||||
|
return self.load_name(offset)
|
||||||
|
|
||||||
|
|
||||||
|
class tzwinbase(tzrangebase):
|
||||||
|
"""tzinfo class based on win32's timezones available in the registry."""
|
||||||
|
def __init__(self):
|
||||||
|
raise NotImplementedError('tzwinbase is an abstract base class')
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
# Compare on all relevant dimensions, including name.
|
||||||
|
if not isinstance(other, tzwinbase):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return (self._std_offset == other._std_offset and
|
||||||
|
self._dst_offset == other._dst_offset and
|
||||||
|
self._stddayofweek == other._stddayofweek and
|
||||||
|
self._dstdayofweek == other._dstdayofweek and
|
||||||
|
self._stdweeknumber == other._stdweeknumber and
|
||||||
|
self._dstweeknumber == other._dstweeknumber and
|
||||||
|
self._stdhour == other._stdhour and
|
||||||
|
self._dsthour == other._dsthour and
|
||||||
|
self._stdminute == other._stdminute and
|
||||||
|
self._dstminute == other._dstminute and
|
||||||
|
self._std_abbr == other._std_abbr and
|
||||||
|
self._dst_abbr == other._dst_abbr)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def list():
|
||||||
|
"""Return a list of all time zones known to the system."""
|
||||||
|
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
||||||
|
with winreg.OpenKey(handle, TZKEYNAME) as tzkey:
|
||||||
|
result = [winreg.EnumKey(tzkey, i)
|
||||||
|
for i in range(winreg.QueryInfoKey(tzkey)[0])]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def display(self):
|
||||||
|
"""
|
||||||
|
Return the display name of the time zone.
|
||||||
|
"""
|
||||||
|
return self._display
|
||||||
|
|
||||||
|
def transitions(self, year):
|
||||||
|
"""
|
||||||
|
For a given year, get the DST on and off transition times, expressed
|
||||||
|
always on the standard time side. For zones with no transitions, this
|
||||||
|
function returns ``None``.
|
||||||
|
|
||||||
|
:param year:
|
||||||
|
The year whose transitions you would like to query.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`tuple` of :class:`datetime.datetime` objects,
|
||||||
|
``(dston, dstoff)`` for zones with an annual DST transition, or
|
||||||
|
``None`` for fixed offset zones.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self.hasdst:
|
||||||
|
return None
|
||||||
|
|
||||||
|
dston = picknthweekday(year, self._dstmonth, self._dstdayofweek,
|
||||||
|
self._dsthour, self._dstminute,
|
||||||
|
self._dstweeknumber)
|
||||||
|
|
||||||
|
dstoff = picknthweekday(year, self._stdmonth, self._stddayofweek,
|
||||||
|
self._stdhour, self._stdminute,
|
||||||
|
self._stdweeknumber)
|
||||||
|
|
||||||
|
# Ambiguous dates default to the STD side
|
||||||
|
dstoff -= self._dst_base_offset
|
||||||
|
|
||||||
|
return dston, dstoff
|
||||||
|
|
||||||
|
def _get_hasdst(self):
|
||||||
|
return self._dstmonth != 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _dst_base_offset(self):
|
||||||
|
return self._dst_base_offset_
|
||||||
|
|
||||||
|
|
||||||
|
class tzwin(tzwinbase):
|
||||||
|
"""
|
||||||
|
Time zone object created from the zone info in the Windows registry
|
||||||
|
|
||||||
|
These are similar to :py:class:`dateutil.tz.tzrange` objects in that
|
||||||
|
the time zone data is provided in the format of a single offset rule
|
||||||
|
for either 0 or 2 time zone transitions per year.
|
||||||
|
|
||||||
|
:param: name
|
||||||
|
The name of a Windows time zone key, e.g. "Eastern Standard Time".
|
||||||
|
The full list of keys can be retrieved with :func:`tzwin.list`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
||||||
|
tzkeyname = text_type("{kn}\\{name}").format(kn=TZKEYNAME, name=name)
|
||||||
|
with winreg.OpenKey(handle, tzkeyname) as tzkey:
|
||||||
|
keydict = valuestodict(tzkey)
|
||||||
|
|
||||||
|
self._std_abbr = keydict["Std"]
|
||||||
|
self._dst_abbr = keydict["Dlt"]
|
||||||
|
|
||||||
|
self._display = keydict["Display"]
|
||||||
|
|
||||||
|
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
||||||
|
tup = struct.unpack("=3l16h", keydict["TZI"])
|
||||||
|
stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
|
||||||
|
dstoffset = stdoffset-tup[2] # + DaylightBias * -1
|
||||||
|
self._std_offset = datetime.timedelta(minutes=stdoffset)
|
||||||
|
self._dst_offset = datetime.timedelta(minutes=dstoffset)
|
||||||
|
|
||||||
|
# for the meaning see the win32 TIME_ZONE_INFORMATION structure docs
|
||||||
|
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
|
||||||
|
(self._stdmonth,
|
||||||
|
self._stddayofweek, # Sunday = 0
|
||||||
|
self._stdweeknumber, # Last = 5
|
||||||
|
self._stdhour,
|
||||||
|
self._stdminute) = tup[4:9]
|
||||||
|
|
||||||
|
(self._dstmonth,
|
||||||
|
self._dstdayofweek, # Sunday = 0
|
||||||
|
self._dstweeknumber, # Last = 5
|
||||||
|
self._dsthour,
|
||||||
|
self._dstminute) = tup[12:17]
|
||||||
|
|
||||||
|
self._dst_base_offset_ = self._dst_offset - self._std_offset
|
||||||
|
self.hasdst = self._get_hasdst()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "tzwin(%s)" % repr(self._name)
|
||||||
|
|
||||||
|
def __reduce__(self):
|
||||||
|
return (self.__class__, (self._name,))
|
||||||
|
|
||||||
|
|
||||||
|
class tzwinlocal(tzwinbase):
|
||||||
|
"""
|
||||||
|
Class representing the local time zone information in the Windows registry
|
||||||
|
|
||||||
|
While :class:`dateutil.tz.tzlocal` makes system calls (via the :mod:`time`
|
||||||
|
module) to retrieve time zone information, ``tzwinlocal`` retrieves the
|
||||||
|
rules directly from the Windows registry and creates an object like
|
||||||
|
:class:`dateutil.tz.tzwin`.
|
||||||
|
|
||||||
|
Because Windows does not have an equivalent of :func:`time.tzset`, on
|
||||||
|
Windows, :class:`dateutil.tz.tzlocal` instances will always reflect the
|
||||||
|
time zone settings *at the time that the process was started*, meaning
|
||||||
|
changes to the machine's time zone settings during the run of a program
|
||||||
|
on Windows will **not** be reflected by :class:`dateutil.tz.tzlocal`.
|
||||||
|
Because ``tzwinlocal`` reads the registry directly, it is unaffected by
|
||||||
|
this issue.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
||||||
|
with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey:
|
||||||
|
keydict = valuestodict(tzlocalkey)
|
||||||
|
|
||||||
|
self._std_abbr = keydict["StandardName"]
|
||||||
|
self._dst_abbr = keydict["DaylightName"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
tzkeyname = text_type('{kn}\\{sn}').format(kn=TZKEYNAME,
|
||||||
|
sn=self._std_abbr)
|
||||||
|
with winreg.OpenKey(handle, tzkeyname) as tzkey:
|
||||||
|
_keydict = valuestodict(tzkey)
|
||||||
|
self._display = _keydict["Display"]
|
||||||
|
except OSError:
|
||||||
|
self._display = None
|
||||||
|
|
||||||
|
stdoffset = -keydict["Bias"]-keydict["StandardBias"]
|
||||||
|
dstoffset = stdoffset-keydict["DaylightBias"]
|
||||||
|
|
||||||
|
self._std_offset = datetime.timedelta(minutes=stdoffset)
|
||||||
|
self._dst_offset = datetime.timedelta(minutes=dstoffset)
|
||||||
|
|
||||||
|
# For reasons unclear, in this particular key, the day of week has been
|
||||||
|
# moved to the END of the SYSTEMTIME structure.
|
||||||
|
tup = struct.unpack("=8h", keydict["StandardStart"])
|
||||||
|
|
||||||
|
(self._stdmonth,
|
||||||
|
self._stdweeknumber, # Last = 5
|
||||||
|
self._stdhour,
|
||||||
|
self._stdminute) = tup[1:5]
|
||||||
|
|
||||||
|
self._stddayofweek = tup[7]
|
||||||
|
|
||||||
|
tup = struct.unpack("=8h", keydict["DaylightStart"])
|
||||||
|
|
||||||
|
(self._dstmonth,
|
||||||
|
self._dstweeknumber, # Last = 5
|
||||||
|
self._dsthour,
|
||||||
|
self._dstminute) = tup[1:5]
|
||||||
|
|
||||||
|
self._dstdayofweek = tup[7]
|
||||||
|
|
||||||
|
self._dst_base_offset_ = self._dst_offset - self._std_offset
|
||||||
|
self.hasdst = self._get_hasdst()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "tzwinlocal()"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
# str will return the standard name, not the daylight name.
|
||||||
|
return "tzwinlocal(%s)" % repr(self._std_abbr)
|
||||||
|
|
||||||
|
def __reduce__(self):
|
||||||
|
return (self.__class__, ())
|
||||||
|
|
||||||
|
|
||||||
|
def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
|
||||||
|
""" dayofweek == 0 means Sunday, whichweek 5 means last instance """
|
||||||
|
first = datetime.datetime(year, month, 1, hour, minute)
|
||||||
|
|
||||||
|
# This will work if dayofweek is ISO weekday (1-7) or Microsoft-style (0-6),
|
||||||
|
# Because 7 % 7 = 0
|
||||||
|
weekdayone = first.replace(day=((dayofweek - first.isoweekday()) % 7) + 1)
|
||||||
|
wd = weekdayone + ((whichweek - 1) * ONEWEEK)
|
||||||
|
if (wd.month != month):
|
||||||
|
wd -= ONEWEEK
|
||||||
|
|
||||||
|
return wd
|
||||||
|
|
||||||
|
|
||||||
|
def valuestodict(key):
|
||||||
|
"""Convert a registry key's values to a dictionary."""
|
||||||
|
dout = {}
|
||||||
|
size = winreg.QueryInfoKey(key)[1]
|
||||||
|
tz_res = None
|
||||||
|
|
||||||
|
for i in range(size):
|
||||||
|
key_name, value, dtype = winreg.EnumValue(key, i)
|
||||||
|
if dtype == winreg.REG_DWORD or dtype == winreg.REG_DWORD_LITTLE_ENDIAN:
|
||||||
|
# If it's a DWORD (32-bit integer), it's stored as unsigned - convert
|
||||||
|
# that to a proper signed integer
|
||||||
|
if value & (1 << 31):
|
||||||
|
value = value - (1 << 32)
|
||||||
|
elif dtype == winreg.REG_SZ:
|
||||||
|
# If it's a reference to the tzres DLL, load the actual string
|
||||||
|
if value.startswith('@tzres'):
|
||||||
|
tz_res = tz_res or tzres()
|
||||||
|
value = tz_res.name_from_string(value)
|
||||||
|
|
||||||
|
value = value.rstrip('\x00') # Remove trailing nulls
|
||||||
|
|
||||||
|
dout[key_name] = value
|
||||||
|
|
||||||
|
return dout
|
2
Source/Libs/dateutil/tzwin.py
Normal file
2
Source/Libs/dateutil/tzwin.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# tzwin has moved to dateutil.tz.win
|
||||||
|
from .tz.win import *
|
71
Source/Libs/dateutil/utils.py
Normal file
71
Source/Libs/dateutil/utils.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
This module offers general convenience and utility functions for dealing with
|
||||||
|
datetimes.
|
||||||
|
|
||||||
|
.. versionadded:: 2.7.0
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from datetime import datetime, time
|
||||||
|
|
||||||
|
|
||||||
|
def today(tzinfo=None):
|
||||||
|
"""
|
||||||
|
Returns a :py:class:`datetime` representing the current day at midnight
|
||||||
|
|
||||||
|
:param tzinfo:
|
||||||
|
The time zone to attach (also used to determine the current day).
|
||||||
|
|
||||||
|
:return:
|
||||||
|
A :py:class:`datetime.datetime` object representing the current day
|
||||||
|
at midnight.
|
||||||
|
"""
|
||||||
|
|
||||||
|
dt = datetime.now(tzinfo)
|
||||||
|
return datetime.combine(dt.date(), time(0, tzinfo=tzinfo))
|
||||||
|
|
||||||
|
|
||||||
|
def default_tzinfo(dt, tzinfo):
|
||||||
|
"""
|
||||||
|
Sets the ``tzinfo`` parameter on naive datetimes only
|
||||||
|
|
||||||
|
This is useful for example when you are provided a datetime that may have
|
||||||
|
either an implicit or explicit time zone, such as when parsing a time zone
|
||||||
|
string.
|
||||||
|
|
||||||
|
.. doctest::
|
||||||
|
|
||||||
|
>>> from dateutil.tz import tzoffset
|
||||||
|
>>> from dateutil.parser import parse
|
||||||
|
>>> from dateutil.utils import default_tzinfo
|
||||||
|
>>> dflt_tz = tzoffset("EST", -18000)
|
||||||
|
>>> print(default_tzinfo(parse('2014-01-01 12:30 UTC'), dflt_tz))
|
||||||
|
2014-01-01 12:30:00+00:00
|
||||||
|
>>> print(default_tzinfo(parse('2014-01-01 12:30'), dflt_tz))
|
||||||
|
2014-01-01 12:30:00-05:00
|
||||||
|
|
||||||
|
:param dt:
|
||||||
|
The datetime on which to replace the time zone
|
||||||
|
|
||||||
|
:param tzinfo:
|
||||||
|
The :py:class:`datetime.tzinfo` subclass instance to assign to
|
||||||
|
``dt`` if (and only if) it is naive.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns an aware :py:class:`datetime.datetime`.
|
||||||
|
"""
|
||||||
|
if dt.tzinfo is not None:
|
||||||
|
return dt
|
||||||
|
else:
|
||||||
|
return dt.replace(tzinfo=tzinfo)
|
||||||
|
|
||||||
|
|
||||||
|
def within_delta(dt1, dt2, delta):
|
||||||
|
"""
|
||||||
|
Useful for comparing two datetimes that may have a negligible difference
|
||||||
|
to be considered equal.
|
||||||
|
"""
|
||||||
|
delta = abs(delta)
|
||||||
|
difference = dt1 - dt2
|
||||||
|
return -delta <= difference <= delta
|
167
Source/Libs/dateutil/zoneinfo/__init__.py
Normal file
167
Source/Libs/dateutil/zoneinfo/__init__.py
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import warnings
|
||||||
|
import json
|
||||||
|
|
||||||
|
from tarfile import TarFile
|
||||||
|
from pkgutil import get_data
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
from dateutil.tz import tzfile as _tzfile
|
||||||
|
|
||||||
|
__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"]
|
||||||
|
|
||||||
|
ZONEFILENAME = "dateutil-zoneinfo.tar.gz"
|
||||||
|
METADATA_FN = 'METADATA'
|
||||||
|
|
||||||
|
|
||||||
|
class tzfile(_tzfile):
|
||||||
|
def __reduce__(self):
|
||||||
|
return (gettz, (self._filename,))
|
||||||
|
|
||||||
|
|
||||||
|
def getzoneinfofile_stream():
|
||||||
|
try:
|
||||||
|
return BytesIO(get_data(__name__, ZONEFILENAME))
|
||||||
|
except IOError as e: # TODO switch to FileNotFoundError?
|
||||||
|
warnings.warn("I/O error({0}): {1}".format(e.errno, e.strerror))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ZoneInfoFile(object):
|
||||||
|
def __init__(self, zonefile_stream=None):
|
||||||
|
if zonefile_stream is not None:
|
||||||
|
with TarFile.open(fileobj=zonefile_stream) as tf:
|
||||||
|
self.zones = {zf.name: tzfile(tf.extractfile(zf), filename=zf.name)
|
||||||
|
for zf in tf.getmembers()
|
||||||
|
if zf.isfile() and zf.name != METADATA_FN}
|
||||||
|
# deal with links: They'll point to their parent object. Less
|
||||||
|
# waste of memory
|
||||||
|
links = {zl.name: self.zones[zl.linkname]
|
||||||
|
for zl in tf.getmembers() if
|
||||||
|
zl.islnk() or zl.issym()}
|
||||||
|
self.zones.update(links)
|
||||||
|
try:
|
||||||
|
metadata_json = tf.extractfile(tf.getmember(METADATA_FN))
|
||||||
|
metadata_str = metadata_json.read().decode('UTF-8')
|
||||||
|
self.metadata = json.loads(metadata_str)
|
||||||
|
except KeyError:
|
||||||
|
# no metadata in tar file
|
||||||
|
self.metadata = None
|
||||||
|
else:
|
||||||
|
self.zones = {}
|
||||||
|
self.metadata = None
|
||||||
|
|
||||||
|
def get(self, name, default=None):
|
||||||
|
"""
|
||||||
|
Wrapper for :func:`ZoneInfoFile.zones.get`. This is a convenience method
|
||||||
|
for retrieving zones from the zone dictionary.
|
||||||
|
|
||||||
|
:param name:
|
||||||
|
The name of the zone to retrieve. (Generally IANA zone names)
|
||||||
|
|
||||||
|
:param default:
|
||||||
|
The value to return in the event of a missing key.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self.zones.get(name, default)
|
||||||
|
|
||||||
|
|
||||||
|
# The current API has gettz as a module function, although in fact it taps into
|
||||||
|
# a stateful class. So as a workaround for now, without changing the API, we
|
||||||
|
# will create a new "global" class instance the first time a user requests a
|
||||||
|
# timezone. Ugly, but adheres to the api.
|
||||||
|
#
|
||||||
|
# TODO: Remove after deprecation period.
|
||||||
|
_CLASS_ZONE_INSTANCE = []
|
||||||
|
|
||||||
|
|
||||||
|
def get_zonefile_instance(new_instance=False):
|
||||||
|
"""
|
||||||
|
This is a convenience function which provides a :class:`ZoneInfoFile`
|
||||||
|
instance using the data provided by the ``dateutil`` package. By default, it
|
||||||
|
caches a single instance of the ZoneInfoFile object and returns that.
|
||||||
|
|
||||||
|
:param new_instance:
|
||||||
|
If ``True``, a new instance of :class:`ZoneInfoFile` is instantiated and
|
||||||
|
used as the cached instance for the next call. Otherwise, new instances
|
||||||
|
are created only as necessary.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`ZoneInfoFile` object.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
"""
|
||||||
|
if new_instance:
|
||||||
|
zif = None
|
||||||
|
else:
|
||||||
|
zif = getattr(get_zonefile_instance, '_cached_instance', None)
|
||||||
|
|
||||||
|
if zif is None:
|
||||||
|
zif = ZoneInfoFile(getzoneinfofile_stream())
|
||||||
|
|
||||||
|
get_zonefile_instance._cached_instance = zif
|
||||||
|
|
||||||
|
return zif
|
||||||
|
|
||||||
|
|
||||||
|
def gettz(name):
|
||||||
|
"""
|
||||||
|
This retrieves a time zone from the local zoneinfo tarball that is packaged
|
||||||
|
with dateutil.
|
||||||
|
|
||||||
|
:param name:
|
||||||
|
An IANA-style time zone name, as found in the zoneinfo file.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
Returns a :class:`dateutil.tz.tzfile` time zone object.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
It is generally inadvisable to use this function, and it is only
|
||||||
|
provided for API compatibility with earlier versions. This is *not*
|
||||||
|
equivalent to ``dateutil.tz.gettz()``, which selects an appropriate
|
||||||
|
time zone based on the inputs, favoring system zoneinfo. This is ONLY
|
||||||
|
for accessing the dateutil-specific zoneinfo (which may be out of
|
||||||
|
date compared to the system zoneinfo).
|
||||||
|
|
||||||
|
.. deprecated:: 2.6
|
||||||
|
If you need to use a specific zoneinfofile over the system zoneinfo,
|
||||||
|
instantiate a :class:`dateutil.zoneinfo.ZoneInfoFile` object and call
|
||||||
|
:func:`dateutil.zoneinfo.ZoneInfoFile.get(name)` instead.
|
||||||
|
|
||||||
|
Use :func:`get_zonefile_instance` to retrieve an instance of the
|
||||||
|
dateutil-provided zoneinfo.
|
||||||
|
"""
|
||||||
|
warnings.warn("zoneinfo.gettz() will be removed in future versions, "
|
||||||
|
"to use the dateutil-provided zoneinfo files, instantiate a "
|
||||||
|
"ZoneInfoFile object and use ZoneInfoFile.zones.get() "
|
||||||
|
"instead. See the documentation for details.",
|
||||||
|
DeprecationWarning)
|
||||||
|
|
||||||
|
if len(_CLASS_ZONE_INSTANCE) == 0:
|
||||||
|
_CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
|
||||||
|
return _CLASS_ZONE_INSTANCE[0].zones.get(name)
|
||||||
|
|
||||||
|
|
||||||
|
def gettz_db_metadata():
|
||||||
|
""" Get the zonefile metadata
|
||||||
|
|
||||||
|
See `zonefile_metadata`_
|
||||||
|
|
||||||
|
:returns:
|
||||||
|
A dictionary with the database metadata
|
||||||
|
|
||||||
|
.. deprecated:: 2.6
|
||||||
|
See deprecation warning in :func:`zoneinfo.gettz`. To get metadata,
|
||||||
|
query the attribute ``zoneinfo.ZoneInfoFile.metadata``.
|
||||||
|
"""
|
||||||
|
warnings.warn("zoneinfo.gettz_db_metadata() will be removed in future "
|
||||||
|
"versions, to use the dateutil-provided zoneinfo files, "
|
||||||
|
"ZoneInfoFile object and query the 'metadata' attribute "
|
||||||
|
"instead. See the documentation for details.",
|
||||||
|
DeprecationWarning)
|
||||||
|
|
||||||
|
if len(_CLASS_ZONE_INSTANCE) == 0:
|
||||||
|
_CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
|
||||||
|
return _CLASS_ZONE_INSTANCE[0].metadata
|
BIN
Source/Libs/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz
Normal file
BIN
Source/Libs/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz
Normal file
Binary file not shown.
75
Source/Libs/dateutil/zoneinfo/rebuild.py
Normal file
75
Source/Libs/dateutil/zoneinfo/rebuild.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import json
|
||||||
|
from subprocess import check_call, check_output
|
||||||
|
from tarfile import TarFile
|
||||||
|
|
||||||
|
from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
|
||||||
|
|
||||||
|
|
||||||
|
def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
|
||||||
|
"""Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
|
||||||
|
|
||||||
|
filename is the timezone tarball from ``ftp.iana.org/tz``.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
zonedir = os.path.join(tmpdir, "zoneinfo")
|
||||||
|
moduledir = os.path.dirname(__file__)
|
||||||
|
try:
|
||||||
|
with TarFile.open(filename) as tf:
|
||||||
|
for name in zonegroups:
|
||||||
|
tf.extract(name, tmpdir)
|
||||||
|
filepaths = [os.path.join(tmpdir, n) for n in zonegroups]
|
||||||
|
|
||||||
|
_run_zic(zonedir, filepaths)
|
||||||
|
|
||||||
|
# write metadata file
|
||||||
|
with open(os.path.join(zonedir, METADATA_FN), 'w') as f:
|
||||||
|
json.dump(metadata, f, indent=4, sort_keys=True)
|
||||||
|
target = os.path.join(moduledir, ZONEFILENAME)
|
||||||
|
with TarFile.open(target, "w:%s" % format) as tf:
|
||||||
|
for entry in os.listdir(zonedir):
|
||||||
|
entrypath = os.path.join(zonedir, entry)
|
||||||
|
tf.add(entrypath, entry)
|
||||||
|
finally:
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_zic(zonedir, filepaths):
|
||||||
|
"""Calls the ``zic`` compiler in a compatible way to get a "fat" binary.
|
||||||
|
|
||||||
|
Recent versions of ``zic`` default to ``-b slim``, while older versions
|
||||||
|
don't even have the ``-b`` option (but default to "fat" binaries). The
|
||||||
|
current version of dateutil does not support Version 2+ TZif files, which
|
||||||
|
causes problems when used in conjunction with "slim" binaries, so this
|
||||||
|
function is used to ensure that we always get a "fat" binary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
help_text = check_output(["zic", "--help"])
|
||||||
|
except OSError as e:
|
||||||
|
_print_on_nosuchfile(e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
if b"-b " in help_text:
|
||||||
|
bloat_args = ["-b", "fat"]
|
||||||
|
else:
|
||||||
|
bloat_args = []
|
||||||
|
|
||||||
|
check_call(["zic"] + bloat_args + ["-d", zonedir] + filepaths)
|
||||||
|
|
||||||
|
|
||||||
|
def _print_on_nosuchfile(e):
|
||||||
|
"""Print helpful troubleshooting message
|
||||||
|
|
||||||
|
e is an exception raised by subprocess.check_call()
|
||||||
|
|
||||||
|
"""
|
||||||
|
if e.errno == 2:
|
||||||
|
logging.error(
|
||||||
|
"Could not find zic. Perhaps you need to install "
|
||||||
|
"libc-bin or some other package that provides it, "
|
||||||
|
"or it's not in your PATH?")
|
998
Source/Libs/six.py
Normal file
998
Source/Libs/six.py
Normal file
@ -0,0 +1,998 @@
|
|||||||
|
# Copyright (c) 2010-2020 Benjamin Peterson
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
"""Utilities for writing code that runs on Python 2 and 3"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import itertools
|
||||||
|
import operator
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
|
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||||
|
__version__ = "1.16.0"
|
||||||
|
|
||||||
|
|
||||||
|
# Useful for very coarse version differentiation.
|
||||||
|
PY2 = sys.version_info[0] == 2
|
||||||
|
PY3 = sys.version_info[0] == 3
|
||||||
|
PY34 = sys.version_info[0:2] >= (3, 4)
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
string_types = str,
|
||||||
|
integer_types = int,
|
||||||
|
class_types = type,
|
||||||
|
text_type = str
|
||||||
|
binary_type = bytes
|
||||||
|
|
||||||
|
MAXSIZE = sys.maxsize
|
||||||
|
else:
|
||||||
|
string_types = basestring,
|
||||||
|
integer_types = (int, long)
|
||||||
|
class_types = (type, types.ClassType)
|
||||||
|
text_type = unicode
|
||||||
|
binary_type = str
|
||||||
|
|
||||||
|
if sys.platform.startswith("java"):
|
||||||
|
# Jython always uses 32 bits.
|
||||||
|
MAXSIZE = int((1 << 31) - 1)
|
||||||
|
else:
|
||||||
|
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
||||||
|
class X(object):
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return 1 << 31
|
||||||
|
try:
|
||||||
|
len(X())
|
||||||
|
except OverflowError:
|
||||||
|
# 32-bit
|
||||||
|
MAXSIZE = int((1 << 31) - 1)
|
||||||
|
else:
|
||||||
|
# 64-bit
|
||||||
|
MAXSIZE = int((1 << 63) - 1)
|
||||||
|
del X
|
||||||
|
|
||||||
|
if PY34:
|
||||||
|
from importlib.util import spec_from_loader
|
||||||
|
else:
|
||||||
|
spec_from_loader = None
|
||||||
|
|
||||||
|
|
||||||
|
def _add_doc(func, doc):
|
||||||
|
"""Add documentation to a function."""
|
||||||
|
func.__doc__ = doc
|
||||||
|
|
||||||
|
|
||||||
|
def _import_module(name):
|
||||||
|
"""Import module, returning the module after the last dot."""
|
||||||
|
__import__(name)
|
||||||
|
return sys.modules[name]
|
||||||
|
|
||||||
|
|
||||||
|
class _LazyDescr(object):
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __get__(self, obj, tp):
|
||||||
|
result = self._resolve()
|
||||||
|
setattr(obj, self.name, result) # Invokes __set__.
|
||||||
|
try:
|
||||||
|
# This is a bit ugly, but it avoids running this again by
|
||||||
|
# removing this descriptor.
|
||||||
|
delattr(obj.__class__, self.name)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class MovedModule(_LazyDescr):
|
||||||
|
|
||||||
|
def __init__(self, name, old, new=None):
|
||||||
|
super(MovedModule, self).__init__(name)
|
||||||
|
if PY3:
|
||||||
|
if new is None:
|
||||||
|
new = name
|
||||||
|
self.mod = new
|
||||||
|
else:
|
||||||
|
self.mod = old
|
||||||
|
|
||||||
|
def _resolve(self):
|
||||||
|
return _import_module(self.mod)
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
_module = self._resolve()
|
||||||
|
value = getattr(_module, attr)
|
||||||
|
setattr(self, attr, value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class _LazyModule(types.ModuleType):
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
super(_LazyModule, self).__init__(name)
|
||||||
|
self.__doc__ = self.__class__.__doc__
|
||||||
|
|
||||||
|
def __dir__(self):
|
||||||
|
attrs = ["__doc__", "__name__"]
|
||||||
|
attrs += [attr.name for attr in self._moved_attributes]
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
# Subclasses should override this
|
||||||
|
_moved_attributes = []
|
||||||
|
|
||||||
|
|
||||||
|
class MovedAttribute(_LazyDescr):
|
||||||
|
|
||||||
|
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
|
||||||
|
super(MovedAttribute, self).__init__(name)
|
||||||
|
if PY3:
|
||||||
|
if new_mod is None:
|
||||||
|
new_mod = name
|
||||||
|
self.mod = new_mod
|
||||||
|
if new_attr is None:
|
||||||
|
if old_attr is None:
|
||||||
|
new_attr = name
|
||||||
|
else:
|
||||||
|
new_attr = old_attr
|
||||||
|
self.attr = new_attr
|
||||||
|
else:
|
||||||
|
self.mod = old_mod
|
||||||
|
if old_attr is None:
|
||||||
|
old_attr = name
|
||||||
|
self.attr = old_attr
|
||||||
|
|
||||||
|
def _resolve(self):
|
||||||
|
module = _import_module(self.mod)
|
||||||
|
return getattr(module, self.attr)
|
||||||
|
|
||||||
|
|
||||||
|
class _SixMetaPathImporter(object):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A meta path importer to import six.moves and its submodules.
|
||||||
|
|
||||||
|
This class implements a PEP302 finder and loader. It should be compatible
|
||||||
|
with Python 2.5 and all existing versions of Python3
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, six_module_name):
|
||||||
|
self.name = six_module_name
|
||||||
|
self.known_modules = {}
|
||||||
|
|
||||||
|
def _add_module(self, mod, *fullnames):
|
||||||
|
for fullname in fullnames:
|
||||||
|
self.known_modules[self.name + "." + fullname] = mod
|
||||||
|
|
||||||
|
def _get_module(self, fullname):
|
||||||
|
return self.known_modules[self.name + "." + fullname]
|
||||||
|
|
||||||
|
def find_module(self, fullname, path=None):
|
||||||
|
if fullname in self.known_modules:
|
||||||
|
return self
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_spec(self, fullname, path, target=None):
|
||||||
|
if fullname in self.known_modules:
|
||||||
|
return spec_from_loader(fullname, self)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __get_module(self, fullname):
|
||||||
|
try:
|
||||||
|
return self.known_modules[fullname]
|
||||||
|
except KeyError:
|
||||||
|
raise ImportError("This loader does not know module " + fullname)
|
||||||
|
|
||||||
|
def load_module(self, fullname):
|
||||||
|
try:
|
||||||
|
# in case of a reload
|
||||||
|
return sys.modules[fullname]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
mod = self.__get_module(fullname)
|
||||||
|
if isinstance(mod, MovedModule):
|
||||||
|
mod = mod._resolve()
|
||||||
|
else:
|
||||||
|
mod.__loader__ = self
|
||||||
|
sys.modules[fullname] = mod
|
||||||
|
return mod
|
||||||
|
|
||||||
|
def is_package(self, fullname):
|
||||||
|
"""
|
||||||
|
Return true, if the named module is a package.
|
||||||
|
|
||||||
|
We need this method to get correct spec objects with
|
||||||
|
Python 3.4 (see PEP451)
|
||||||
|
"""
|
||||||
|
return hasattr(self.__get_module(fullname), "__path__")
|
||||||
|
|
||||||
|
def get_code(self, fullname):
|
||||||
|
"""Return None
|
||||||
|
|
||||||
|
Required, if is_package is implemented"""
|
||||||
|
self.__get_module(fullname) # eventually raises ImportError
|
||||||
|
return None
|
||||||
|
get_source = get_code # same as get_code
|
||||||
|
|
||||||
|
def create_module(self, spec):
|
||||||
|
return self.load_module(spec.name)
|
||||||
|
|
||||||
|
def exec_module(self, module):
|
||||||
|
pass
|
||||||
|
|
||||||
|
_importer = _SixMetaPathImporter(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class _MovedItems(_LazyModule):
|
||||||
|
|
||||||
|
"""Lazy loading of moved objects"""
|
||||||
|
__path__ = [] # mark as package
|
||||||
|
|
||||||
|
|
||||||
|
_moved_attributes = [
|
||||||
|
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
||||||
|
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
||||||
|
MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
|
||||||
|
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
||||||
|
MovedAttribute("intern", "__builtin__", "sys"),
|
||||||
|
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
||||||
|
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
|
||||||
|
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
|
||||||
|
MovedAttribute("getoutput", "commands", "subprocess"),
|
||||||
|
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
|
||||||
|
MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
|
||||||
|
MovedAttribute("reduce", "__builtin__", "functools"),
|
||||||
|
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
|
||||||
|
MovedAttribute("StringIO", "StringIO", "io"),
|
||||||
|
MovedAttribute("UserDict", "UserDict", "collections"),
|
||||||
|
MovedAttribute("UserList", "UserList", "collections"),
|
||||||
|
MovedAttribute("UserString", "UserString", "collections"),
|
||||||
|
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
||||||
|
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
||||||
|
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
||||||
|
MovedModule("builtins", "__builtin__"),
|
||||||
|
MovedModule("configparser", "ConfigParser"),
|
||||||
|
MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"),
|
||||||
|
MovedModule("copyreg", "copy_reg"),
|
||||||
|
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
||||||
|
MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
|
||||||
|
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"),
|
||||||
|
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
||||||
|
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
||||||
|
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
||||||
|
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
||||||
|
MovedModule("http_client", "httplib", "http.client"),
|
||||||
|
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
|
||||||
|
MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
|
||||||
|
MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
||||||
|
MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
|
||||||
|
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
|
||||||
|
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
||||||
|
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
|
||||||
|
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
|
||||||
|
MovedModule("cPickle", "cPickle", "pickle"),
|
||||||
|
MovedModule("queue", "Queue"),
|
||||||
|
MovedModule("reprlib", "repr"),
|
||||||
|
MovedModule("socketserver", "SocketServer"),
|
||||||
|
MovedModule("_thread", "thread", "_thread"),
|
||||||
|
MovedModule("tkinter", "Tkinter"),
|
||||||
|
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
||||||
|
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
||||||
|
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
||||||
|
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
||||||
|
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
||||||
|
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
|
||||||
|
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
||||||
|
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
||||||
|
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
||||||
|
"tkinter.colorchooser"),
|
||||||
|
MovedModule("tkinter_commondialog", "tkCommonDialog",
|
||||||
|
"tkinter.commondialog"),
|
||||||
|
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
||||||
|
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
||||||
|
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
||||||
|
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
|
||||||
|
"tkinter.simpledialog"),
|
||||||
|
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
||||||
|
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
||||||
|
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
||||||
|
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
||||||
|
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
|
||||||
|
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
|
||||||
|
]
|
||||||
|
# Add windows specific modules.
|
||||||
|
if sys.platform == "win32":
|
||||||
|
_moved_attributes += [
|
||||||
|
MovedModule("winreg", "_winreg"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for attr in _moved_attributes:
|
||||||
|
setattr(_MovedItems, attr.name, attr)
|
||||||
|
if isinstance(attr, MovedModule):
|
||||||
|
_importer._add_module(attr, "moves." + attr.name)
|
||||||
|
del attr
|
||||||
|
|
||||||
|
_MovedItems._moved_attributes = _moved_attributes
|
||||||
|
|
||||||
|
moves = _MovedItems(__name__ + ".moves")
|
||||||
|
_importer._add_module(moves, "moves")
|
||||||
|
|
||||||
|
|
||||||
|
class Module_six_moves_urllib_parse(_LazyModule):
|
||||||
|
|
||||||
|
"""Lazy loading of moved objects in six.moves.urllib_parse"""
|
||||||
|
|
||||||
|
|
||||||
|
_urllib_parse_moved_attributes = [
|
||||||
|
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("urljoin", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("urlparse", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("quote", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"),
|
||||||
|
MovedAttribute("urlencode", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("splitquery", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("splittag", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("splituser", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("splitvalue", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_params", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_query", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
|
||||||
|
]
|
||||||
|
for attr in _urllib_parse_moved_attributes:
|
||||||
|
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
||||||
|
del attr
|
||||||
|
|
||||||
|
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
|
||||||
|
|
||||||
|
_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
|
||||||
|
"moves.urllib_parse", "moves.urllib.parse")
|
||||||
|
|
||||||
|
|
||||||
|
class Module_six_moves_urllib_error(_LazyModule):
|
||||||
|
|
||||||
|
"""Lazy loading of moved objects in six.moves.urllib_error"""
|
||||||
|
|
||||||
|
|
||||||
|
_urllib_error_moved_attributes = [
|
||||||
|
MovedAttribute("URLError", "urllib2", "urllib.error"),
|
||||||
|
MovedAttribute("HTTPError", "urllib2", "urllib.error"),
|
||||||
|
MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
|
||||||
|
]
|
||||||
|
for attr in _urllib_error_moved_attributes:
|
||||||
|
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
||||||
|
del attr
|
||||||
|
|
||||||
|
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
|
||||||
|
|
||||||
|
_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
|
||||||
|
"moves.urllib_error", "moves.urllib.error")
|
||||||
|
|
||||||
|
|
||||||
|
class Module_six_moves_urllib_request(_LazyModule):
|
||||||
|
|
||||||
|
"""Lazy loading of moved objects in six.moves.urllib_request"""
|
||||||
|
|
||||||
|
|
||||||
|
_urllib_request_moved_attributes = [
|
||||||
|
MovedAttribute("urlopen", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("install_opener", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("build_opener", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("pathname2url", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("url2pathname", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("getproxies", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("Request", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("FileHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("urlretrieve", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
|
||||||
|
MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
|
||||||
|
]
|
||||||
|
for attr in _urllib_request_moved_attributes:
|
||||||
|
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
||||||
|
del attr
|
||||||
|
|
||||||
|
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
|
||||||
|
|
||||||
|
_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
|
||||||
|
"moves.urllib_request", "moves.urllib.request")
|
||||||
|
|
||||||
|
|
||||||
|
class Module_six_moves_urllib_response(_LazyModule):
|
||||||
|
|
||||||
|
"""Lazy loading of moved objects in six.moves.urllib_response"""
|
||||||
|
|
||||||
|
|
||||||
|
_urllib_response_moved_attributes = [
|
||||||
|
MovedAttribute("addbase", "urllib", "urllib.response"),
|
||||||
|
MovedAttribute("addclosehook", "urllib", "urllib.response"),
|
||||||
|
MovedAttribute("addinfo", "urllib", "urllib.response"),
|
||||||
|
MovedAttribute("addinfourl", "urllib", "urllib.response"),
|
||||||
|
]
|
||||||
|
for attr in _urllib_response_moved_attributes:
|
||||||
|
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
||||||
|
del attr
|
||||||
|
|
||||||
|
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
|
||||||
|
|
||||||
|
_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
|
||||||
|
"moves.urllib_response", "moves.urllib.response")
|
||||||
|
|
||||||
|
|
||||||
|
class Module_six_moves_urllib_robotparser(_LazyModule):
|
||||||
|
|
||||||
|
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
|
||||||
|
|
||||||
|
|
||||||
|
_urllib_robotparser_moved_attributes = [
|
||||||
|
MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
|
||||||
|
]
|
||||||
|
for attr in _urllib_robotparser_moved_attributes:
|
||||||
|
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
||||||
|
del attr
|
||||||
|
|
||||||
|
Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
|
||||||
|
|
||||||
|
_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
|
||||||
|
"moves.urllib_robotparser", "moves.urllib.robotparser")
|
||||||
|
|
||||||
|
|
||||||
|
class Module_six_moves_urllib(types.ModuleType):
|
||||||
|
|
||||||
|
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
|
||||||
|
__path__ = [] # mark as package
|
||||||
|
parse = _importer._get_module("moves.urllib_parse")
|
||||||
|
error = _importer._get_module("moves.urllib_error")
|
||||||
|
request = _importer._get_module("moves.urllib_request")
|
||||||
|
response = _importer._get_module("moves.urllib_response")
|
||||||
|
robotparser = _importer._get_module("moves.urllib_robotparser")
|
||||||
|
|
||||||
|
def __dir__(self):
|
||||||
|
return ['parse', 'error', 'request', 'response', 'robotparser']
|
||||||
|
|
||||||
|
_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
|
||||||
|
"moves.urllib")
|
||||||
|
|
||||||
|
|
||||||
|
def add_move(move):
|
||||||
|
"""Add an item to six.moves."""
|
||||||
|
setattr(_MovedItems, move.name, move)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_move(name):
|
||||||
|
"""Remove item from six.moves."""
|
||||||
|
try:
|
||||||
|
delattr(_MovedItems, name)
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
del moves.__dict__[name]
|
||||||
|
except KeyError:
|
||||||
|
raise AttributeError("no such move, %r" % (name,))
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
_meth_func = "__func__"
|
||||||
|
_meth_self = "__self__"
|
||||||
|
|
||||||
|
_func_closure = "__closure__"
|
||||||
|
_func_code = "__code__"
|
||||||
|
_func_defaults = "__defaults__"
|
||||||
|
_func_globals = "__globals__"
|
||||||
|
else:
|
||||||
|
_meth_func = "im_func"
|
||||||
|
_meth_self = "im_self"
|
||||||
|
|
||||||
|
_func_closure = "func_closure"
|
||||||
|
_func_code = "func_code"
|
||||||
|
_func_defaults = "func_defaults"
|
||||||
|
_func_globals = "func_globals"
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
advance_iterator = next
|
||||||
|
except NameError:
|
||||||
|
def advance_iterator(it):
|
||||||
|
return it.next()
|
||||||
|
next = advance_iterator
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
callable = callable
|
||||||
|
except NameError:
|
||||||
|
def callable(obj):
|
||||||
|
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
def get_unbound_function(unbound):
|
||||||
|
return unbound
|
||||||
|
|
||||||
|
create_bound_method = types.MethodType
|
||||||
|
|
||||||
|
def create_unbound_method(func, cls):
|
||||||
|
return func
|
||||||
|
|
||||||
|
Iterator = object
|
||||||
|
else:
|
||||||
|
def get_unbound_function(unbound):
|
||||||
|
return unbound.im_func
|
||||||
|
|
||||||
|
def create_bound_method(func, obj):
|
||||||
|
return types.MethodType(func, obj, obj.__class__)
|
||||||
|
|
||||||
|
def create_unbound_method(func, cls):
|
||||||
|
return types.MethodType(func, None, cls)
|
||||||
|
|
||||||
|
class Iterator(object):
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return type(self).__next__(self)
|
||||||
|
|
||||||
|
callable = callable
|
||||||
|
_add_doc(get_unbound_function,
|
||||||
|
"""Get the function out of a possibly unbound function""")
|
||||||
|
|
||||||
|
|
||||||
|
get_method_function = operator.attrgetter(_meth_func)
|
||||||
|
get_method_self = operator.attrgetter(_meth_self)
|
||||||
|
get_function_closure = operator.attrgetter(_func_closure)
|
||||||
|
get_function_code = operator.attrgetter(_func_code)
|
||||||
|
get_function_defaults = operator.attrgetter(_func_defaults)
|
||||||
|
get_function_globals = operator.attrgetter(_func_globals)
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
def iterkeys(d, **kw):
|
||||||
|
return iter(d.keys(**kw))
|
||||||
|
|
||||||
|
def itervalues(d, **kw):
|
||||||
|
return iter(d.values(**kw))
|
||||||
|
|
||||||
|
def iteritems(d, **kw):
|
||||||
|
return iter(d.items(**kw))
|
||||||
|
|
||||||
|
def iterlists(d, **kw):
|
||||||
|
return iter(d.lists(**kw))
|
||||||
|
|
||||||
|
viewkeys = operator.methodcaller("keys")
|
||||||
|
|
||||||
|
viewvalues = operator.methodcaller("values")
|
||||||
|
|
||||||
|
viewitems = operator.methodcaller("items")
|
||||||
|
else:
|
||||||
|
def iterkeys(d, **kw):
|
||||||
|
return d.iterkeys(**kw)
|
||||||
|
|
||||||
|
def itervalues(d, **kw):
|
||||||
|
return d.itervalues(**kw)
|
||||||
|
|
||||||
|
def iteritems(d, **kw):
|
||||||
|
return d.iteritems(**kw)
|
||||||
|
|
||||||
|
def iterlists(d, **kw):
|
||||||
|
return d.iterlists(**kw)
|
||||||
|
|
||||||
|
viewkeys = operator.methodcaller("viewkeys")
|
||||||
|
|
||||||
|
viewvalues = operator.methodcaller("viewvalues")
|
||||||
|
|
||||||
|
viewitems = operator.methodcaller("viewitems")
|
||||||
|
|
||||||
|
_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
|
||||||
|
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
|
||||||
|
_add_doc(iteritems,
|
||||||
|
"Return an iterator over the (key, value) pairs of a dictionary.")
|
||||||
|
_add_doc(iterlists,
|
||||||
|
"Return an iterator over the (key, [values]) pairs of a dictionary.")
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
def b(s):
|
||||||
|
return s.encode("latin-1")
|
||||||
|
|
||||||
|
def u(s):
|
||||||
|
return s
|
||||||
|
unichr = chr
|
||||||
|
import struct
|
||||||
|
int2byte = struct.Struct(">B").pack
|
||||||
|
del struct
|
||||||
|
byte2int = operator.itemgetter(0)
|
||||||
|
indexbytes = operator.getitem
|
||||||
|
iterbytes = iter
|
||||||
|
import io
|
||||||
|
StringIO = io.StringIO
|
||||||
|
BytesIO = io.BytesIO
|
||||||
|
del io
|
||||||
|
_assertCountEqual = "assertCountEqual"
|
||||||
|
if sys.version_info[1] <= 1:
|
||||||
|
_assertRaisesRegex = "assertRaisesRegexp"
|
||||||
|
_assertRegex = "assertRegexpMatches"
|
||||||
|
_assertNotRegex = "assertNotRegexpMatches"
|
||||||
|
else:
|
||||||
|
_assertRaisesRegex = "assertRaisesRegex"
|
||||||
|
_assertRegex = "assertRegex"
|
||||||
|
_assertNotRegex = "assertNotRegex"
|
||||||
|
else:
|
||||||
|
def b(s):
|
||||||
|
return s
|
||||||
|
# Workaround for standalone backslash
|
||||||
|
|
||||||
|
def u(s):
|
||||||
|
return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
|
||||||
|
unichr = unichr
|
||||||
|
int2byte = chr
|
||||||
|
|
||||||
|
def byte2int(bs):
|
||||||
|
return ord(bs[0])
|
||||||
|
|
||||||
|
def indexbytes(buf, i):
|
||||||
|
return ord(buf[i])
|
||||||
|
iterbytes = functools.partial(itertools.imap, ord)
|
||||||
|
import StringIO
|
||||||
|
StringIO = BytesIO = StringIO.StringIO
|
||||||
|
_assertCountEqual = "assertItemsEqual"
|
||||||
|
_assertRaisesRegex = "assertRaisesRegexp"
|
||||||
|
_assertRegex = "assertRegexpMatches"
|
||||||
|
_assertNotRegex = "assertNotRegexpMatches"
|
||||||
|
_add_doc(b, """Byte literal""")
|
||||||
|
_add_doc(u, """Text literal""")
|
||||||
|
|
||||||
|
|
||||||
|
def assertCountEqual(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertCountEqual)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def assertRaisesRegex(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertRaisesRegex)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def assertRegex(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertRegex)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def assertNotRegex(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertNotRegex)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
exec_ = getattr(moves.builtins, "exec")
|
||||||
|
|
||||||
|
def reraise(tp, value, tb=None):
|
||||||
|
try:
|
||||||
|
if value is None:
|
||||||
|
value = tp()
|
||||||
|
if value.__traceback__ is not tb:
|
||||||
|
raise value.with_traceback(tb)
|
||||||
|
raise value
|
||||||
|
finally:
|
||||||
|
value = None
|
||||||
|
tb = None
|
||||||
|
|
||||||
|
else:
|
||||||
|
def exec_(_code_, _globs_=None, _locs_=None):
|
||||||
|
"""Execute code in a namespace."""
|
||||||
|
if _globs_ is None:
|
||||||
|
frame = sys._getframe(1)
|
||||||
|
_globs_ = frame.f_globals
|
||||||
|
if _locs_ is None:
|
||||||
|
_locs_ = frame.f_locals
|
||||||
|
del frame
|
||||||
|
elif _locs_ is None:
|
||||||
|
_locs_ = _globs_
|
||||||
|
exec("""exec _code_ in _globs_, _locs_""")
|
||||||
|
|
||||||
|
exec_("""def reraise(tp, value, tb=None):
|
||||||
|
try:
|
||||||
|
raise tp, value, tb
|
||||||
|
finally:
|
||||||
|
tb = None
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info[:2] > (3,):
|
||||||
|
exec_("""def raise_from(value, from_value):
|
||||||
|
try:
|
||||||
|
raise value from from_value
|
||||||
|
finally:
|
||||||
|
value = None
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
def raise_from(value, from_value):
|
||||||
|
raise value
|
||||||
|
|
||||||
|
|
||||||
|
print_ = getattr(moves.builtins, "print", None)
|
||||||
|
if print_ is None:
|
||||||
|
def print_(*args, **kwargs):
|
||||||
|
"""The new-style print function for Python 2.4 and 2.5."""
|
||||||
|
fp = kwargs.pop("file", sys.stdout)
|
||||||
|
if fp is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
def write(data):
|
||||||
|
if not isinstance(data, basestring):
|
||||||
|
data = str(data)
|
||||||
|
# If the file has an encoding, encode unicode with it.
|
||||||
|
if (isinstance(fp, file) and
|
||||||
|
isinstance(data, unicode) and
|
||||||
|
fp.encoding is not None):
|
||||||
|
errors = getattr(fp, "errors", None)
|
||||||
|
if errors is None:
|
||||||
|
errors = "strict"
|
||||||
|
data = data.encode(fp.encoding, errors)
|
||||||
|
fp.write(data)
|
||||||
|
want_unicode = False
|
||||||
|
sep = kwargs.pop("sep", None)
|
||||||
|
if sep is not None:
|
||||||
|
if isinstance(sep, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
elif not isinstance(sep, str):
|
||||||
|
raise TypeError("sep must be None or a string")
|
||||||
|
end = kwargs.pop("end", None)
|
||||||
|
if end is not None:
|
||||||
|
if isinstance(end, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
elif not isinstance(end, str):
|
||||||
|
raise TypeError("end must be None or a string")
|
||||||
|
if kwargs:
|
||||||
|
raise TypeError("invalid keyword arguments to print()")
|
||||||
|
if not want_unicode:
|
||||||
|
for arg in args:
|
||||||
|
if isinstance(arg, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
break
|
||||||
|
if want_unicode:
|
||||||
|
newline = unicode("\n")
|
||||||
|
space = unicode(" ")
|
||||||
|
else:
|
||||||
|
newline = "\n"
|
||||||
|
space = " "
|
||||||
|
if sep is None:
|
||||||
|
sep = space
|
||||||
|
if end is None:
|
||||||
|
end = newline
|
||||||
|
for i, arg in enumerate(args):
|
||||||
|
if i:
|
||||||
|
write(sep)
|
||||||
|
write(arg)
|
||||||
|
write(end)
|
||||||
|
if sys.version_info[:2] < (3, 3):
|
||||||
|
_print = print_
|
||||||
|
|
||||||
|
def print_(*args, **kwargs):
|
||||||
|
fp = kwargs.get("file", sys.stdout)
|
||||||
|
flush = kwargs.pop("flush", False)
|
||||||
|
_print(*args, **kwargs)
|
||||||
|
if flush and fp is not None:
|
||||||
|
fp.flush()
|
||||||
|
|
||||||
|
_add_doc(reraise, """Reraise an exception.""")
|
||||||
|
|
||||||
|
if sys.version_info[0:2] < (3, 4):
|
||||||
|
# This does exactly the same what the :func:`py3:functools.update_wrapper`
|
||||||
|
# function does on Python versions after 3.2. It sets the ``__wrapped__``
|
||||||
|
# attribute on ``wrapper`` object and it doesn't raise an error if any of
|
||||||
|
# the attributes mentioned in ``assigned`` and ``updated`` are missing on
|
||||||
|
# ``wrapped`` object.
|
||||||
|
def _update_wrapper(wrapper, wrapped,
|
||||||
|
assigned=functools.WRAPPER_ASSIGNMENTS,
|
||||||
|
updated=functools.WRAPPER_UPDATES):
|
||||||
|
for attr in assigned:
|
||||||
|
try:
|
||||||
|
value = getattr(wrapped, attr)
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
setattr(wrapper, attr, value)
|
||||||
|
for attr in updated:
|
||||||
|
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
|
||||||
|
wrapper.__wrapped__ = wrapped
|
||||||
|
return wrapper
|
||||||
|
_update_wrapper.__doc__ = functools.update_wrapper.__doc__
|
||||||
|
|
||||||
|
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
|
||||||
|
updated=functools.WRAPPER_UPDATES):
|
||||||
|
return functools.partial(_update_wrapper, wrapped=wrapped,
|
||||||
|
assigned=assigned, updated=updated)
|
||||||
|
wraps.__doc__ = functools.wraps.__doc__
|
||||||
|
|
||||||
|
else:
|
||||||
|
wraps = functools.wraps
|
||||||
|
|
||||||
|
|
||||||
|
def with_metaclass(meta, *bases):
|
||||||
|
"""Create a base class with a metaclass."""
|
||||||
|
# This requires a bit of explanation: the basic idea is to make a dummy
|
||||||
|
# metaclass for one level of class instantiation that replaces itself with
|
||||||
|
# the actual metaclass.
|
||||||
|
class metaclass(type):
|
||||||
|
|
||||||
|
def __new__(cls, name, this_bases, d):
|
||||||
|
if sys.version_info[:2] >= (3, 7):
|
||||||
|
# This version introduced PEP 560 that requires a bit
|
||||||
|
# of extra care (we mimic what is done by __build_class__).
|
||||||
|
resolved_bases = types.resolve_bases(bases)
|
||||||
|
if resolved_bases is not bases:
|
||||||
|
d['__orig_bases__'] = bases
|
||||||
|
else:
|
||||||
|
resolved_bases = bases
|
||||||
|
return meta(name, resolved_bases, d)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __prepare__(cls, name, this_bases):
|
||||||
|
return meta.__prepare__(name, bases)
|
||||||
|
return type.__new__(metaclass, 'temporary_class', (), {})
|
||||||
|
|
||||||
|
|
||||||
|
def add_metaclass(metaclass):
|
||||||
|
"""Class decorator for creating a class with a metaclass."""
|
||||||
|
def wrapper(cls):
|
||||||
|
orig_vars = cls.__dict__.copy()
|
||||||
|
slots = orig_vars.get('__slots__')
|
||||||
|
if slots is not None:
|
||||||
|
if isinstance(slots, str):
|
||||||
|
slots = [slots]
|
||||||
|
for slots_var in slots:
|
||||||
|
orig_vars.pop(slots_var)
|
||||||
|
orig_vars.pop('__dict__', None)
|
||||||
|
orig_vars.pop('__weakref__', None)
|
||||||
|
if hasattr(cls, '__qualname__'):
|
||||||
|
orig_vars['__qualname__'] = cls.__qualname__
|
||||||
|
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_binary(s, encoding='utf-8', errors='strict'):
|
||||||
|
"""Coerce **s** to six.binary_type.
|
||||||
|
|
||||||
|
For Python 2:
|
||||||
|
- `unicode` -> encoded to `str`
|
||||||
|
- `str` -> `str`
|
||||||
|
|
||||||
|
For Python 3:
|
||||||
|
- `str` -> encoded to `bytes`
|
||||||
|
- `bytes` -> `bytes`
|
||||||
|
"""
|
||||||
|
if isinstance(s, binary_type):
|
||||||
|
return s
|
||||||
|
if isinstance(s, text_type):
|
||||||
|
return s.encode(encoding, errors)
|
||||||
|
raise TypeError("not expecting type '%s'" % type(s))
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_str(s, encoding='utf-8', errors='strict'):
|
||||||
|
"""Coerce *s* to `str`.
|
||||||
|
|
||||||
|
For Python 2:
|
||||||
|
- `unicode` -> encoded to `str`
|
||||||
|
- `str` -> `str`
|
||||||
|
|
||||||
|
For Python 3:
|
||||||
|
- `str` -> `str`
|
||||||
|
- `bytes` -> decoded to `str`
|
||||||
|
"""
|
||||||
|
# Optimization: Fast return for the common case.
|
||||||
|
if type(s) is str:
|
||||||
|
return s
|
||||||
|
if PY2 and isinstance(s, text_type):
|
||||||
|
return s.encode(encoding, errors)
|
||||||
|
elif PY3 and isinstance(s, binary_type):
|
||||||
|
return s.decode(encoding, errors)
|
||||||
|
elif not isinstance(s, (text_type, binary_type)):
|
||||||
|
raise TypeError("not expecting type '%s'" % type(s))
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_text(s, encoding='utf-8', errors='strict'):
|
||||||
|
"""Coerce *s* to six.text_type.
|
||||||
|
|
||||||
|
For Python 2:
|
||||||
|
- `unicode` -> `unicode`
|
||||||
|
- `str` -> `unicode`
|
||||||
|
|
||||||
|
For Python 3:
|
||||||
|
- `str` -> `str`
|
||||||
|
- `bytes` -> decoded to `str`
|
||||||
|
"""
|
||||||
|
if isinstance(s, binary_type):
|
||||||
|
return s.decode(encoding, errors)
|
||||||
|
elif isinstance(s, text_type):
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
raise TypeError("not expecting type '%s'" % type(s))
|
||||||
|
|
||||||
|
|
||||||
|
def python_2_unicode_compatible(klass):
|
||||||
|
"""
|
||||||
|
A class decorator that defines __unicode__ and __str__ methods under Python 2.
|
||||||
|
Under Python 3 it does nothing.
|
||||||
|
|
||||||
|
To support Python 2 and 3 with a single code base, define a __str__ method
|
||||||
|
returning text and apply this decorator to the class.
|
||||||
|
"""
|
||||||
|
if PY2:
|
||||||
|
if '__str__' not in klass.__dict__:
|
||||||
|
raise ValueError("@python_2_unicode_compatible cannot be applied "
|
||||||
|
"to %s because it doesn't define __str__()." %
|
||||||
|
klass.__name__)
|
||||||
|
klass.__unicode__ = klass.__str__
|
||||||
|
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
|
||||||
|
return klass
|
||||||
|
|
||||||
|
|
||||||
|
# Complete the moves implementation.
|
||||||
|
# This code is at the end of this module to speed up module loading.
|
||||||
|
# Turn this module into a package.
|
||||||
|
__path__ = [] # required for PEP 302 and PEP 451
|
||||||
|
__package__ = __name__ # see PEP 366 @ReservedAssignment
|
||||||
|
if globals().get("__spec__") is not None:
|
||||||
|
__spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
|
||||||
|
# Remove other six meta path importers, since they cause problems. This can
|
||||||
|
# happen if six is removed from sys.modules and then reloaded. (Setuptools does
|
||||||
|
# this for some reason.)
|
||||||
|
if sys.meta_path:
|
||||||
|
for i, importer in enumerate(sys.meta_path):
|
||||||
|
# Here's some real nastiness: Another "instance" of the six module might
|
||||||
|
# be floating around. Therefore, we can't use isinstance() to check for
|
||||||
|
# the six meta path importer, since the other six instance will have
|
||||||
|
# inserted an importer with different class.
|
||||||
|
if (type(importer).__name__ == "_SixMetaPathImporter" and
|
||||||
|
importer.name == __name__):
|
||||||
|
del sys.meta_path[i]
|
||||||
|
break
|
||||||
|
del i, importer
|
||||||
|
# Finally, add the importer to the meta path import hook.
|
||||||
|
sys.meta_path.append(_importer)
|
Loading…
x
Reference in New Issue
Block a user