From 536d5187a038a44aec624dd2a99792f49dec82ed Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 28 Jun 2018 11:49:02 -0400 Subject: [PATCH] Vendor python3 formatargspec Replaced the usage of inspect.formatargspec() with a vendored version copied from the Python standard library, as inspect.formatargspec() is deprecated and as of Python 3.7.0 is emitting a warning. Change-Id: I751652fac7f605a3a10b547ba8c5f34fef1de945 Fixes: #4291 --- doc/build/changelog/unreleased_12/4291.rst | 7 +++ lib/sqlalchemy/util/compat.py | 64 +++++++++++++++++++++- lib/sqlalchemy/util/langhelpers.py | 22 ++++---- 3 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 doc/build/changelog/unreleased_12/4291.rst diff --git a/doc/build/changelog/unreleased_12/4291.rst b/doc/build/changelog/unreleased_12/4291.rst new file mode 100644 index 0000000000..0fd5e7c4a7 --- /dev/null +++ b/doc/build/changelog/unreleased_12/4291.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: bug, py3k + :tickets: 4291 + + Replaced the usage of inspect.formatargspec() with a vendored version + copied from the Python standard library, as inspect.formatargspec() + is deprecated and as of Python 3.7.0 is emitting a warning. diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py index 2d952c63f7..bc0c3e6e06 100644 --- a/lib/sqlalchemy/util/compat.py +++ b/lib/sqlalchemy/util/compat.py @@ -17,6 +17,7 @@ except ImportError: py36 = sys.version_info >= (3, 6) py33 = sys.version_info >= (3, 3) +py35 = sys.version_info >= (3, 5) py32 = sys.version_info >= (3, 2) py3k = sys.version_info >= (3, 0) py2k = sys.version_info < (3, 0) @@ -166,6 +167,67 @@ else: itertools_imap = itertools.imap from itertools import izip_longest as zip_longest +if py35: + from inspect import formatannotation + + 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. + + Utimately 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. + + """ + + 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 + + import time if win32 or jython: @@ -232,8 +294,6 @@ def with_metaclass(meta, *bases): return metaclass('temporary_class', None, {}) - - @contextmanager def nested(*managers): """Implement contextlib.nested, mostly for unit tests. diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 213f3a0ad7..81bfee30ac 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -9,8 +9,8 @@ modules, classes, hierarchies, attributes, functions, and methods. """ -import itertools import inspect +import itertools import operator import re import sys @@ -280,7 +280,7 @@ try: except ImportError: def inspect_func_args(fn): - names, _, has_kw, _ = inspect.getargspec(fn) + names, _, has_kw, _ = compat.inspect_getargspec(fn) return names, bool(has_kw) @@ -371,7 +371,7 @@ def format_argspec_plus(fn, grouped=True): else: # we accept an existing argspec... spec = fn - args = inspect.formatargspec(*spec) + args = compat.inspect_formatargspec(*spec) if spec[0]: self_arg = spec[0][0] elif spec[1]: @@ -380,8 +380,8 @@ def format_argspec_plus(fn, grouped=True): self_arg = None if compat.py3k: - apply_pos = inspect.formatargspec(spec[0], spec[1], - spec[2], None, spec[4]) + apply_pos = compat.inspect_formatargspec( + spec[0], spec[1], spec[2], None, spec[4]) num_defaults = 0 if spec[3]: num_defaults += len(spec[3]) @@ -389,7 +389,7 @@ def format_argspec_plus(fn, grouped=True): num_defaults += len(spec[4]) name_args = spec[0] + spec[4] else: - apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2]) + apply_pos = compat.inspect_formatargspec(spec[0], spec[1], spec[2]) num_defaults = 0 if spec[3]: num_defaults += len(spec[3]) @@ -400,9 +400,9 @@ def format_argspec_plus(fn, grouped=True): else: defaulted_vals = () - apply_kw = inspect.formatargspec(name_args, spec[1], spec[2], - defaulted_vals, - formatvalue=lambda x: '=' + x) + apply_kw = compat.inspect_formatargspec( + name_args, spec[1], spec[2], defaulted_vals, + formatvalue=lambda x: '=' + x) if grouped: return dict(args=args, self_arg=self_arg, apply_pos=apply_pos, apply_kw=apply_kw) @@ -646,8 +646,8 @@ def monkeypatch_proxied_specials(into_cls, from_cls, skip=None, only=None, continue try: spec = compat.inspect_getargspec(fn) - fn_args = inspect.formatargspec(spec[0]) - d_args = inspect.formatargspec(spec[0][1:]) + fn_args = compat.inspect_formatargspec(spec[0]) + d_args = compat.inspect_formatargspec(spec[0][1:]) except TypeError: fn_args = '(self, *args, **kw)' d_args = '(*args, **kw)' -- 2.47.2