Skip to content

Generic, higher kinded function not sharing Callable’s limitations #13107

Closed
@flying-sheep

Description

@flying-sheep

Documentation

I can define the following decorator:

P = ParamSpec('P')
R = TypeVar('R', covariant=True)

def file_cache(fn: Callable[Concatenate[Path, P], R]) -> Callable[P, R]:
    path: Path = ...
    def wrapper(*args: P.args, **kw: P.kwargs) -> R:
        if path.is_file():
            return read(path)
        return fn(path, *args, **kw)
    return wrapper

But Callable is limited to kwargs-less functions, so mypy complains when I apply the decorator to a function, and try to specify the keyword argument:

@file_cache
def get_thing(path: Path, *, some_arg: int) -> X:
    x = calculate_x()
    path.write_bytes(x.serialize())
    return x

if __name__ == '__main__':
    get_thing(some_arg=1)
error: Unexpected keyword argument "some_arg" for "get_thing"

In an attempt to circumvent the problem, I tried to define the following, but mypy doesn’t seem to understand it:

P = ParamSpec('P')
R = TypeVar('R', covariant=True)


class Function(Protocol[P, R]):
    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
        ...

And will complain that the decorated function was a Callable[[Path, DefaultNamedArg(int, 'some_arg')], X, not a Function[<nothing>, <nothing>].

If I made a mistake in defining Function, please help.

If it looks correct: a) why doesn’t it exist / why is Callable so limited? and b) mypy should understand my definition.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions