def _np_signature(f): """An enhanced funcsigs.signature that can handle numpy.ufunc.""" if not isinstance(f, np.ufunc): return funcsigs.signature(f) def names_from_num(prefix, n): if n <= 0: return [] elif n == 1: return [prefix] else: return [prefix + str(i + 1) for i in range(n)] input_names = names_from_num('x', f.nin) output_names = names_from_num('out', f.nout) keyword_only_params = [ ('where', True), ('casting', 'same_kind'), ('order', 'K'), ('dtype', None), ('subok', True), ('signature', None), ('extobj', None)] params = [] params += [funcsigs.Parameter(name, funcsigs.Parameter.POSITIONAL_ONLY) for name in input_names] if f.nout > 1: params += [funcsigs.Parameter(name, funcsigs.Parameter.POSITIONAL_ONLY, default=None) for name in output_names] params += [funcsigs.Parameter( 'out', funcsigs.Parameter.POSITIONAL_OR_KEYWORD, default=None if f.nout == 1 else (None,) * f.nout)] params += [funcsigs.Parameter(name, funcsigs.Parameter.KEYWORD_ONLY, default=default) for name, default in keyword_only_params] return funcsigs.Signature(params)
def test_signature_parameter_unhashable(self): p = inspect.Parameter('foo', default=42, kind=inspect.Parameter.KEYWORD_ONLY) with self.assertRaisesRegex(TypeError, 'unhashable type'): hash(p)
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
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 __signature__(self): if hasattr(self, '__customsig'): return self.__customsig kwargs = [] for param in self.PARAMETERS: kwargs.append(funcsigs.Parameter(param.name, default=param.default, kind=funcsigs.Parameter.POSITIONAL_OR_KEYWORD)) self.__customsig = funcsigs.Signature(kwargs, __validate_parameters__=True) return self.__customsig
def extract_signature_and_value(func_or_str, default_parameters=None): if not inspect.isfunction(func_or_str): if default_parameters is None: parameters = [] else: kind = funcsigs.Parameter.POSITIONAL_OR_KEYWORD parameters = [funcsigs.Parameter(name, kind=kind) for name in default_parameters] return funcsigs.Signature(parameters), func_or_str signature = funcsigs.signature(func_or_str) # pass mock values to extract the value args = [None] * len(signature.parameters) return signature, func_or_str(*args)
def __init__(self, pinfo): self.name = pinfo['name'] self.py_name = pinfo['name'].replace('.', '_').replace('-', '_') self.defaultValue = pinfo.get('defaultValue') self.paramType = pinfo['paramType'] func_param_kwargs = {} if 'defaultValue' in pinfo: func_param_kwargs['default'] = pinfo['defaultValue'] if 'required' not in pinfo: func_param_kwargs['default'] = None if self.paramType in ('path', 'body'): sig_ptype = funcsigs.Parameter.POSITIONAL_OR_KEYWORD else: sig_ptype = funcsigs.Parameter.KEYWORD_ONLY self.func_param = funcsigs.Parameter(self.py_name, sig_ptype, **func_param_kwargs)
def template_def(signature, code): """ Returns a ``Mako`` template with the given ``signature``. :param signature: a list of postitional argument names, or a ``Signature`` object from ``funcsigs`` module. :code: a body of the template. """ if not isinstance(signature, funcsigs.Signature): # treating ``signature`` as a list of positional arguments # HACK: Signature or Parameter constructors are not documented. kind = funcsigs.Parameter.POSITIONAL_OR_KEYWORD signature = funcsigs.Signature([funcsigs.Parameter(name, kind=kind) for name in signature]) template_src = "<%def name='_func" + str(signature) + "'>\n" + code + "\n</%def>" return template_from(template_src).get_def('_func')
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 args_from(original_function, only=None, allexcept=None, inject_kwargs=None, inject_docs=None, wraps=None, update_docstring_args=False): """ Decorator to transfer call signatures - helps to hide ugly *args and **kwargs in delegated calls Args: original_function (callable): the function to take the call signature from only (List[str]): only transfer these arguments (incompatible with `allexcept`) wraps (bool): Transfer documentation and attributes from original_function to decorated_function, using functools.wraps (default: True if call signature is unchanged, False otherwise) allexcept (List[str]): transfer all except these arguments (incompatible with `only`) inject_kwargs (dict): Inject new kwargs into the call signature (of the form ``{argname: defaultvalue}``) inject_docs (dict): Add or modifies argument documentation (requires google-style docstrings) with a dict of the form `{argname: "(type): description"}` update_docstring_args (bool): Update "arguments" section of the docstring using the original function's documentation (requires google-style docstrings and wraps=False) Note: To use arguments from a classes' __init__ method, pass the class itself as ``original_function`` - this will also allow us to inject the documentation Returns: Decorator function """ # NEWFEATURE - verify arguments? if only and allexcept: raise ValueError('Error in keyword arguments - ' 'pass *either* "only" or "allexcept", not both') origname = get_qualified_name(original_function) if hasattr(original_function, '__signature__'): sig = original_function.__signature__.replace() else: sig = funcsigs.signature(original_function) # Modify the call signature if necessary if only or allexcept or inject_kwargs: wraps = if_not_none(wraps, False) newparams = [] if only: for param in only: newparams.append(sig.parameters[param]) elif allexcept: for name, param in sig.parameters.items(): if name not in allexcept: newparams.append(param) else: newparams = list(sig.parameters.values()) if inject_kwargs: for name, default in inject_kwargs.items(): newp = funcsigs.Parameter(name, funcsigs.Parameter.POSITIONAL_OR_KEYWORD, default=default) newparams.append(newp) newparams.sort(key=lambda param: param._kind) sig = sig.replace(parameters=newparams) else: wraps = if_not_none(wraps, True) # Get the docstring arguments if update_docstring_args: original_docs = GoogleDocArgumentInjector(original_function.__doc__) argument_docstrings = collections.OrderedDict((p.name, original_docs.args[p.name]) for p in newparams) def decorator(f): """Modify f's call signature (using the `__signature__` attribute)""" if wraps: fname = original_function.__name__ f = functools.wraps(original_function)(f) f.__name__ = fname # revert name change else: fname = f.__name__ f.__signature__ = sig if update_docstring_args or inject_kwargs: if not update_docstring_args: argument_docstrings = GoogleDocArgumentInjector(f.__doc__).args docs = GoogleDocArgumentInjector(f.__doc__) docs.args = argument_docstrings if not hasattr(f, '__orig_docs'): f.__orig_docs = [] f.__orig_docs.append(f.__doc__) f.__doc__ = docs.new_docstring() # Only for building sphinx documentation: if os.environ.get('SPHINX_IS_BUILDING_DOCS', ""): sigstring = '%s%s\n' % (fname, sig) if hasattr(f, '__doc__') and f.__doc__ is not None: f.__doc__ = sigstring + f.__doc__ else: f.__doc__ = sigstring return f return decorator