You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					632 lines
				
				18 KiB
			
		
		
			
		
	
	
					632 lines
				
				18 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								# util/compat.py
							 | 
						||
| 
								 | 
							
								# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
							 | 
						||
| 
								 | 
							
								# <see AUTHORS file>
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This module is part of SQLAlchemy and is released under
							 | 
						||
| 
								 | 
							
								# the MIT License: https://www.opensource.org/licenses/mit-license.php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""Handle Python version/platform incompatibilities."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import collections
							 | 
						||
| 
								 | 
							
								import contextlib
							 | 
						||
| 
								 | 
							
								import inspect
							 | 
						||
| 
								 | 
							
								import operator
							 | 
						||
| 
								 | 
							
								import platform
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								py39 = sys.version_info >= (3, 9)
							 | 
						||
| 
								 | 
							
								py38 = sys.version_info >= (3, 8)
							 | 
						||
| 
								 | 
							
								py37 = sys.version_info >= (3, 7)
							 | 
						||
| 
								 | 
							
								py3k = sys.version_info >= (3, 0)
							 | 
						||
| 
								 | 
							
								py2k = sys.version_info < (3, 0)
							 | 
						||
| 
								 | 
							
								pypy = platform.python_implementation() == "PyPy"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								cpython = platform.python_implementation() == "CPython"
							 | 
						||
| 
								 | 
							
								win32 = sys.platform.startswith("win")
							 | 
						||
| 
								 | 
							
								osx = sys.platform.startswith("darwin")
							 | 
						||
| 
								 | 
							
								arm = "aarch" in platform.machine().lower()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								has_refcount_gc = bool(cpython)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								contextmanager = contextlib.contextmanager
							 | 
						||
| 
								 | 
							
								dottedgetter = operator.attrgetter
							 | 
						||
| 
								 | 
							
								namedtuple = collections.namedtuple
							 | 
						||
| 
								 | 
							
								next = next  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								FullArgSpec = collections.namedtuple(
							 | 
						||
| 
								 | 
							
								    "FullArgSpec",
							 | 
						||
| 
								 | 
							
								    [
							 | 
						||
| 
								 | 
							
								        "args",
							 | 
						||
| 
								 | 
							
								        "varargs",
							 | 
						||
| 
								 | 
							
								        "varkw",
							 | 
						||
| 
								 | 
							
								        "defaults",
							 | 
						||
| 
								 | 
							
								        "kwonlyargs",
							 | 
						||
| 
								 | 
							
								        "kwonlydefaults",
							 | 
						||
| 
								 | 
							
								        "annotations",
							 | 
						||
| 
								 | 
							
								    ],
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class nullcontext(object):
							 | 
						||
| 
								 | 
							
								    """Context manager that does no additional processing.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Vendored from Python 3.7.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, enter_result=None):
							 | 
						||
| 
								 | 
							
								        self.enter_result = enter_result
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __enter__(self):
							 | 
						||
| 
								 | 
							
								        return self.enter_result
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __exit__(self, *excinfo):
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								try:
							 | 
						||
| 
								 | 
							
								    import threading
							 | 
						||
| 
								 | 
							
								except ImportError:
							 | 
						||
| 
								 | 
							
								    import dummy_threading as threading  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def inspect_getfullargspec(func):
							 | 
						||
| 
								 | 
							
								    """Fully vendored version of getfullargspec from Python 3.3."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if inspect.ismethod(func):
							 | 
						||
| 
								 | 
							
								        func = func.__func__
							 | 
						||
| 
								 | 
							
								    if not inspect.isfunction(func):
							 | 
						||
| 
								 | 
							
								        raise TypeError("{!r} is not a Python function".format(func))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    co = func.__code__
							 | 
						||
| 
								 | 
							
								    if not inspect.iscode(co):
							 | 
						||
| 
								 | 
							
								        raise TypeError("{!r} is not a code object".format(co))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    nargs = co.co_argcount
							 | 
						||
| 
								 | 
							
								    names = co.co_varnames
							 | 
						||
| 
								 | 
							
								    nkwargs = co.co_kwonlyargcount if py3k else 0
							 | 
						||
| 
								 | 
							
								    args = list(names[:nargs])
							 | 
						||
| 
								 | 
							
								    kwonlyargs = list(names[nargs : nargs + nkwargs])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    nargs += nkwargs
							 | 
						||
| 
								 | 
							
								    varargs = None
							 | 
						||
| 
								 | 
							
								    if co.co_flags & inspect.CO_VARARGS:
							 | 
						||
| 
								 | 
							
								        varargs = co.co_varnames[nargs]
							 | 
						||
| 
								 | 
							
								        nargs = nargs + 1
							 | 
						||
| 
								 | 
							
								    varkw = None
							 | 
						||
| 
								 | 
							
								    if co.co_flags & inspect.CO_VARKEYWORDS:
							 | 
						||
| 
								 | 
							
								        varkw = co.co_varnames[nargs]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return FullArgSpec(
							 | 
						||
| 
								 | 
							
								        args,
							 | 
						||
| 
								 | 
							
								        varargs,
							 | 
						||
| 
								 | 
							
								        varkw,
							 | 
						||
| 
								 | 
							
								        func.__defaults__,
							 | 
						||
| 
								 | 
							
								        kwonlyargs,
							 | 
						||
| 
								 | 
							
								        func.__kwdefaults__ if py3k else None,
							 | 
						||
| 
								 | 
							
								        func.__annotations__ if py3k else {},
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if py38:
							 | 
						||
| 
								 | 
							
								    from importlib import metadata as importlib_metadata
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								    import importlib_metadata  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def importlib_metadata_get(group):
							 | 
						||
| 
								 | 
							
								    ep = importlib_metadata.entry_points()
							 | 
						||
| 
								 | 
							
								    if hasattr(ep, "select"):
							 | 
						||
| 
								 | 
							
								        return ep.select(group=group)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return ep.get(group, ())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if py3k:
							 | 
						||
| 
								 | 
							
								    import base64
							 | 
						||
| 
								 | 
							
								    import builtins
							 | 
						||
| 
								 | 
							
								    import configparser
							 | 
						||
| 
								 | 
							
								    import itertools
							 | 
						||
| 
								 | 
							
								    import pickle
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    from functools import reduce
							 | 
						||
| 
								 | 
							
								    from io import BytesIO as byte_buffer
							 | 
						||
| 
								 | 
							
								    from io import StringIO
							 | 
						||
| 
								 | 
							
								    from itertools import zip_longest
							 | 
						||
| 
								 | 
							
								    from time import perf_counter
							 | 
						||
| 
								 | 
							
								    from urllib.parse import (
							 | 
						||
| 
								 | 
							
								        quote_plus,
							 | 
						||
| 
								 | 
							
								        unquote_plus,
							 | 
						||
| 
								 | 
							
								        parse_qsl,
							 | 
						||
| 
								 | 
							
								        quote,
							 | 
						||
| 
								 | 
							
								        unquote,
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    string_types = (str,)
							 | 
						||
| 
								 | 
							
								    binary_types = (bytes,)
							 | 
						||
| 
								 | 
							
								    binary_type = bytes
							 | 
						||
| 
								 | 
							
								    text_type = str
							 | 
						||
| 
								 | 
							
								    int_types = (int,)
							 | 
						||
| 
								 | 
							
								    iterbytes = iter
							 | 
						||
| 
								 | 
							
								    long_type = int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    itertools_filterfalse = itertools.filterfalse
							 | 
						||
| 
								 | 
							
								    itertools_filter = filter
							 | 
						||
| 
								 | 
							
								    itertools_imap = map
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    exec_ = getattr(builtins, "exec")
							 | 
						||
| 
								 | 
							
								    import_ = getattr(builtins, "__import__")
							 | 
						||
| 
								 | 
							
								    print_ = getattr(builtins, "print")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def b(s):
							 | 
						||
| 
								 | 
							
								        return s.encode("latin-1")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def b64decode(x):
							 | 
						||
| 
								 | 
							
								        return base64.b64decode(x.encode("ascii"))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def b64encode(x):
							 | 
						||
| 
								 | 
							
								        return base64.b64encode(x).decode("ascii")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def decode_backslashreplace(text, encoding):
							 | 
						||
| 
								 | 
							
								        return text.decode(encoding, errors="backslashreplace")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def cmp(a, b):
							 | 
						||
| 
								 | 
							
								        return (a > b) - (a < b)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def raise_(
							 | 
						||
| 
								 | 
							
								        exception, with_traceback=None, replace_context=None, from_=False
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        r"""implement "raise" with cause support.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param exception: exception to raise
							 | 
						||
| 
								 | 
							
								        :param with_traceback: will call exception.with_traceback()
							 | 
						||
| 
								 | 
							
								        :param replace_context: an as-yet-unsupported feature.  This is
							 | 
						||
| 
								 | 
							
								         an exception object which we are "replacing", e.g., it's our
							 | 
						||
| 
								 | 
							
								         "cause" but we don't want it printed.    Basically just what
							 | 
						||
| 
								 | 
							
								         ``__suppress_context__`` does but we don't want to suppress
							 | 
						||
| 
								 | 
							
								         the enclosing context, if any.  So for now we make it the
							 | 
						||
| 
								 | 
							
								         cause.
							 | 
						||
| 
								 | 
							
								        :param from\_: the cause.  this actually sets the cause and doesn't
							 | 
						||
| 
								 | 
							
								         hope to hide it someday.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if with_traceback is not None:
							 | 
						||
| 
								 | 
							
								            exception = exception.with_traceback(with_traceback)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if from_ is not False:
							 | 
						||
| 
								 | 
							
								            exception.__cause__ = from_
							 | 
						||
| 
								 | 
							
								        elif replace_context is not None:
							 | 
						||
| 
								 | 
							
								            # no good solution here, we would like to have the exception
							 | 
						||
| 
								 | 
							
								            # have only the context of replace_context.__context__ so that the
							 | 
						||
| 
								 | 
							
								            # intermediary exception does not change, but we can't figure
							 | 
						||
| 
								 | 
							
								            # that out.
							 | 
						||
| 
								 | 
							
								            exception.__cause__ = replace_context
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            raise exception
							 | 
						||
| 
								 | 
							
								        finally:
							 | 
						||
| 
								 | 
							
								            # credit to
							 | 
						||
| 
								 | 
							
								            # https://cosmicpercolator.com/2016/01/13/exception-leaks-in-python-2-and-3/
							 | 
						||
| 
								 | 
							
								            # as the __traceback__ object creates a cycle
							 | 
						||
| 
								 | 
							
								            del exception, replace_context, from_, with_traceback
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def u(s):
							 | 
						||
| 
								 | 
							
								        return s
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def ue(s):
							 | 
						||
| 
								 | 
							
								        return s
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    from typing import TYPE_CHECKING
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Unused. Kept for backwards compatibility.
							 | 
						||
| 
								 | 
							
								    callable = callable  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    from abc import ABC
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _qualname(fn):
							 | 
						||
| 
								 | 
							
								        return fn.__qualname__
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								    import base64
							 | 
						||
| 
								 | 
							
								    import ConfigParser as configparser  # noqa
							 | 
						||
| 
								 | 
							
								    import itertools
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    from StringIO import StringIO  # noqa
							 | 
						||
| 
								 | 
							
								    from cStringIO import StringIO as byte_buffer  # noqa
							 | 
						||
| 
								 | 
							
								    from itertools import izip_longest as zip_longest  # noqa
							 | 
						||
| 
								 | 
							
								    from time import clock as perf_counter  # noqa
							 | 
						||
| 
								 | 
							
								    from urllib import quote  # noqa
							 | 
						||
| 
								 | 
							
								    from urllib import quote_plus  # noqa
							 | 
						||
| 
								 | 
							
								    from urllib import unquote  # noqa
							 | 
						||
| 
								 | 
							
								    from urllib import unquote_plus  # noqa
							 | 
						||
| 
								 | 
							
								    from urlparse import parse_qsl  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    from abc import ABCMeta
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class ABC(object):
							 | 
						||
| 
								 | 
							
								        __metaclass__ = ABCMeta
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        import cPickle as pickle
							 | 
						||
| 
								 | 
							
								    except ImportError:
							 | 
						||
| 
								 | 
							
								        import pickle  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    string_types = (basestring,)  # noqa
							 | 
						||
| 
								 | 
							
								    binary_types = (bytes,)
							 | 
						||
| 
								 | 
							
								    binary_type = str
							 | 
						||
| 
								 | 
							
								    text_type = unicode  # noqa
							 | 
						||
| 
								 | 
							
								    int_types = int, long  # noqa
							 | 
						||
| 
								 | 
							
								    long_type = long  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    callable = callable  # noqa
							 | 
						||
| 
								 | 
							
								    cmp = cmp  # noqa
							 | 
						||
| 
								 | 
							
								    reduce = reduce  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    b64encode = base64.b64encode
							 | 
						||
| 
								 | 
							
								    b64decode = base64.b64decode
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    itertools_filterfalse = itertools.ifilterfalse
							 | 
						||
| 
								 | 
							
								    itertools_filter = itertools.ifilter
							 | 
						||
| 
								 | 
							
								    itertools_imap = itertools.imap
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def b(s):
							 | 
						||
| 
								 | 
							
								        return s
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def exec_(func_text, globals_, lcl=None):
							 | 
						||
| 
								 | 
							
								        if lcl is None:
							 | 
						||
| 
								 | 
							
								            exec("exec func_text in globals_")
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            exec("exec func_text in globals_, lcl")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def iterbytes(buf):
							 | 
						||
| 
								 | 
							
								        return (ord(byte) for byte in buf)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def import_(*args):
							 | 
						||
| 
								 | 
							
								        if len(args) == 4:
							 | 
						||
| 
								 | 
							
								            args = args[0:3] + ([str(arg) for arg in args[3]],)
							 | 
						||
| 
								 | 
							
								        return __import__(*args)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def print_(*args, **kwargs):
							 | 
						||
| 
								 | 
							
								        fp = kwargs.pop("file", sys.stdout)
							 | 
						||
| 
								 | 
							
								        if fp is None:
							 | 
						||
| 
								 | 
							
								            return
							 | 
						||
| 
								 | 
							
								        for arg in enumerate(args):
							 | 
						||
| 
								 | 
							
								            if not isinstance(arg, basestring):  # noqa
							 | 
						||
| 
								 | 
							
								                arg = str(arg)
							 | 
						||
| 
								 | 
							
								            fp.write(arg)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def u(s):
							 | 
						||
| 
								 | 
							
								        # this differs from what six does, which doesn't support non-ASCII
							 | 
						||
| 
								 | 
							
								        # strings - we only use u() with
							 | 
						||
| 
								 | 
							
								        # literal source strings, and all our source files with non-ascii
							 | 
						||
| 
								 | 
							
								        # in them (all are tests) are utf-8 encoded.
							 | 
						||
| 
								 | 
							
								        return unicode(s, "utf-8")  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def ue(s):
							 | 
						||
| 
								 | 
							
								        return unicode(s, "unicode_escape")  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def decode_backslashreplace(text, encoding):
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            return text.decode(encoding)
							 | 
						||
| 
								 | 
							
								        except UnicodeDecodeError:
							 | 
						||
| 
								 | 
							
								            # regular "backslashreplace" for an incompatible encoding raises:
							 | 
						||
| 
								 | 
							
								            # "TypeError: don't know how to handle UnicodeDecodeError in
							 | 
						||
| 
								 | 
							
								            # error callback"
							 | 
						||
| 
								 | 
							
								            return repr(text)[1:-1].decode()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def safe_bytestring(text):
							 | 
						||
| 
								 | 
							
								        # py2k only
							 | 
						||
| 
								 | 
							
								        if not isinstance(text, string_types):
							 | 
						||
| 
								 | 
							
								            return unicode(text).encode(  # noqa: F821
							 | 
						||
| 
								 | 
							
								                "ascii", errors="backslashreplace"
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        elif isinstance(text, unicode):  # noqa: F821
							 | 
						||
| 
								 | 
							
								            return text.encode("ascii", errors="backslashreplace")
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return text
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    exec(
							 | 
						||
| 
								 | 
							
								        "def raise_(exception, with_traceback=None, replace_context=None, "
							 | 
						||
| 
								 | 
							
								        "from_=False):\n"
							 | 
						||
| 
								 | 
							
								        "    if with_traceback:\n"
							 | 
						||
| 
								 | 
							
								        "        raise type(exception), exception, with_traceback\n"
							 | 
						||
| 
								 | 
							
								        "    else:\n"
							 | 
						||
| 
								 | 
							
								        "        raise exception\n"
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    TYPE_CHECKING = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _qualname(meth):
							 | 
						||
| 
								 | 
							
								        """return __qualname__ equivalent for a method on a class"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for cls in meth.im_class.__mro__:
							 | 
						||
| 
								 | 
							
								            if meth.__name__ in cls.__dict__:
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return meth.__name__
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return "%s.%s" % (cls.__name__, meth.__name__)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if py3k:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _formatannotation(annotation, base_module=None):
							 | 
						||
| 
								 | 
							
								        """vendored from python 3.7"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if getattr(annotation, "__module__", None) == "typing":
							 | 
						||
| 
								 | 
							
								            return repr(annotation).replace("typing.", "")
							 | 
						||
| 
								 | 
							
								        if isinstance(annotation, type):
							 | 
						||
| 
								 | 
							
								            if annotation.__module__ in ("builtins", base_module):
							 | 
						||
| 
								 | 
							
								                return annotation.__qualname__
							 | 
						||
| 
								 | 
							
								            return annotation.__module__ + "." + annotation.__qualname__
							 | 
						||
| 
								 | 
							
								        return repr(annotation)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def inspect_formatargspec(
							 | 
						||
| 
								 | 
							
								        args,
							 | 
						||
| 
								 | 
							
								        varargs=None,
							 | 
						||
| 
								 | 
							
								        varkw=None,
							 | 
						||
| 
								 | 
							
								        defaults=None,
							 | 
						||
| 
								 | 
							
								        kwonlyargs=(),
							 | 
						||
| 
								 | 
							
								        kwonlydefaults={},
							 | 
						||
| 
								 | 
							
								        annotations={},
							 | 
						||
| 
								 | 
							
								        formatarg=str,
							 | 
						||
| 
								 | 
							
								        formatvarargs=lambda name: "*" + name,
							 | 
						||
| 
								 | 
							
								        formatvarkw=lambda name: "**" + name,
							 | 
						||
| 
								 | 
							
								        formatvalue=lambda value: "=" + repr(value),
							 | 
						||
| 
								 | 
							
								        formatreturns=lambda text: " -> " + text,
							 | 
						||
| 
								 | 
							
								        formatannotation=_formatannotation,
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Copy formatargspec from python 3.7 standard library.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Python 3 has deprecated formatargspec and requested that Signature
							 | 
						||
| 
								 | 
							
								        be used instead, however this requires a full reimplementation
							 | 
						||
| 
								 | 
							
								        of formatargspec() in terms of creating Parameter objects and such.
							 | 
						||
| 
								 | 
							
								        Instead of introducing all the object-creation overhead and having
							 | 
						||
| 
								 | 
							
								        to reinvent from scratch, just copy their compatibility routine.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Ultimately we would need to rewrite our "decorator" routine completely
							 | 
						||
| 
								 | 
							
								        which is not really worth it right now, until all Python 2.x support
							 | 
						||
| 
								 | 
							
								        is dropped.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        kwonlydefaults = kwonlydefaults or {}
							 | 
						||
| 
								 | 
							
								        annotations = annotations or {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def formatargandannotation(arg):
							 | 
						||
| 
								 | 
							
								            result = formatarg(arg)
							 | 
						||
| 
								 | 
							
								            if arg in annotations:
							 | 
						||
| 
								 | 
							
								                result += ": " + formatannotation(annotations[arg])
							 | 
						||
| 
								 | 
							
								            return result
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        specs = []
							 | 
						||
| 
								 | 
							
								        if defaults:
							 | 
						||
| 
								 | 
							
								            firstdefault = len(args) - len(defaults)
							 | 
						||
| 
								 | 
							
								        for i, arg in enumerate(args):
							 | 
						||
| 
								 | 
							
								            spec = formatargandannotation(arg)
							 | 
						||
| 
								 | 
							
								            if defaults and i >= firstdefault:
							 | 
						||
| 
								 | 
							
								                spec = spec + formatvalue(defaults[i - firstdefault])
							 | 
						||
| 
								 | 
							
								            specs.append(spec)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if varargs is not None:
							 | 
						||
| 
								 | 
							
								            specs.append(formatvarargs(formatargandannotation(varargs)))
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            if kwonlyargs:
							 | 
						||
| 
								 | 
							
								                specs.append("*")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if kwonlyargs:
							 | 
						||
| 
								 | 
							
								            for kwonlyarg in kwonlyargs:
							 | 
						||
| 
								 | 
							
								                spec = formatargandannotation(kwonlyarg)
							 | 
						||
| 
								 | 
							
								                if kwonlydefaults and kwonlyarg in kwonlydefaults:
							 | 
						||
| 
								 | 
							
								                    spec += formatvalue(kwonlydefaults[kwonlyarg])
							 | 
						||
| 
								 | 
							
								                specs.append(spec)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if varkw is not None:
							 | 
						||
| 
								 | 
							
								            specs.append(formatvarkw(formatargandannotation(varkw)))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        result = "(" + ", ".join(specs) + ")"
							 | 
						||
| 
								 | 
							
								        if "return" in annotations:
							 | 
						||
| 
								 | 
							
								            result += formatreturns(formatannotation(annotations["return"]))
							 | 
						||
| 
								 | 
							
								        return result
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								    from inspect import formatargspec as _inspect_formatargspec
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def inspect_formatargspec(*spec, **kw):
							 | 
						||
| 
								 | 
							
								        # convert for a potential FullArgSpec from compat.getfullargspec()
							 | 
						||
| 
								 | 
							
								        return _inspect_formatargspec(*spec[0:4], **kw)  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Fix deprecation of accessing ABCs straight from collections module
							 | 
						||
| 
								 | 
							
								# (which will stop working in 3.8).
							 | 
						||
| 
								 | 
							
								if py3k:
							 | 
						||
| 
								 | 
							
								    import collections.abc as collections_abc
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								    import collections as collections_abc  # noqa
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if py37:
							 | 
						||
| 
								 | 
							
								    import dataclasses
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def dataclass_fields(cls):
							 | 
						||
| 
								 | 
							
								        """Return a sequence of all dataclasses.Field objects associated
							 | 
						||
| 
								 | 
							
								        with a class."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if dataclasses.is_dataclass(cls):
							 | 
						||
| 
								 | 
							
								            return dataclasses.fields(cls)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def local_dataclass_fields(cls):
							 | 
						||
| 
								 | 
							
								        """Return a sequence of all dataclasses.Field objects associated with
							 | 
						||
| 
								 | 
							
								        a class, excluding those that originate from a superclass."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if dataclasses.is_dataclass(cls):
							 | 
						||
| 
								 | 
							
								            super_fields = set()
							 | 
						||
| 
								 | 
							
								            for sup in cls.__bases__:
							 | 
						||
| 
								 | 
							
								                super_fields.update(dataclass_fields(sup))
							 | 
						||
| 
								 | 
							
								            return [
							 | 
						||
| 
								 | 
							
								                f for f in dataclasses.fields(cls) if f not in super_fields
							 | 
						||
| 
								 | 
							
								            ]
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def dataclass_fields(cls):
							 | 
						||
| 
								 | 
							
								        return []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def local_dataclass_fields(cls):
							 | 
						||
| 
								 | 
							
								        return []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def raise_from_cause(exception, exc_info=None):
							 | 
						||
| 
								 | 
							
								    r"""legacy.  use raise\_()"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if exc_info is None:
							 | 
						||
| 
								 | 
							
								        exc_info = sys.exc_info()
							 | 
						||
| 
								 | 
							
								    exc_type, exc_value, exc_tb = exc_info
							 | 
						||
| 
								 | 
							
								    cause = exc_value if exc_value is not exception else None
							 | 
						||
| 
								 | 
							
								    reraise(type(exception), exception, tb=exc_tb, cause=cause)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def reraise(tp, value, tb=None, cause=None):
							 | 
						||
| 
								 | 
							
								    r"""legacy.  use raise\_()"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    raise_(value, with_traceback=tb, from_=cause)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def with_metaclass(meta, *bases, **kw):
							 | 
						||
| 
								 | 
							
								    """Create a base class with a metaclass.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Drops the middle class upon creation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Source: https://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class metaclass(meta):
							 | 
						||
| 
								 | 
							
								        __call__ = type.__call__
							 | 
						||
| 
								 | 
							
								        __init__ = type.__init__
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __new__(cls, name, this_bases, d):
							 | 
						||
| 
								 | 
							
								            if this_bases is None:
							 | 
						||
| 
								 | 
							
								                cls = type.__new__(cls, name, (), d)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                cls = meta(name, bases, d)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if hasattr(cls, "__init_subclass__") and hasattr(
							 | 
						||
| 
								 | 
							
								                cls.__init_subclass__, "__func__"
							 | 
						||
| 
								 | 
							
								            ):
							 | 
						||
| 
								 | 
							
								                cls.__init_subclass__.__func__(cls, **kw)
							 | 
						||
| 
								 | 
							
								            return cls
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return metaclass("temporary_class", None, {})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if py3k:
							 | 
						||
| 
								 | 
							
								    from datetime import timezone
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								    from datetime import datetime
							 | 
						||
| 
								 | 
							
								    from datetime import timedelta
							 | 
						||
| 
								 | 
							
								    from datetime import tzinfo
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class timezone(tzinfo):
							 | 
						||
| 
								 | 
							
								        """Minimal port of python 3 timezone object"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        __slots__ = "_offset"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __init__(self, offset):
							 | 
						||
| 
								 | 
							
								            if not isinstance(offset, timedelta):
							 | 
						||
| 
								 | 
							
								                raise TypeError("offset must be a timedelta")
							 | 
						||
| 
								 | 
							
								            if not self._minoffset <= offset <= self._maxoffset:
							 | 
						||
| 
								 | 
							
								                raise ValueError(
							 | 
						||
| 
								 | 
							
								                    "offset must be a timedelta "
							 | 
						||
| 
								 | 
							
								                    "strictly between -timedelta(hours=24) and "
							 | 
						||
| 
								 | 
							
								                    "timedelta(hours=24)."
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								            self._offset = offset
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __eq__(self, other):
							 | 
						||
| 
								 | 
							
								            if type(other) != timezone:
							 | 
						||
| 
								 | 
							
								                return False
							 | 
						||
| 
								 | 
							
								            return self._offset == other._offset
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __hash__(self):
							 | 
						||
| 
								 | 
							
								            return hash(self._offset)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __repr__(self):
							 | 
						||
| 
								 | 
							
								            return "sqlalchemy.util.%s(%r)" % (
							 | 
						||
| 
								 | 
							
								                self.__class__.__name__,
							 | 
						||
| 
								 | 
							
								                self._offset,
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __str__(self):
							 | 
						||
| 
								 | 
							
								            return self.tzname(None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def utcoffset(self, dt):
							 | 
						||
| 
								 | 
							
								            return self._offset
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def tzname(self, dt):
							 | 
						||
| 
								 | 
							
								            return self._name_from_offset(self._offset)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def dst(self, dt):
							 | 
						||
| 
								 | 
							
								            return None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def fromutc(self, dt):
							 | 
						||
| 
								 | 
							
								            if isinstance(dt, datetime):
							 | 
						||
| 
								 | 
							
								                if dt.tzinfo is not self:
							 | 
						||
| 
								 | 
							
								                    raise ValueError("fromutc: dt.tzinfo " "is not self")
							 | 
						||
| 
								 | 
							
								                return dt + self._offset
							 | 
						||
| 
								 | 
							
								            raise TypeError(
							 | 
						||
| 
								 | 
							
								                "fromutc() argument must be a datetime instance" " or None"
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        @staticmethod
							 | 
						||
| 
								 | 
							
								        def _timedelta_to_microseconds(timedelta):
							 | 
						||
| 
								 | 
							
								            """backport of timedelta._to_microseconds()"""
							 | 
						||
| 
								 | 
							
								            return (
							 | 
						||
| 
								 | 
							
								                timedelta.days * (24 * 3600) + timedelta.seconds
							 | 
						||
| 
								 | 
							
								            ) * 1000000 + timedelta.microseconds
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        @staticmethod
							 | 
						||
| 
								 | 
							
								        def _divmod_timedeltas(a, b):
							 | 
						||
| 
								 | 
							
								            """backport of timedelta.__divmod__"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            q, r = divmod(
							 | 
						||
| 
								 | 
							
								                timezone._timedelta_to_microseconds(a),
							 | 
						||
| 
								 | 
							
								                timezone._timedelta_to_microseconds(b),
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            return q, timedelta(0, 0, r)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        @staticmethod
							 | 
						||
| 
								 | 
							
								        def _name_from_offset(delta):
							 | 
						||
| 
								 | 
							
								            if not delta:
							 | 
						||
| 
								 | 
							
								                return "UTC"
							 | 
						||
| 
								 | 
							
								            if delta < timedelta(0):
							 | 
						||
| 
								 | 
							
								                sign = "-"
							 | 
						||
| 
								 | 
							
								                delta = -delta
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                sign = "+"
							 | 
						||
| 
								 | 
							
								            hours, rest = timezone._divmod_timedeltas(
							 | 
						||
| 
								 | 
							
								                delta, timedelta(hours=1)
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            minutes, rest = timezone._divmod_timedeltas(
							 | 
						||
| 
								 | 
							
								                rest, timedelta(minutes=1)
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            result = "UTC%s%02d:%02d" % (sign, hours, minutes)
							 | 
						||
| 
								 | 
							
								            if rest.seconds:
							 | 
						||
| 
								 | 
							
								                result += ":%02d" % (rest.seconds,)
							 | 
						||
| 
								 | 
							
								            if rest.microseconds:
							 | 
						||
| 
								 | 
							
								                result += ".%06d" % (rest.microseconds,)
							 | 
						||
| 
								 | 
							
								            return result
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        _maxoffset = timedelta(hours=23, minutes=59)
							 | 
						||
| 
								 | 
							
								        _minoffset = -_maxoffset
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    timezone.utc = timezone(timedelta(0))
							 |