Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValueError: no signature found for builtin type <class 'collections.defaultdict'> #5

Open
dmtrs opened this issue Mar 30, 2021 · 0 comments

Comments

@dmtrs
Copy link
Owner

dmtrs commented Mar 30, 2021

    @pytest.mark.asyncio
    async def test_gotcha() -> None:

        async def foo(r: Dict[str, str] = defaultdict() ) -> Dict[str, str]:
            return r

        assert await foo() is await foo()

        @dependant
>       async def bar(r: Dict[str, str] = Depends(defaultdict)) -> Dict[str, str]:

tests/test_examples.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
dependable/decorator.py:15: in __init__
    self.dependant: Dependant = get_dependant(call=call)
dependable/utils.py:109: in get_dependant
    sub_dependant = get_param_sub_dependant(param=param)
dependable/utils.py:89: in get_param_sub_dependant
    return get_dependant(
dependable/utils.py:102: in get_dependant
    call_signature = get_typed_signature(call)
dependable/utils.py:65: in get_typed_signature
    signature = inspect.signature(call)
/usr/local/lib/python3.9/inspect.py:3130: in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
/usr/local/lib/python3.9/inspect.py:2879: in from_callable
    return _signature_from_callable(obj, sigcls=cls,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

obj = <class 'collections.defaultdict'>

    def _signature_from_callable(obj, *,
                                 follow_wrapper_chains=True,
                                 skip_bound_arg=True,
                                 sigcls):

        """Private helper function to get signature for arbitrary
        callable objects.
        """

        if not callable(obj):
            raise TypeError('{!r} is not a callable object'.format(obj))

        if isinstance(obj, types.MethodType):
            # In this case we skip the first parameter of the underlying
            # function (usually `self` or `cls`).
            sig = _signature_from_callable(
                obj.__func__,
                follow_wrapper_chains=follow_wrapper_chains,
                skip_bound_arg=skip_bound_arg,
                sigcls=sigcls)

            if skip_bound_arg:
                return _signature_bound_method(sig)
            else:
                return sig

        # Was this function wrapped by a decorator?
        if follow_wrapper_chains:
            obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))
            if isinstance(obj, types.MethodType):
                # If the unwrapped object is a *method*, we might want to
                # skip its first parameter (self).
                # See test_signature_wrapped_bound_method for details.
                return _signature_from_callable(
                    obj,
                    follow_wrapper_chains=follow_wrapper_chains,
                    skip_bound_arg=skip_bound_arg,
                    sigcls=sigcls)

        try:
            sig = obj.__signature__
        except AttributeError:
            pass
        else:
            if sig is not None:
                if not isinstance(sig, Signature):
                    raise TypeError(
                        'unexpected object {!r} in __signature__ '
                        'attribute'.format(sig))
                return sig

        try:
            partialmethod = obj._partialmethod
        except AttributeError:
            pass
        else:
            if isinstance(partialmethod, functools.partialmethod):
                # Unbound partialmethod (see functools.partialmethod)
                # This means, that we need to calculate the signature
                # as if it's a regular partial object, but taking into
                # account that the first positional argument
                # (usually `self`, or `cls`) will not be passed
                # automatically (as for boundmethods)

                wrapped_sig = _signature_from_callable(
                    partialmethod.func,
                    follow_wrapper_chains=follow_wrapper_chains,
                    skip_bound_arg=skip_bound_arg,
                    sigcls=sigcls)

                sig = _signature_get_partial(wrapped_sig, partialmethod, (None,))
                first_wrapped_param = tuple(wrapped_sig.parameters.values())[0]
                if first_wrapped_param.kind is Parameter.VAR_POSITIONAL:
                    # First argument of the wrapped callable is `*args`, as in
                    # `partialmethod(lambda *args)`.
                    return sig
                else:
                    sig_params = tuple(sig.parameters.values())
                    assert (not sig_params or
                            first_wrapped_param is not sig_params[0])
                    new_params = (first_wrapped_param,) + sig_params
                    return sig.replace(parameters=new_params)

        if isfunction(obj) or _signature_is_functionlike(obj):
            # If it's a pure Python function, or an object that is duck type
            # of a Python function (Cython functions, for instance), then:
            return _signature_from_function(sigcls, obj,
                                            skip_bound_arg=skip_bound_arg)

        if _signature_is_builtin(obj):
            return _signature_from_builtin(sigcls, obj,
                                           skip_bound_arg=skip_bound_arg)

        if isinstance(obj, functools.partial):
            wrapped_sig = _signature_from_callable(
                obj.func,
                follow_wrapper_chains=follow_wrapper_chains,
                skip_bound_arg=skip_bound_arg,
                sigcls=sigcls)
            return _signature_get_partial(wrapped_sig, obj)

        sig = None
        if isinstance(obj, type):
            # obj is a class or a metaclass

            # First, let's see if it has an overloaded __call__ defined
            # in its metaclass
            call = _signature_get_user_defined_method(type(obj), '__call__')
            if call is not None:
                sig = _signature_from_callable(
                    call,
                    follow_wrapper_chains=follow_wrapper_chains,
                    skip_bound_arg=skip_bound_arg,
                    sigcls=sigcls)
            else:
                # Now we check if the 'obj' class has a '__new__' method
                new = _signature_get_user_defined_method(obj, '__new__')
                if new is not None:
                    sig = _signature_from_callable(
                        new,
                        follow_wrapper_chains=follow_wrapper_chains,
                        skip_bound_arg=skip_bound_arg,
                        sigcls=sigcls)
                else:
                    # Finally, we should have at least __init__ implemented
                    init = _signature_get_user_defined_method(obj, '__init__')
                    if init is not None:
                        sig = _signature_from_callable(
                            init,
                            follow_wrapper_chains=follow_wrapper_chains,
                            skip_bound_arg=skip_bound_arg,
                            sigcls=sigcls)

            if sig is None:
                # At this point we know, that `obj` is a class, with no user-
                # defined '__init__', '__new__', or class-level '__call__'

                for base in obj.__mro__[:-1]:
                    # Since '__text_signature__' is implemented as a
                    # descriptor that extracts text signature from the
                    # class docstring, if 'obj' is derived from a builtin
                    # class, its own '__text_signature__' may be 'None'.
                    # Therefore, we go through the MRO (except the last
                    # class in there, which is 'object') to find the first
                    # class with non-empty text signature.
                    try:
                        text_sig = base.__text_signature__
                    except AttributeError:
                        pass
                    else:
                        if text_sig:
                            # If 'obj' class has a __text_signature__ attribute:
                            # return a signature based on it
                            return _signature_fromstr(sigcls, obj, text_sig)

                # No '__text_signature__' was found for the 'obj' class.
                # Last option is to check if its '__init__' is
                # object.__init__ or type.__init__.
                if type not in obj.__mro__:
                    # We have a class (not metaclass), but no user-defined
                    # __init__ or __new__ for it
                    if (obj.__init__ is object.__init__ and
                        obj.__new__ is object.__new__):
                        # Return a signature of 'object' builtin.
                        return sigcls.from_callable(object)
                    else:
>                       raise ValueError(
                            'no signature found for builtin type {!r}'.format(obj))
E                       ValueError: no signature found for builtin type <class 'collections.defaultdict'>

/usr/local/lib/python3.9/inspect.py:2410: ValueError
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant