Exemple #1
0
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)
Exemple #2
0
    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)
Exemple #3
0
    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
Exemple #4
0
    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'))
Exemple #5
0
    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
Exemple #6
0
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)
Exemple #7
0
 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)
Exemple #8
0
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')
Exemple #9
0
    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)
Exemple #10
0
    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