Private helper to calculate how 'wrapped_sig' signature will look like after applying a 'functools.partial' object (or alike) on it.
(wrapped_sig, partial, extra_args=())
| 1945 | |
| 1946 | |
| 1947 | def _signature_get_partial(wrapped_sig, partial, extra_args=()): |
| 1948 | """Private helper to calculate how 'wrapped_sig' signature will |
| 1949 | look like after applying a 'functools.partial' object (or alike) |
| 1950 | on it. |
| 1951 | """ |
| 1952 | |
| 1953 | old_params = wrapped_sig.parameters |
| 1954 | new_params = OrderedDict(old_params.items()) |
| 1955 | |
| 1956 | partial_args = partial.args or () |
| 1957 | partial_keywords = partial.keywords or {} |
| 1958 | |
| 1959 | if extra_args: |
| 1960 | partial_args = extra_args + partial_args |
| 1961 | |
| 1962 | try: |
| 1963 | ba = wrapped_sig.bind_partial(*partial_args, **partial_keywords) |
| 1964 | except TypeError as ex: |
| 1965 | msg = 'partial object {!r} has incorrect arguments'.format(partial) |
| 1966 | raise ValueError(msg) from ex |
| 1967 | |
| 1968 | |
| 1969 | transform_to_kwonly = False |
| 1970 | for param_name, param in old_params.items(): |
| 1971 | try: |
| 1972 | arg_value = ba.arguments[param_name] |
| 1973 | except KeyError: |
| 1974 | pass |
| 1975 | else: |
| 1976 | if param.kind is _POSITIONAL_ONLY: |
| 1977 | # If positional-only parameter is bound by partial, |
| 1978 | # it effectively disappears from the signature |
| 1979 | # However, if it is a Placeholder it is not removed |
| 1980 | # And also looses default value |
| 1981 | if arg_value is functools.Placeholder: |
| 1982 | new_params[param_name] = param.replace(default=_empty) |
| 1983 | else: |
| 1984 | new_params.pop(param_name) |
| 1985 | continue |
| 1986 | |
| 1987 | if param.kind is _POSITIONAL_OR_KEYWORD: |
| 1988 | if param_name in partial_keywords: |
| 1989 | # This means that this parameter, and all parameters |
| 1990 | # after it should be keyword-only (and var-positional |
| 1991 | # should be removed). Here's why. Consider the following |
| 1992 | # function: |
| 1993 | # foo(a, b, *args, c): |
| 1994 | # pass |
| 1995 | # |
| 1996 | # "partial(foo, a='spam')" will have the following |
| 1997 | # signature: "(*, a='spam', b, c)". Because attempting |
| 1998 | # to call that partial with "(10, 20)" arguments will |
| 1999 | # raise a TypeError, saying that "a" argument received |
| 2000 | # multiple values. |
| 2001 | transform_to_kwonly = True |
| 2002 | # Set the new default value |
| 2003 | new_params[param_name] = param.replace(default=arg_value) |
| 2004 | else: |
no test coverage detected
searching dependent graphs…