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

[spec] Can staticmethod calls infer type parameters for the containing class? #1845

Open
comex opened this issue Aug 19, 2024 · 1 comment
Open
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@comex
Copy link

comex commented Aug 19, 2024

In this code:

from typing import TypeVar, Generic
T = TypeVar('T')

class Foo(Generic[T]):
    @staticmethod
    def create(arg: T) -> 'Foo[T]':
        ...

reveal_type(Foo.create(1234))

What should the type be? Should T be inferred based on the argument to the static method, resulting in Foo[int]? Or should it be Foo[Unknown] or similar?

mypy (python/mypy@fe15ee69b) picks Foo[int].

pyright used to choose Foo[int], but microsoft/pyright#7454 changed it to pick Foo[Unknown], on the grounds that this is required to comply with PEP 696's statement:

Type parameter defaults should be bound by attribute access (including call and subscript).

My example does not include any type parameter defaults, but I can see the logic of applying the same rule without one: you wouldn't want it to be a breaking change to add a default.

Still, why can't these kinds of static method calls be treated like constructor calls, where class type parameters can be inferred from arguments?

@comex comex added the topic: feature Discussions about new features for Python's type annotations label Aug 19, 2024
@erictraut
Copy link
Collaborator

erictraut commented Aug 19, 2024

This is currently under-specified in the typing spec, and we should eventually address this hole. At a recent typing meetup, I presented a list of potential typing spec priorities, and you'll fine this on the list ("staticmethod and classmethod" and "Binding a class or object to a method or attribute").

The reason I made this change in pyright is because recent clarifications in the constructor chapter of the spec plus the portion of the spec adopted from PEP 696 strongly imply that non-constructor calls to a class (including static methods and class methods) require specialization prior to binding. This specialization can be explicit (like Foo[int]) or implicit (like Foo). If it is implicit, the specialization comes from the default type arguments. If no such defaults are provided, they default to Any (for TypeVars), ... (for ParamSpecs) and tuple[Any, ...] (for TypeVarTuples).

Mypy has not yet implemented full support for PEP 696, so that might explain why its behavior differs from pyright in this case.

If we were to spec a different behavior for "these kinds of static method calls", we'd need to specify what types of static methods would be impacted and which would not. Or perhaps you're proposing that all static methods should act this way? Regardless, we'd need to specify how this interacts with PEP 696 defaults. We would presumably need to adopt some language similar to that found in this section about __new__ methods. We would also need to decide whether class methods should also get some sort of a carve-out under some or all circumstances.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

2 participants