def get_callable_args(function, required_only=False):
"""Get names of callable arguments.
Special arguments (like ``*args`` and ``**kwargs``) are not included into
output.
If required_only is True, optional arguments (with default values)
are not included into output.
"""
sig = get_signature(function)
function_args = list(six.iterkeys(sig.parameters))
for param_name, p in six.iteritems(sig.parameters):
if (p.kind in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD)
or (required_only and p.default is not Parameter.empty)):
function_args.remove(param_name)
return function_args
python类Parameter()的实例源码
def get_callable_args(function, required_only=False):
"""Get names of callable arguments.
Special arguments (like ``*args`` and ``**kwargs``) are not included into
output.
If required_only is True, optional arguments (with default values)
are not included into output.
"""
sig = get_signature(function)
function_args = list(six.iterkeys(sig.parameters))
for param_name, p in six.iteritems(sig.parameters):
if (p.kind in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD)
or (required_only and p.default is not Parameter.empty)):
function_args.remove(param_name)
return function_args
def test_callable_and_async_signature(self):
mapping_viz = self.plugin.visualizers['mapping_viz']
for callable_attr in '__call__', 'async':
signature = inspect.Signature.from_callable(
getattr(mapping_viz, callable_attr))
parameters = list(signature.parameters.items())
kind = inspect.Parameter.POSITIONAL_OR_KEYWORD
exp_parameters = [
('mapping1', inspect.Parameter(
'mapping1', kind, annotation=Mapping)),
('mapping2', inspect.Parameter(
'mapping2', kind, annotation=Mapping)),
('key_label', inspect.Parameter(
'key_label', kind, annotation=Str)),
('value_label', inspect.Parameter(
'value_label', kind, annotation=Str))
]
self.assertEqual(parameters, exp_parameters)
def test_callable_and_async_different_signature(self):
# Test that a different Visualizer object has a different dynamic
# signature.
most_common_viz = self.plugin.visualizers['most_common_viz']
for callable_attr in '__call__', 'async':
signature = inspect.Signature.from_callable(
getattr(most_common_viz, callable_attr))
parameters = list(signature.parameters.items())
kind = inspect.Parameter.POSITIONAL_OR_KEYWORD
exp_parameters = [
('ints', inspect.Parameter(
'ints', kind, annotation=IntSequence1 | IntSequence2))
]
self.assertEqual(parameters, exp_parameters)
def test_callable_and_async_signature(self):
# Shouldn't include `ctx`
typical_pipeline = self.plugin.pipelines['typical_pipeline']
kind = inspect.Parameter.POSITIONAL_OR_KEYWORD
exp_parameters = [
('int_sequence', inspect.Parameter(
'int_sequence', kind, annotation=IntSequence1)),
('mapping', inspect.Parameter(
'mapping', kind, annotation=Mapping)),
('do_extra_thing', inspect.Parameter(
'do_extra_thing', kind, annotation=Bool)),
('add', inspect.Parameter(
'add', kind, default=1, annotation=Int))
]
for callable_attr in '__call__', 'async':
signature = inspect.Signature.from_callable(
getattr(typical_pipeline, callable_attr))
parameters = list(signature.parameters.items())
self.assertEqual(parameters, exp_parameters)
def test_callable_and_async_signature_with_artifacts_and_parameters(self):
# Signature with input artifacts and parameters (i.e. primitives).
concatenate_ints = self.plugin.methods['concatenate_ints']
for callable_attr in '__call__', 'async':
signature = inspect.Signature.from_callable(
getattr(concatenate_ints, callable_attr))
parameters = list(signature.parameters.items())
kind = inspect.Parameter.POSITIONAL_OR_KEYWORD
exp_parameters = [
('ints1', inspect.Parameter(
'ints1', kind, annotation=IntSequence1 | IntSequence2)),
('ints2', inspect.Parameter(
'ints2', kind, annotation=IntSequence1)),
('ints3', inspect.Parameter(
'ints3', kind, annotation=IntSequence2)),
('int1', inspect.Parameter(
'int1', kind, annotation=Int)),
('int2', inspect.Parameter(
'int2', kind, annotation=Int))
]
self.assertEqual(parameters, exp_parameters)
def test_callable_and_async_signature_with_no_parameters(self):
# Signature without parameters (i.e. primitives), only input artifacts.
method = self.plugin.methods['merge_mappings']
for callable_attr in '__call__', 'async':
signature = inspect.Signature.from_callable(
getattr(method, callable_attr))
parameters = list(signature.parameters.items())
kind = inspect.Parameter.POSITIONAL_OR_KEYWORD
exp_parameters = [
('mapping1', inspect.Parameter(
'mapping1', kind, annotation=Mapping)),
('mapping2', inspect.Parameter(
'mapping2', kind, annotation=Mapping))
]
self.assertEqual(parameters, exp_parameters)
def post(path):
def decorater(func):
@functools.wraps(func)
def wrapper(*args, **kw):
return func(*args, **kw)
wrapper.__method__ = 'POST'
wrapper.__route__ = path
return wrapper
return decorater
# ??inspect.Parameter ? kind ???5??
# POSITIONAL_ONLY ???????
# POSITIONAL_OR_KEYWORD ????????????????
# VAR_POSITIONAL ???? *args
# KEYWORD_ONLY ?????????key????? *,key
# VAR_KEYWORD ???? **kw
def test_signature_str_positional_only(self):
P = inspect.Parameter
def test(a_po, *, b, **kwargs):
return a_po, kwargs
sig = inspect.signature(test)
new_params = list(sig.parameters.values())
new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY)
test.__signature__ = sig.replace(parameters=new_params)
self.assertEqual(str(inspect.signature(test)),
'(<a_po>, *, b, **kwargs)')
sig = inspect.signature(test)
new_params = list(sig.parameters.values())
new_params[0] = new_params[0].replace(name=None)
test.__signature__ = sig.replace(parameters=new_params)
self.assertEqual(str(inspect.signature(test)),
'(<0>, *, b, **kwargs)')
def test_signature_bind_positional_only(self):
P = inspect.Parameter
def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs):
return a_po, b_po, c_po, foo, bar, kwargs
sig = inspect.signature(test)
new_params = collections.OrderedDict(tuple(sig.parameters.items()))
for name in ('a_po', 'b_po', 'c_po'):
new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY)
new_sig = sig.replace(parameters=new_params.values())
test.__signature__ = new_sig
self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6),
(1, 2, 4, 5, 6, {}))
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
self.call(test, 1, 2, c_po=4)
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
self.call(test, a_po=1, b_po=2)
def accepts_kwargs(function):
"""Returns ``True`` if function accepts kwargs otherwise ``False``."""
sig = get_signature(function)
return any(p.kind == Parameter.VAR_KEYWORD
for p in six.itervalues(sig.parameters))
def accepts_kwargs(function):
"""Returns ``True`` if function accepts kwargs otherwise ``False``."""
sig = get_signature(function)
return any(p.kind == Parameter.VAR_KEYWORD
for p in six.itervalues(sig.parameters))
def _wrap_maker(func):
def inner(*args, **kwargs):
chunks = kwargs.pop('chunks')
X, y = func(*args, **kwargs)
return (da.from_array(X, chunks=(chunks, X.shape[-1])),
da.from_array(y, chunks=chunks))
__all__.append(func.__name__)
if not six.PY2:
sig = inspect.signature(func)
params = list(sig.parameters.values())
# TODO(py3): Make this keyword-only
params.append(
inspect.Parameter("chunks",
inspect.Parameter.POSITIONAL_OR_KEYWORD,
default=None))
inner.__signature__ = sig.replace(parameters=params)
doc = func.__doc__.split("\n")
doc = [' ' + doc[0], chunks_doc] + doc[1:]
inner.__doc__ = dedent('\n'.join(doc))
inner.__name__ = func.__name__
inner.__module__ = __name__
return inner
def get_imports_for_annotation(anno: Any) -> ImportMap:
"""Return the imports (module, name) needed for the type in the annotation"""
imports = ImportMap()
if (
anno is inspect.Parameter.empty or
anno is inspect.Signature.empty or
not isinstance(anno, (type, _Any, _Union)) or
anno.__module__ == 'builtins'
):
return imports
if isinstance(anno, _Any):
imports['typing'].add('Any')
elif _is_optional(anno):
imports['typing'].add('Optional')
elem_type = _get_optional_elem(anno)
elem_imports = get_imports_for_annotation(elem_type)
imports.merge(elem_imports)
elif isinstance(anno, (_Union, GenericMeta)):
if isinstance(anno, _Union):
imports['typing'].add('Union')
else:
name = _get_import_for_qualname(anno.__qualname__)
imports[anno.__module__].add(name)
elem_types = anno.__args__ or []
for et in elem_types:
elem_imports = get_imports_for_annotation(et)
imports.merge(elem_imports)
else:
name = _get_import_for_qualname(anno.__qualname__)
imports[anno.__module__].add(name)
return imports
def update_signature_args(sig: inspect.Signature, arg_types: Dict[str, type], has_self: bool) -> inspect.Signature:
"""Update argument annotations with the supplied types"""
params = []
for arg_idx, name in enumerate(sig.parameters):
param = sig.parameters[name]
typ = arg_types.get(name)
# Don't touch pre-existing annotations and leave self un-annotated
if (typ is not None) and \
(param.annotation is inspect.Parameter.empty) and \
((not has_self) or (arg_idx != 0)):
param = param.replace(annotation=typ)
params.append(param)
return sig.replace(parameters=params)
def has_unparsable_defaults(sig: inspect.Signature) -> bool:
"""Return whether or not the reprs for all defaults in the signature are valid python expressions"""
for param in sig.parameters.values():
if param.default is inspect.Parameter.empty:
continue
try:
parser.expr(repr(param.default))
except SyntaxError:
return True
return False
def render_parameter(param: inspect.Parameter) -> str:
"""Convert a parameter into its stub representation.
NB: This is copied almost entirely from https://github.com/python/cpython/blob/3.6/Lib/inspect.py
with the modification that it calls our own rendering functions for annotations.
TODO: push a patch upstream so we don't have to do this on Python 3.x.
"""
kind = param.kind
formatted = param.name
# Add annotation and default value
if param.annotation is not inspect.Parameter.empty:
anno = param.annotation
if not _is_optional(anno) and param.default is None:
# we're constructing types at runtime and mypy is very confused
anno = Optional[anno] # type: ignore
rendered = render_annotation(anno)
formatted = '{}: {}'.format(formatted, rendered)
if param.default is not inspect.Parameter.empty:
formatted = '{} = {}'.format(formatted, repr(param.default))
if kind == inspect.Parameter.VAR_POSITIONAL:
formatted = '*' + formatted
elif kind == inspect.Parameter.VAR_KEYWORD:
formatted = '**' + formatted
return formatted
def _param_type_error(self, param, argname, argvalue):
paramname = "Vararg parameter" if param.kind == "VAR_POSITIONAL" else \
"Parameter `%s`" % argname
msg = param.checker.get_error_msg(paramname, argvalue)
return self._type_error(msg)
def source(self):
args = []
for p in self.params:
if p.has_default:
args.append(p.name + "=" + repr(p.default))
else:
args.append(p.name)
return "%s(%s)" % (self.function.__name__, ", ".join(args))
# ------------------------------------------------------------------------------
# Parameter
# ------------------------------------------------------------------------------
def __repr__(self):
return ("<Param '%s' %s%s>" %
(self.name,
Parameter.SHORT_POSITIONAL_NAME[self.kind],
" " + self._checker.name() if self._checker else ""))
def has_parameter_kind(func, kind):
"""
https://docs.python.org/3/library/inspect.html#inspect.signature
Returns: whether the func has a parameter kind
"""
P = inspect.Parameter
assert kind in [P.POSITIONAL_ONLY,
P.POSITIONAL_OR_KEYWORD,
P.VAR_POSITIONAL,
P.KEYWORD_ONLY,
P.VAR_KEYWORD]
return any(param for param in
inspect.signature(func).parameters.values()
if param.kind == kind)
def has_kwargs(func):
"""
Returns: whether the func accepts **kwargs
"""
return has_parameter_kind(func, inspect.Parameter.VAR_KEYWORD)
def has_varargs(func):
"""
Returns: whether the func accepts *args
"""
return has_parameter_kind(func, inspect.Parameter.VAR_POSITIONAL)
def test_signature_object(self):
S = inspect.Signature
P = inspect.Parameter
self.assertEqual(str(S()), '()')
def test(po, pk, *args, ko, **kwargs):
pass
sig = inspect.signature(test)
po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY)
pk = sig.parameters['pk']
args = sig.parameters['args']
ko = sig.parameters['ko']
kwargs = sig.parameters['kwargs']
S((po, pk, args, ko, kwargs))
with self.assertRaisesRegex(ValueError, 'wrong parameter order'):
S((pk, po, args, ko, kwargs))
with self.assertRaisesRegex(ValueError, 'wrong parameter order'):
S((po, args, pk, ko, kwargs))
with self.assertRaisesRegex(ValueError, 'wrong parameter order'):
S((args, po, pk, ko, kwargs))
with self.assertRaisesRegex(ValueError, 'wrong parameter order'):
S((po, pk, args, kwargs, ko))
kwargs2 = kwargs.replace(name='args')
with self.assertRaisesRegex(ValueError, 'duplicate parameter name'):
S((po, pk, args, kwargs2, ko))
def test_signature_parameter_kinds(self):
P = inspect.Parameter
self.assertTrue(P.POSITIONAL_ONLY < P.POSITIONAL_OR_KEYWORD < \
P.VAR_POSITIONAL < P.KEYWORD_ONLY < P.VAR_KEYWORD)
self.assertEqual(str(P.POSITIONAL_ONLY), 'POSITIONAL_ONLY')
self.assertTrue('POSITIONAL_ONLY' in repr(P.POSITIONAL_ONLY))
def test_signature_parameter_object(self):
p = inspect.Parameter('foo', default=10,
kind=inspect.Parameter.POSITIONAL_ONLY)
self.assertEqual(p.name, 'foo')
self.assertEqual(p.default, 10)
self.assertIs(p.annotation, p.empty)
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
with self.assertRaisesRegex(ValueError, 'invalid value'):
inspect.Parameter('foo', default=10, kind='123')
with self.assertRaisesRegex(ValueError, 'not a valid parameter name'):
inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError,
'non-positional-only parameter'):
inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
inspect.Parameter('a', default=42,
kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
inspect.Parameter('a', default=42,
kind=inspect.Parameter.VAR_POSITIONAL)
p = inspect.Parameter('a', default=42,
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
p.replace(kind=inspect.Parameter.VAR_POSITIONAL)
self.assertTrue(repr(p).startswith('<Parameter'))
def test_signature_parameter_equality(self):
P = inspect.Parameter
p = P('foo', default=42, kind=inspect.Parameter.KEYWORD_ONLY)
self.assertEqual(p, p)
self.assertNotEqual(p, 42)
self.assertEqual(p, P('foo', default=42,
kind=inspect.Parameter.KEYWORD_ONLY))
def test_signature_parameter_replace(self):
p = inspect.Parameter('foo', default=42,
kind=inspect.Parameter.KEYWORD_ONLY)
self.assertIsNot(p, p.replace())
self.assertEqual(p, p.replace())
p2 = p.replace(annotation=1)
self.assertEqual(p2.annotation, 1)
p2 = p2.replace(annotation=p2.empty)
self.assertEqual(p, p2)
p2 = p2.replace(name='bar')
self.assertEqual(p2.name, 'bar')
self.assertNotEqual(p2, p)
with self.assertRaisesRegex(ValueError, 'not a valid parameter name'):
p2 = p2.replace(name=p2.empty)
p2 = p2.replace(name='foo', default=None)
self.assertIs(p2.default, None)
self.assertNotEqual(p2, p)
p2 = p2.replace(name='foo', default=p2.empty)
self.assertIs(p2.default, p2.empty)
p2 = p2.replace(default=42, kind=p2.POSITIONAL_OR_KEYWORD)
self.assertEqual(p2.kind, p2.POSITIONAL_OR_KEYWORD)
self.assertNotEqual(p2, p)
with self.assertRaisesRegex(ValueError, 'invalid value for'):
p2 = p2.replace(kind=p2.empty)
p2 = p2.replace(kind=p2.KEYWORD_ONLY)
self.assertEqual(p2, p)
def test_signature_parameter_positional_only(self):
p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY)
self.assertEqual(str(p), '<>')
p = p.replace(name='1')
self.assertEqual(str(p), '<1>')
def test_signature_parameter_immutability(self):
p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY)
with self.assertRaises(AttributeError):
p.foo = 'bar'
with self.assertRaises(AttributeError):
p.kind = 123