Esempio n. 1
0
    def __init__(self, **kwds):

        for key, val in kwds.items():
            setattr(self, key, val)

        # Sanity checks
        required = [
            'compute',
        ]
        for key in required:
            if not getattr(self, key):
                raise ValueError(
                    "{} needs to be defined during instantiation.".format(key))

        # Extract information from the `compute` function.
        # The signature
        self._sig = signature(self.compute)

        # The input parameter names
        self._parameters = tuple(self._sig.parameters.keys())
        #        self._input_params = [p for p in self._sig.parameters.values() if p.default is p.empty]
        #        self._nvar = len(self._input_params)

        # Copy the docstring and signature
        self.__call__ = wraps(self.compute)(self.__call__.__func__)
        if self.doc_template is not None:
            self.__call__.__doc__ = self.doc_template.format(i=self)

        # Fill in missing metadata from the doc
        meta = parse_doc(self.compute.__doc__)
        for key in ['abstract', 'title', 'long_name', 'notes', 'references']:
            setattr(self, key, getattr(self, key) or meta.get(key, ''))
Esempio n. 2
0
    def __init__(self, **kwds):
        """Run checks and organizes the metadata."""
        # keywords of kwds that are class attributes have already been set in __new__
        self.check_identifier(self.identifier)
        if self.missing == "from_context" and self.missing_options is not None:
            raise ValueError(
                "Cannot set `missing_options` with `missing` method being from context."
            )

        # Validate hard-coded missing options
        kls = MISSING_METHODS[self.missing]
        self._missing = kls.execute
        if self.missing_options:
            kls.validate(**self.missing_options)

        # Validation is done : register the instance.
        super().__init__()

        # The `compute` signature
        self._sig = signature(self.compute)

        # The input parameters' name
        self._parameters = tuple(self._sig.parameters.keys())

        # Copy the docstring and signature
        self.__call__ = wraps(self.compute)(self.__call__)
Esempio n. 3
0
def sym_to_num(fun, *args):
    """
    Convert sympy function to numpy function,
    with the output shape broadcasted to the shape
    of the sum of all arguments.

    This is required in case one or more arguments
    are not used explicity in the formula.
    """

    f = fu.wraps(fun)(sp.lambdify(args, fun(*args), modules=("numpy", )))

    @fu.wraps(fun)
    def wrapper(*inner_args):
        """
        Reshape output to always match broadcasted
        sum of inputs, even if they are not all
        explicitly used in the function.
        """
        array_args = map(np.array, inner_args)
        shape = np.shape(sum(array_args))
        ans = f(*inner_args)
        return np.broadcast_to(ans, shape)

    return wrapper
Esempio n. 4
0
def test_wraps_hide_wrapped():
    new_func = wraps(wrappable_func,
                     injected='b')(lambda a: wrappable_func(a, b=1))
    new_sig = inspect.signature(new_func, follow_wrapped=True)

    assert list(new_sig.parameters.keys()) == ['a', 'b']

    new_func = wraps(wrappable_func, injected='b',
                     hide_wrapped=True)(lambda a: wrappable_func(a, b=1))
    new_sig = inspect.signature(new_func, follow_wrapped=True)

    assert list(new_sig.parameters.keys()) == ['a']

    new_func = wraps(wrappable_func,
                     injected='b')(lambda a: wrappable_func(a, b=1))
    new_new_func = wraps(new_func, injected='a',
                         hide_wrapped=True)(lambda: new_func(a=1))
    new_new_sig = inspect.signature(new_new_func, follow_wrapped=True)

    assert len(new_new_sig.parameters) == 0
def test_wraps_inner_kwarg_only():
    """from https://github.com/mahmoud/boltons/issues/261

    mh responds to the issue:

    You'll notice that when kw-only args are involved the first time
    (wraps(f)(g)) it works fine. The other way around, however,
    wraps(g)(f) fails, because by the very nature of funcutils.wraps,
    you're trying to give f the same signature as g. And f's signature
    is not like g's. g supports positional b and f() does not.

    If you want to make a wrapper which converts a keyword-only
    argument to one that can be positional or keyword only, that'll
    require a different approach for now.

    A potential fix would be to pass all function arguments as
    keywords. But doubt that's the right direction, because, while I
    have yet to add positional argument only support, that'll
    definitely throw a wrench into things.
    """
    from boltons.funcutils import wraps

    def g(a: float, b=10):
        return a * b

    def f(a: int, *, b=1):
        return a * b

    # all is well here...
    assert f(3) == 3
    assert g(3) == 30
    assert wraps(f)(g)(
        3) == 3  # yay, g got the f default (not so with functools.wraps!)

    # but this doesn't work
    with pytest.raises(TypeError):
        wraps(g)(f)(3)

    return
    def darkhelm_inject_loop(func):
        sig = inspect.signature(func)
        loop_param = sig.parameters['loop'].replace(default=None)
        sig = sig.replace(parameters=[loop_param])

        def add_loop(args, kwargs):
            bargs = sig.bind(*args, **kwargs)
            bargs.apply_defaults()
            if bargs.arguments['loop'] is None:
                bargs.arguments['loop'] = "don't look at me, I just use gevent"

            return bargs.arguments

        def wrapper(*args, **kwargs):
            return func(**add_loop(args, kwargs))

        return wraps(func, injected=['loop'])(wrapper)
Esempio n. 7
0
    def darkhelm_inject_loop(func):
        sig = inspect.signature(func)
        loop_param = sig.parameters['loop'].replace(default=None)
        sig = sig.replace(parameters=[loop_param])

        def add_loop(args, kwargs):
            bargs = sig.bind(*args, **kwargs)
            bargs.apply_defaults()
            if bargs.arguments['loop'] is None:
                bargs.arguments['loop'] = "don't look at me, I just use gevent"

            return bargs.arguments

        def wrapper(*args, **kwargs):
            return func(**add_loop(args, kwargs))

        return wraps(func, injected=['loop'])(wrapper)
Esempio n. 8
0
    def __init__(self, **kwds):

        # Set instance attributes.
        for key, val in kwds.items():
            setattr(self, key, val)

        # Verify that the identifier is a proper slug
        if not re.match(r"^[-\w]+$", self.identifier):
            warnings.warn(
                "The identifier contains non-alphanumeric characters. It could make life "
                "difficult for downstream software reusing this class.",
                UserWarning,
            )

        # Default value for `var_name` is the `identifier`.
        if self.var_name == "":
            self.var_name = self.identifier

        # Extract information from the `compute` function.
        # The signature
        self._sig = signature(self.compute)

        # The input parameter names
        self._parameters = tuple(self._sig.parameters.keys())
        #        self._input_params = [p for p in self._sig.parameters.values() if p.default is p.empty]
        #        self._nvar = len(self._input_params)

        # Copy the docstring and signature
        self.__call__ = wraps(self.compute)(self.__call__.__func__)
        if self.doc_template is not None:
            self.__call__.__doc__ = self.doc_template.format(i=self)

        # Fill in missing metadata from the doc
        meta = parse_doc(self.compute.__doc__)
        for key in ["abstract", "title", "notes", "references"]:
            setattr(self, key, getattr(self, key) or meta.get(key, ""))