odps/compat.py (299 lines of code) (raw):
# -*- coding: utf-8 -*-
# Copyright 1999-2025 Alibaba Group Holding Ltd.
#
# 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.
import itertools
import logging.config
import os
import platform
import sys
import warnings
try:
if sys.version_info[:2] < (3, 3):
import xml.etree.cElementTree as ElementTree
else:
import xml.etree.ElementTree as ElementTree
except ImportError:
import xml.etree.ElementTree as ElementTree
try:
ElementTreeParseError = getattr(ElementTree, "ParseError")
except AttributeError:
ElementTreeParseError = getattr(ElementTree, "XMLParserError")
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable
from unicodedata import east_asian_width
from .lib import six
PY27 = six.PY2 and sys.version_info[1] == 7
LESS_PY32 = sys.version_info[:2] < (3, 2)
LESS_PY33 = sys.version_info[:2] < (3, 3)
LESS_PY34 = sys.version_info[:2] < (3, 4)
LESS_PY35 = sys.version_info[:2] < (3, 5)
LESS_PY36 = sys.version_info[:2] < (3, 6)
PYPY = platform.python_implementation().lower() == "pypy"
SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2
# Definition of East Asian Width
# http://unicode.org/reports/tr11/
# Ambiguous width can be changed by option
_EAW_MAP = {"Na": 1, "N": 1, "W": 2, "F": 2, "H": 1}
import decimal
DECIMAL_TYPES = [
decimal.Decimal,
]
import json # don't remove
try:
TimeoutError = TimeoutError
except NameError:
TimeoutError = type("TimeoutError", (RuntimeError,), {})
if six.PY3:
lrange = lambda *x: list(range(*x))
lzip = lambda *x: list(zip(*x))
lkeys = lambda x: list(x.keys())
lvalues = lambda x: list(x.values())
litems = lambda x: list(x.items())
irange = range
izip = zip
long_type = int
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
if LESS_PY36:
from .lib import enum
else:
import enum
if LESS_PY33:
try:
import cdecimal as decimal
DECIMAL_TYPES.append(decimal.Decimal)
except:
import decimal
else:
import decimal
def u(s):
return s
def strlen(data, encoding=None):
# encoding is for compat with PY2
return len(data)
def east_asian_len(data, encoding=None, ambiguous_width=1):
"""
Calculate display width considering unicode East Asian Width
"""
if isinstance(data, six.text_type):
return sum(
[_EAW_MAP.get(east_asian_width(c), ambiguous_width) for c in data]
)
else:
return len(data)
dictconfig = lambda config: logging.config.dictConfig(config)
import builtins
from concurrent import futures # don't remove
from .lib import cgi_compat as cgi
UnsupportedOperation = io.UnsupportedOperation
try:
from .lib.version import Version
except BaseException:
from distutils.version import LooseVersion as Version
from threading import Semaphore
else:
lrange = range
lzip = zip
lkeys = lambda x: x.keys()
lvalues = lambda x: x.values()
litems = lambda x: x.items()
irange = xrange
izip = itertools.izip
long_type = long
from .lib import enum
try:
import cdecimal as decimal
DECIMAL_TYPES.append(decimal.Decimal)
except ImportError:
import decimal
try:
import cStringIO as StringIO
except ImportError:
import StringIO
StringIO = BytesIO = StringIO.StringIO
def u(s):
return unicode(s, "unicode_escape")
def strlen(data, encoding=None):
try:
data = data.decode(encoding)
except UnicodeError:
pass
return len(data)
def east_asian_len(data, encoding=None, ambiguous_width=1):
"""
Calculate display width considering unicode East Asian Width
"""
if isinstance(data, six.text_type):
try:
data = data.decode(encoding)
except UnicodeError:
pass
return sum(
[_EAW_MAP.get(east_asian_width(c), ambiguous_width) for c in data]
)
else:
return len(data)
dictconfig = lambda config: logging.config.dictConfig(config)
import cgi
import __builtin__ as builtins # don't remove
from .lib import futures # don't remove
UnsupportedOperation = type("UnsupportedOperation", (OSError, ValueError), {})
from distutils.version import LooseVersion as Version
from threading import _Semaphore as _PySemaphore
from .lib.monotonic import monotonic
class Semaphore(_PySemaphore):
def acquire(self, blocking=True, timeout=None):
if not blocking and timeout is not None:
raise ValueError("can't specify timeout for non-blocking acquire")
rc = False
endtime = None
with self.__cond:
while self.__value == 0:
if not blocking:
break
if timeout is not None:
if endtime is None:
endtime = monotonic() + timeout
else:
timeout = endtime - monotonic()
if timeout <= 0:
break
self.__cond.wait(timeout)
else:
self.__value -= 1
rc = True
return rc
if LESS_PY32:
try:
from .tests.dictconfig import dictConfig
dictconfig = lambda config: dictConfig(config)
except ImportError:
pass
if six.PY3:
from contextlib import suppress
else:
from contextlib import contextmanager
@contextmanager
def suppress(*exceptions):
try:
yield
except exceptions:
pass
Enum = enum.Enum
DECIMAL_TYPES = tuple(DECIMAL_TYPES)
Decimal = decimal.Decimal
try:
import pandas as pd
if not hasattr(pd.DataFrame, "sort_values"):
pd.DataFrame.sort_values = pd.DataFrame.sort
from pandas.core.internals import blocks as pd_blocks
if not hasattr(pd_blocks, "new_block"):
pd_blocks.new_block = pd_blocks.make_block
if not hasattr(pd.RangeIndex, "start"):
pd.RangeIndex.start = property(fget=lambda x: x._start)
pd.RangeIndex.stop = property(fget=lambda x: x._stop)
pd.RangeIndex.step = property(fget=lambda x: x._step)
except (ImportError, ValueError) as ex:
if not isinstance(ex, ImportError):
warnings.warn("Import of pandas skipped. Reasons: %s" % str(ex))
try:
import numpy as np
if not hasattr(np, "float_"):
np.float_ = np.float64
if not hasattr(np, "int_"):
np.int_ = np.int64
except ImportError:
pass
if sys.version_info[0] > 2:
# workaround for polluted sys.path due to some packages
try:
import http.client
except ImportError:
sys.modules.pop("http", None)
old_path = list(sys.path)
sys.path = [os.path.dirname(os.__file__)] + sys.path
import http.client
sys.path = old_path
import datetime
from .lib.ext_types import Monthdelta
from .lib.lib_utils import dir2, getargspec, getfullargspec, isvalidattr
from .lib.six.moves import configparser as ConfigParser
from .lib.six.moves import cPickle as pickle
from .lib.six.moves import reduce, reload_module
from .lib.six.moves.queue import Empty, Queue
from .lib.six.moves.urllib.parse import (
parse_qsl,
quote,
quote_plus,
unquote,
urlencode,
urlparse,
)
from .lib.six.moves.urllib.request import urlretrieve
class _FixedOffset(datetime.tzinfo):
"""
A class building tzinfo objects for fixed-offset time zones.
Note that FixedOffset(0, "UTC") is a different way to build a
UTC tzinfo object.
"""
def __init__(self, offset, name=None):
self.__offset = datetime.timedelta(minutes=offset)
self.__name = name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return _ZERO_TIMEDELTA
try:
import zoneinfo
utc = zoneinfo.ZoneInfo("UTC")
FixedOffset = _FixedOffset
except ImportError:
try:
import pytz
utc = pytz.utc
FixedOffset = pytz._FixedOffset
except ImportError:
_ZERO_TIMEDELTA = datetime.timedelta(0)
FixedOffset = _FixedOffset
utc = FixedOffset(0, "UTC")
try:
from email.utils import parsedate_to_datetime
except ImportError:
import datetime
from email.utils import parsedate_tz
def parsedate_to_datetime(data):
dt_tuple_with_tz = parsedate_tz(data)
dtuple = dt_tuple_with_tz[:-1]
tz = dt_tuple_with_tz[-1]
if tz is None:
return datetime.datetime(*dtuple[:6])
return datetime.datetime(*dtuple[:6], tzinfo=FixedOffset(tz / 60.0))
if not hasattr(datetime, "UTC"):
datetime_utcnow = datetime.datetime.utcnow
else:
def datetime_utcnow():
return datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
__all__ = [
"DECIMAL_TYPES",
"ConfigParser",
"Decimal",
"ElementTree",
"ElementTreeParseError",
"Empty",
"Enum",
"FixedOffset",
"Iterable",
"Monthdelta",
"Queue",
"Semaphore",
"TimeoutError",
"Version",
"builtins",
"cgi",
"datetime_utcnow",
"decimal",
"dictconfig",
"logging.config",
"parse_qsl",
"parsedate_to_datetime",
"pickle",
"quote",
"quote_plus",
"reduce",
"reload_module",
"suppress",
"sys",
"unquote",
"urlencode",
"urlparse",
"urlretrieve",
"utc",
]