Mypy (and PEP 484) currently allows using ellipsis as the default argument for functions defined inside stubs:
# Legal inside *.pyi files, but illegal inside *.py files -- we get the following error:
# "Incompatible default for argument "some_arg" (default has type "ellipsis", argument has type "int")"
def foo(some_arg: int = ...) -> None: pass
I propose generalizing the way mypy handles ellipsis default arguments so that the above becomes permitted for both stub files and regular files as long as the body of the function is either empty or contains just a raise SomeException(...) statement.
The main reason I want this is because I was trying to define a custom Callback protocol where one of the arguments accepted a mutable argument, like so:
class MyCallback(Protocol):
def __call__(self, foo: List[int] = ???) -> None: ...
Unfortunately, there doesn't seem to be an entirely clean way of supporting this:
foo: List[int] = [], but then I get warnings from my IDE and linter about having a mutable default argument.foo: Optional[List[int]] = None, but I don't actually want to allow None arguments.foo: List[int] = bogus, where bogus has type Any, but that causes another error when using the --disallow-any-explicit flag.You run into similar issues when trying to define overloads variants or abstract methods -- basically, function definitions that effectively exist only at "type-check time".
The restriction that you can only use ellipsis default arguments when the function body is missing/just throws an exception should hopefully help prevent the ellipsis from appearing in unexpected places and causing runtime errors.
I'd be willing to implement this myself (especially since this seems like a pretty low-priority feature, all things considered), but want to make sure the idea seems like a reasonable one first before investing the effort.
I like this idea, this can be useful for both protocols and ABCs.
Most helpful comment
I like this idea, this can be useful for both protocols and ABCs.