Skip to content

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

@dmtrs

Description

@dmtrs
    @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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions