From: Mike Bayer Date: Mon, 14 Jan 2019 17:22:40 +0000 (-0500) Subject: move to inspect_getfullargspec X-Git-Tag: rel_1_3_0b2~31^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=150ccf1716a41439c6ed9b06ac9cbf68fa5db1c4;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git move to inspect_getfullargspec Replace inspect_getargspec with inspect_getfullargspec including a compatibility fallback for Py2k and use getfullargspec fully. Change-Id: I92bce0aafc37ce1a360b4f61b75f5892d0911c7e --- diff --git a/lib/sqlalchemy/event/attr.py b/lib/sqlalchemy/event/attr.py index f0f65e6701..9dfa89809d 100644 --- a/lib/sqlalchemy/event/attr.py +++ b/lib/sqlalchemy/event/attr.py @@ -81,9 +81,9 @@ class _ClsLevelDispatch(RefCollection): def __init__(self, parent_dispatch_cls, fn): self.name = fn.__name__ - argspec = util.inspect_getargspec(fn) + argspec = util.inspect_getfullargspec(fn) self.arg_names = argspec.args[1:] - self.has_kw = bool(argspec.keywords) + self.has_kw = bool(argspec.varkw) self.legacy_signatures = list( reversed( sorted( diff --git a/lib/sqlalchemy/event/legacy.py b/lib/sqlalchemy/event/legacy.py index 049df81aaf..93b6a1a9a7 100644 --- a/lib/sqlalchemy/event/legacy.py +++ b/lib/sqlalchemy/event/legacy.py @@ -32,7 +32,7 @@ def _wrap_fn_for_legacy(dispatch_collection, fn, argspec): has_kw = False if len(argnames) == len(argspec.args) and has_kw is bool( - argspec.keywords + argspec.varkw ): if conv: @@ -140,7 +140,7 @@ def _version_signature_changes(parent_dispatch_cls, dispatch_collection): " The :class:`.%(clsname)s.%(event_name)s` event now accepts the \n" " arguments ``%(named_event_arguments)s%(has_kw_arguments)s``.\n" " Support for listener functions which accept the previous \n" - " argument signature(s) listed above as \"deprecated\" will be \n" + ' argument signature(s) listed above as "deprecated" will be \n' " removed in a future release." % { "since": since, @@ -171,6 +171,7 @@ def _augment_fn_docs(dispatch_collection, parent_dispatch_cls, fn): ) text += _version_signature_changes( - parent_dispatch_cls, dispatch_collection) + parent_dispatch_cls, dispatch_collection + ) return util.inject_docstring_text(fn.__doc__, text, 1) diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py index 427296ca28..1e561369fb 100644 --- a/lib/sqlalchemy/orm/collections.py +++ b/lib/sqlalchemy/orm/collections.py @@ -106,7 +106,7 @@ through the adapter, allowing for some very sophisticated behavior. import operator import weakref -from sqlalchemy.util.compat import inspect_getargspec +from sqlalchemy.util.compat import inspect_getfullargspec from . import base from .. import exc as sa_exc from .. import util @@ -433,7 +433,7 @@ class collection(object): "The :meth:`.collection.linker` handler is deprecated and will " "be removed in a future release. Please refer to the " ":meth:`.AttributeEvents.init_collection` " - "and :meth:`.AttributeEvents.dispose_collection` event handlers. " + "and :meth:`.AttributeEvents.dispose_collection` event handlers. ", ) def linker(fn): """Tag the method as a "linked to attribute" event handler. @@ -463,7 +463,7 @@ class collection(object): "The :meth:`.collection.converter` method is deprecated and will " "be removed in a future release. Please refer to the " ":class:`.AttributeEvents.bulk_replace` listener interface in " - "conjunction with the :func:`.event.listen` function." + "conjunction with the :func:`.event.listen` function.", ) def converter(fn): """Tag the method as the collection converter. @@ -1008,7 +1008,9 @@ def _instrument_membership_mutator(method, before, argument, after): adapter.""" # This isn't smart enough to handle @adds(1) for 'def fn(self, (a, b))' if before: - fn_args = list(util.flatten_iterator(inspect_getargspec(method)[0])) + fn_args = list( + util.flatten_iterator(inspect_getfullargspec(method)[0]) + ) if isinstance(argument, int): pos_arg = argument named_arg = len(fn_args) > argument and fn_args[argument] or None diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py index d9e5f87a31..e10744fc1b 100644 --- a/lib/sqlalchemy/orm/events.py +++ b/lib/sqlalchemy/orm/events.py @@ -22,7 +22,7 @@ from .session import sessionmaker from .. import event from .. import exc from .. import util -from ..util.compat import inspect_getargspec +from ..util.compat import inspect_getfullargspec class InstrumentationEvents(event.Events): @@ -639,7 +639,7 @@ class MapperEvents(event.Events): meth = getattr(cls, identifier) try: target_index = ( - inspect_getargspec(meth)[0].index("target") - 1 + inspect_getfullargspec(meth)[0].index("target") - 1 ) except ValueError: target_index = None diff --git a/lib/sqlalchemy/testing/exclusions.py b/lib/sqlalchemy/testing/exclusions.py index bfb239dad0..d205354cff 100644 --- a/lib/sqlalchemy/testing/exclusions.py +++ b/lib/sqlalchemy/testing/exclusions.py @@ -13,7 +13,7 @@ import re from . import config from .. import util from ..util import decorator -from ..util.compat import inspect_getargspec +from ..util.compat import inspect_getfullargspec def skip_if(predicate, reason=None): @@ -303,7 +303,7 @@ class SpecPredicate(Predicate): class LambdaPredicate(Predicate): def __init__(self, lambda_, description=None, args=None, kw=None): - spec = inspect_getargspec(lambda_) + spec = inspect_getfullargspec(lambda_) if not spec[0]: self.lambda_ = lambda db: lambda_() else: diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py index 7e9bedd835..f812671d34 100644 --- a/lib/sqlalchemy/util/__init__.py +++ b/lib/sqlalchemy/util/__init__.py @@ -53,7 +53,7 @@ from .compat import cmp # noqa from .compat import cpython # noqa from .compat import decode_backslashreplace # noqa from .compat import dottedgetter # noqa -from .compat import inspect_getargspec # noqa +from .compat import inspect_getfullargspec # noqa from .compat import int_types # noqa from .compat import iterbytes # noqa from .compat import itertools_filter # noqa diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py index 05e31f7bd9..abd36d9b07 100644 --- a/lib/sqlalchemy/util/compat.py +++ b/lib/sqlalchemy/util/compat.py @@ -31,8 +31,17 @@ dottedgetter = operator.attrgetter namedtuple = collections.namedtuple next = next # noqa -ArgSpec = collections.namedtuple( - "ArgSpec", ["args", "varargs", "keywords", "defaults"] +FullArgSpec = collections.namedtuple( + "FullArgSpec", + [ + "args", + "varargs", + "varkw", + "defaults", + "kwonlyargs", + "kwonlydefaults", + "annotations", + ], ) try: @@ -98,9 +107,6 @@ if py3k: def cmp(a, b): return (a > b) - (a < b) - def inspect_getargspec(func): - return ArgSpec(*inspect_getfullargspec(func)[0:4]) - def reraise(tp, value, tb=None, cause=None): if cause is not None: assert cause is not value, "Same cause emitted" @@ -130,7 +136,7 @@ else: from StringIO import StringIO # noqa from cStringIO import StringIO as byte_buffer # noqa - from inspect import getargspec as inspect_getfullargspec # 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 @@ -149,7 +155,8 @@ else: text_type = unicode # noqa int_types = int, long # noqa - inspect_getargspec = inspect_getfullargspec + def inspect_getfullargspec(func): + return FullArgSpec(*_getargspec(func)[0:4] + ([], None, {})) callable = callable # noqa cmp = cmp # noqa @@ -286,6 +293,14 @@ if py35: return result +elif py2k: + 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 + + else: from inspect import formatargspec as inspect_formatargspec # noqa diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 27c4be0ec7..56e1304e3a 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -121,8 +121,9 @@ def decorator(target): """A signature-matching decorator factory.""" def decorate(fn): - if not inspect.isfunction(fn): + if not inspect.isfunction(fn) and not inspect.ismethod(fn): raise Exception("not a decoratable function") + spec = compat.inspect_getfullargspec(fn) names = tuple(spec[0]) + spec[1:3] + (fn.__name__,) targ_name, fn_name = _unique_symbols(names, "target", "fn") @@ -242,6 +243,26 @@ class PluginLoader(object): self.impls[name] = load +def _inspect_func_args(fn): + try: + co_varkeywords = inspect.CO_VARKEYWORDS + except AttributeError: + # https://docs.python.org/3/library/inspect.html + # The flags are specific to CPython, and may not be defined in other + # Python implementations. Furthermore, the flags are an implementation + # detail, and can be removed or deprecated in future Python releases. + spec = compat.inspect_getfullargspec(fn) + return spec[0], bool(spec[2]) + else: + # use fn.__code__ plus flags to reduce method call overhead + co = fn.__code__ + nargs = co.co_argcount + return ( + list(co.co_varnames[:nargs]), + bool(co.co_flags & inspect.CO_VARKEYWORDS), + ) + + def get_cls_kwargs(cls, _set=None): r"""Return the full set of inherited kwargs for the given `cls`. @@ -250,7 +271,10 @@ def get_cls_kwargs(cls, _set=None): to pass along unrecognized keywords to its base classes, and the collection process is repeated recursively on each of the bases. - Uses a subset of inspect.getargspec() to cut down on method overhead. + Uses a subset of inspect.getfullargspec() to cut down on method overhead, + as this is used within the Core typing system to create copies of type + objects which is a performance-sensitive operation. + No anonymous tuple arguments please ! """ @@ -267,7 +291,7 @@ def get_cls_kwargs(cls, _set=None): ) if has_init: - names, has_kw = inspect_func_args(ctr) + names, has_kw = _inspect_func_args(ctr) _set.update(names) if not has_kw and not toplevel: @@ -282,26 +306,6 @@ def get_cls_kwargs(cls, _set=None): return _set -try: - # TODO: who doesn't have this constant? - from inspect import CO_VARKEYWORDS - - def inspect_func_args(fn): - co = fn.__code__ - nargs = co.co_argcount - names = co.co_varnames - args = list(names[:nargs]) - has_kw = bool(co.co_flags & CO_VARKEYWORDS) - return args, has_kw - - -except ImportError: - - def inspect_func_args(fn): - names, _, has_kw, _ = compat.inspect_getargspec(fn) - return names, bool(has_kw) - - def get_func_kwargs(func): """Return the set of legal kwargs for the given `func`. @@ -310,7 +314,7 @@ def get_func_kwargs(func): """ - return compat.inspect_getargspec(func)[0] + return compat.inspect_getfullargspec(func)[0] def get_callable_argspec(fn, no_self=False, _is_init=False): @@ -326,26 +330,38 @@ def get_callable_argspec(fn, no_self=False, _is_init=False): raise TypeError("Can't inspect builtin: %s" % fn) elif inspect.isfunction(fn): if _is_init and no_self: - spec = compat.inspect_getargspec(fn) - return compat.ArgSpec( - spec.args[1:], spec.varargs, spec.keywords, spec.defaults + spec = compat.inspect_getfullargspec(fn) + return compat.FullArgSpec( + spec.args[1:], + spec.varargs, + spec.varkw, + spec.defaults, + spec.kwonlyargs, + spec.kwonlydefaults, + spec.annotations, ) else: - return compat.inspect_getargspec(fn) + return compat.inspect_getfullargspec(fn) elif inspect.ismethod(fn): if no_self and (_is_init or fn.__self__): - spec = compat.inspect_getargspec(fn.__func__) - return compat.ArgSpec( - spec.args[1:], spec.varargs, spec.keywords, spec.defaults + spec = compat.inspect_getfullargspec(fn.__func__) + return compat.FullArgSpec( + spec.args[1:], + spec.varargs, + spec.varkw, + spec.defaults, + spec.kwonlyargs, + spec.kwonlydefaults, + spec.annotations, ) else: - return compat.inspect_getargspec(fn.__func__) + return compat.inspect_getfullargspec(fn.__func__) elif inspect.isclass(fn): return get_callable_argspec( fn.__init__, no_self=no_self, _is_init=True ) elif hasattr(fn, "__func__"): - return compat.inspect_getargspec(fn.__func__) + return compat.inspect_getfullargspec(fn.__func__) elif hasattr(fn, "__call__"): if inspect.ismethod(fn.__call__): return get_callable_argspec(fn.__call__, no_self=no_self) @@ -390,8 +406,8 @@ def format_argspec_plus(fn, grouped=True): if compat.callable(fn): spec = compat.inspect_getfullargspec(fn) else: - # we accept an existing argspec... spec = fn + args = compat.inspect_formatargspec(*spec) if spec[0]: self_arg = spec[0][0] @@ -400,22 +416,15 @@ def format_argspec_plus(fn, grouped=True): else: self_arg = None - if compat.py3k: - 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]) - if spec[4]: - num_defaults += len(spec[4]) - name_args = spec[0] + spec[4] - else: - apply_pos = compat.inspect_formatargspec(spec[0], spec[1], spec[2]) - num_defaults = 0 - if spec[3]: - num_defaults += len(spec[3]) - name_args = spec[0] + 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]) + if spec[4]: + num_defaults += len(spec[4]) + name_args = spec[0] + spec[4] if num_defaults: defaulted_vals = name_args[0 - num_defaults :] @@ -479,7 +488,7 @@ def getargspec_init(method): """ try: - return compat.inspect_getargspec(method) + return compat.inspect_getfullargspec(method) except TypeError: if method is object.__init__: return (["self"], None, None, None) @@ -516,30 +525,30 @@ def generic_repr(obj, additional_kw=(), to_inspect=None, omit_kwarg=()): vargs = None for i, insp in enumerate(to_inspect): try: - (_args, _vargs, vkw, defaults) = compat.inspect_getargspec( - insp.__init__ - ) + spec = compat.inspect_getfullargspec(insp.__init__) except TypeError: continue else: - default_len = defaults and len(defaults) or 0 + default_len = spec.defaults and len(spec.defaults) or 0 if i == 0: - if _vargs: - vargs = _vargs + if spec.varargs: + vargs = spec.varargs if default_len: - pos_args.extend(_args[1:-default_len]) + pos_args.extend(spec.args[1:-default_len]) else: - pos_args.extend(_args[1:]) + pos_args.extend(spec.args[1:]) else: kw_args.update( - [(arg, missing) for arg in _args[1:-default_len]] + [(arg, missing) for arg in spec.args[1:-default_len]] ) if default_len: kw_args.update( [ (arg, default) - for arg, default in zip(_args[-default_len:], defaults) + for arg, default in zip( + spec.args[-default_len:], spec.defaults + ) ] ) output = [] @@ -710,7 +719,7 @@ def monkeypatch_proxied_specials( except AttributeError: continue try: - spec = compat.inspect_getargspec(fn) + spec = compat.inspect_getfullargspec(fn) fn_args = compat.inspect_formatargspec(spec[0]) d_args = compat.inspect_formatargspec(spec[0][1:]) except TypeError: @@ -1478,8 +1487,8 @@ class EnsureKWArgType(type): m = re.match(fn_reg, key) if m: fn = clsdict[key] - spec = compat.inspect_getargspec(fn) - if not spec.keywords: + spec = compat.inspect_getfullargspec(fn) + if not spec.varkw: clsdict[key] = wrapped = cls._wrap_w_kw(fn) setattr(cls, key, wrapped) super(EnsureKWArgType, cls).__init__(clsname, bases, clsdict) diff --git a/test/base/test_utils.py b/test/base/test_utils.py index 69af6e0329..b27379248d 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -1674,7 +1674,10 @@ class ArgInspectionTest(fixtures.TestBase): def foo(x, y, **kw): pass - eq_(get_callable_argspec(foo), (["x", "y"], None, "kw", None)) + eq_( + get_callable_argspec(foo), + compat.FullArgSpec(["x", "y"], None, "kw", None, [], None, {}), + ) def test_callable_argspec_fn_no_self(self): def foo(x, y, **kw): @@ -1682,7 +1685,7 @@ class ArgInspectionTest(fixtures.TestBase): eq_( get_callable_argspec(foo, no_self=True), - (["x", "y"], None, "kw", None), + compat.FullArgSpec(["x", "y"], None, "kw", None, [], None, {}), ) def test_callable_argspec_fn_no_self_but_self(self): @@ -1691,7 +1694,9 @@ class ArgInspectionTest(fixtures.TestBase): eq_( get_callable_argspec(foo, no_self=True), - (["self", "x", "y"], None, "kw", None), + compat.FullArgSpec( + ["self", "x", "y"], None, "kw", None, [], None, {} + ), ) @fails_if(lambda: util.pypy, "pypy returns plain *arg, **kw") @@ -1711,7 +1716,9 @@ class ArgInspectionTest(fixtures.TestBase): eq_( get_callable_argspec(Foo.foo), - (["self", "x", "y"], None, "kw", None), + compat.FullArgSpec( + ["self", "x", "y"], None, "kw", None, [], None, {} + ), ) def test_callable_argspec_instance_method_no_self(self): @@ -1721,7 +1728,7 @@ class ArgInspectionTest(fixtures.TestBase): eq_( get_callable_argspec(Foo().foo, no_self=True), - (["x", "y"], None, "kw", None), + compat.FullArgSpec(["x", "y"], None, "kw", None, [], None, {}), ) def test_callable_argspec_unbound_method_no_self(self): @@ -1731,7 +1738,9 @@ class ArgInspectionTest(fixtures.TestBase): eq_( get_callable_argspec(Foo.foo, no_self=True), - (["self", "x", "y"], None, "kw", None), + compat.FullArgSpec( + ["self", "x", "y"], None, "kw", None, [], None, {} + ), ) def test_callable_argspec_init(self): @@ -1739,7 +1748,12 @@ class ArgInspectionTest(fixtures.TestBase): def __init__(self, x, y): pass - eq_(get_callable_argspec(Foo), (["self", "x", "y"], None, None, None)) + eq_( + get_callable_argspec(Foo), + compat.FullArgSpec( + ["self", "x", "y"], None, None, None, [], None, {} + ), + ) def test_callable_argspec_init_no_self(self): class Foo(object): @@ -1748,7 +1762,7 @@ class ArgInspectionTest(fixtures.TestBase): eq_( get_callable_argspec(Foo, no_self=True), - (["x", "y"], None, None, None), + compat.FullArgSpec(["x", "y"], None, None, None, [], None, {}), ) def test_callable_argspec_call(self): @@ -1757,7 +1771,10 @@ class ArgInspectionTest(fixtures.TestBase): pass eq_( - get_callable_argspec(Foo()), (["self", "x", "y"], None, None, None) + get_callable_argspec(Foo()), + compat.FullArgSpec( + ["self", "x", "y"], None, None, None, [], None, {} + ), ) def test_callable_argspec_call_no_self(self): @@ -1767,7 +1784,7 @@ class ArgInspectionTest(fixtures.TestBase): eq_( get_callable_argspec(Foo(), no_self=True), - (["x", "y"], None, None, None), + compat.FullArgSpec(["x", "y"], None, None, None, [], None, {}), ) @fails_if(lambda: util.pypy, "pypy returns plain *arg, **kw") @@ -1781,6 +1798,25 @@ class ArgInspectionTest(fixtures.TestBase): assert_raises(TypeError, get_callable_argspec, bar) + def test_getargspec_6_tuple(self): + def foo(x, y, z, **kw): + pass + + spec = compat.inspect_getfullargspec(foo) + + eq_( + spec, + compat.FullArgSpec( + args=["x", "y", "z"], + varargs=None, + varkw="kw", + defaults=None, + kwonlyargs=[], + kwonlydefaults=None, + annotations={}, + ), + ) + class SymbolTest(fixtures.TestBase): def test_basic(self): @@ -1833,16 +1869,49 @@ class SymbolTest(fixtures.TestBase): assert (sym1 | sym2) & (sym2 | sym4) -class TestFormatArgspec(fixtures.TestBase): - def test_specs(self): - def test(fn, wanted, grouped=None): - if grouped is None: - parsed = util.format_argspec_plus(fn) - else: - parsed = util.format_argspec_plus(fn, grouped=grouped) - eq_(parsed, wanted) +class _Py3KFixtures(object): + pass + + +if util.py3k: + _locals = {} + exec( + """ +def _kw_only_fixture(self, a, *, b, c): + pass + +def _kw_plus_posn_fixture(self, a, *args, b, c): + pass + +def _kw_opt_fixture(self, a, *, b, c="c"): + pass +""", + _locals, + ) + for k in _locals: + setattr(_Py3KFixtures, k, _locals[k]) + - test( +class TestFormatArgspec(_Py3KFixtures, fixtures.TestBase): + def _test_format_argspec_plus(self, fn, wanted, grouped=None): + + # test direct function + if grouped is None: + parsed = util.format_argspec_plus(fn) + else: + parsed = util.format_argspec_plus(fn, grouped=grouped) + eq_(parsed, wanted) + + # test sending fullargspec + spec = compat.inspect_getfullargspec(fn) + if grouped is None: + parsed = util.format_argspec_plus(spec) + else: + parsed = util.format_argspec_plus(spec, grouped=grouped) + eq_(parsed, wanted) + + def test_specs(self): + self._test_format_argspec_plus( lambda: None, { "args": "()", @@ -1852,13 +1921,13 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda: None, {"args": "", "self_arg": None, "apply_kw": "", "apply_pos": ""}, grouped=False, ) - test( + self._test_format_argspec_plus( lambda self: None, { "args": "(self)", @@ -1868,7 +1937,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda self: None, { "args": "self", @@ -1879,7 +1948,7 @@ class TestFormatArgspec(fixtures.TestBase): grouped=False, ) - test( + self._test_format_argspec_plus( lambda *a: None, { "args": "(*a)", @@ -1889,7 +1958,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda **kw: None, { "args": "(**kw)", @@ -1899,7 +1968,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda *a, **kw: None, { "args": "(*a, **kw)", @@ -1909,7 +1978,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda a, *b: None, { "args": "(a, *b)", @@ -1919,7 +1988,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda a, **b: None, { "args": "(a, **b)", @@ -1929,7 +1998,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda a, *b, **c: None, { "args": "(a, *b, **c)", @@ -1939,7 +2008,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda a, b=1, **c: None, { "args": "(a, b=1, **c)", @@ -1949,7 +2018,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda a=1, b=2: None, { "args": "(a=1, b=2)", @@ -1959,7 +2028,7 @@ class TestFormatArgspec(fixtures.TestBase): }, ) - test( + self._test_format_argspec_plus( lambda a=1, b=2: None, { "args": "a=1, b=2", @@ -1970,6 +2039,38 @@ class TestFormatArgspec(fixtures.TestBase): grouped=False, ) + if util.py3k: + self._test_format_argspec_plus( + self._kw_only_fixture, + { + "args": "self, a, *, b, c", + "self_arg": "self", + "apply_pos": "self, a, *, b, c", + "apply_kw": "self, a, b=b, c=c", + }, + grouped=False, + ) + self._test_format_argspec_plus( + self._kw_plus_posn_fixture, + { + "args": "self, a, *args, b, c", + "self_arg": "self", + "apply_pos": "self, a, *args, b, c", + "apply_kw": "self, a, b=b, c=c, *args", + }, + grouped=False, + ) + self._test_format_argspec_plus( + self._kw_opt_fixture, + { + "args": "self, a, *, b, c='c'", + "self_arg": "self", + "apply_pos": "self, a, *, b, c", + "apply_kw": "self, a, b=b, c=c", + }, + grouped=False, + ) + @testing.fails_if( lambda: util.pypy, "pypy doesn't report Obj.__init__ as object.__init__", diff --git a/test/orm/test_session.py b/test/orm/test_session.py index 03b18df6aa..7221f1d126 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -35,7 +35,7 @@ from sqlalchemy.testing.schema import Table from sqlalchemy.testing.util import gc_collect from sqlalchemy.util import pickle from sqlalchemy.util import pypy -from sqlalchemy.util.compat import inspect_getargspec +from sqlalchemy.util.compat import inspect_getfullargspec from test.orm import _fixtures @@ -1850,7 +1850,7 @@ class SessionInterface(fixtures.TestBase): for meth in Session.public_methods: if meth in blacklist: continue - spec = inspect_getargspec(getattr(Session, meth)) + spec = inspect_getfullargspec(getattr(Session, meth)) if len(spec[0]) > 1 or spec[1]: ok.add(meth) return ok