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(
has_kw = False
if len(argnames) == len(argspec.args) and has_kw is bool(
- argspec.keywords
+ argspec.varkw
):
if conv:
" 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,
)
text += _version_signature_changes(
- parent_dispatch_cls, dispatch_collection)
+ parent_dispatch_cls, dispatch_collection
+ )
return util.inject_docstring_text(fn.__doc__, text, 1)
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
"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.
"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.
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
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):
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
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):
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:
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
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:
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"
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
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
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
"""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")
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`.
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 !
"""
)
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:
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`.
"""
- return compat.inspect_getargspec(func)[0]
+ return compat.inspect_getfullargspec(func)[0]
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)
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]
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 :]
"""
try:
- return compat.inspect_getargspec(method)
+ return compat.inspect_getfullargspec(method)
except TypeError:
if method is object.__init__:
return (["self"], None, None, None)
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 = []
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:
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)
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):
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):
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")
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):
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):
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):
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):
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):
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):
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")
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):
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": "()",
},
)
- 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)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda self: None,
{
"args": "self",
grouped=False,
)
- test(
+ self._test_format_argspec_plus(
lambda *a: None,
{
"args": "(*a)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda **kw: None,
{
"args": "(**kw)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda *a, **kw: None,
{
"args": "(*a, **kw)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda a, *b: None,
{
"args": "(a, *b)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda a, **b: None,
{
"args": "(a, **b)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda a, *b, **c: None,
{
"args": "(a, *b, **c)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda a, b=1, **c: None,
{
"args": "(a, b=1, **c)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda a=1, b=2: None,
{
"args": "(a=1, b=2)",
},
)
- test(
+ self._test_format_argspec_plus(
lambda a=1, b=2: None,
{
"args": "a=1, b=2",
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__",
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
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