diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-05-29 17:27:19 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-05-29 17:27:19 -0400 |
| commit | df99e1ef5f334ce7f4c8118c3e0bdf2949f54de3 (patch) | |
| tree | 1e5bd4a26e446b28de87e4aef564cc998221dcb6 /lib/sqlalchemy/util | |
| parent | 152c08fe59ed0899d037c26882463ee2b374c014 (diff) | |
| download | sqlalchemy-df99e1ef5f334ce7f4c8118c3e0bdf2949f54de3.tar.gz | |
Use fully vendored getfullargspec
Replaced the Python compatbility routines for ``getfullargspec()`` with a
fully vendored version from Python 3.3. Originally, Python was emitting
deprecation warnings for this function in Python 3.8 alphas. While this
change was reverted, it was observed that Python 3 implementations for
``getfullargspec()`` are an order of magnitude slower as of the 3.4 series
where it was rewritten against ``Signature``. While Python plans to
improve upon this situation, SQLAlchemy projects for now are using a simple
replacement to avoid any future issues.
Fixes: #4674
Change-Id: I1ab8729c4072634db80c79bb7bc44197dc5e7114
Diffstat (limited to 'lib/sqlalchemy/util')
| -rw-r--r-- | lib/sqlalchemy/util/compat.py | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py index c12f2d379..386aaf731 100644 --- a/lib/sqlalchemy/util/compat.py +++ b/lib/sqlalchemy/util/compat.py @@ -9,6 +9,7 @@ import collections import contextlib +import inspect import operator import sys import time @@ -44,19 +45,6 @@ FullArgSpec = collections.namedtuple( ], ) -FullArgSpec = collections.namedtuple( - "FullArgSpec", - [ - "args", - "varargs", - "varkw", - "defaults", - "kwonlyargs", - "kwonlydefaults", - "annotations", - ], -) - try: import threading except ImportError: @@ -70,6 +58,45 @@ else: safe_kwarg = str +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]) + step = 0 + + 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 py3k: import base64 import builtins @@ -78,7 +105,6 @@ if py3k: import pickle from functools import reduce - from inspect import getfullargspec as inspect_getfullargspec from io import BytesIO as byte_buffer from io import StringIO from itertools import zip_longest @@ -149,7 +175,6 @@ else: from StringIO import StringIO # noqa from cStringIO import StringIO as byte_buffer # noqa - from inspect import getargspec as _getargspec from itertools import izip_longest as zip_longest # noqa from urllib import quote # noqa from urllib import quote_plus # noqa @@ -168,9 +193,6 @@ else: text_type = unicode # noqa int_types = int, long # noqa - def inspect_getfullargspec(func): - return FullArgSpec(*_getargspec(func)[0:4] + ([], None, {})) - callable = callable # noqa cmp = cmp # noqa reduce = reduce # noqa |
