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

Constructor call within generic class confuses type arguments #7507

Open
erictraut opened this issue Mar 17, 2024 · 6 comments
Open

Constructor call within generic class confuses type arguments #7507

erictraut opened this issue Mar 17, 2024 · 6 comments
Labels
bug Something isn't working

Comments

@erictraut
Copy link
Collaborator

A regression introduced in 1.1.337 breaks the following:

from typing import Generic, TypeVar

T = TypeVar("T")
U = TypeVar("U")


class Test2(Generic[T, U]):
    def __init__(self):
        pass

    def test2(self) -> None:
        x1: Test2[U, T]

        x1 = Test2[U, T]()

This should have been caught by the constructor26.py unit test, but it was not.

This is related to #7369.

@erictraut erictraut added the bug Something isn't working label Mar 17, 2024
@peku33
Copy link

peku33 commented Mar 26, 2024

I am not sure if this is related, but recently this started to raise "type is partially unknown" error:

from typing import Generic, Self, TypeVar


T = TypeVar("T")

class Test(Generic[T]):
    @classmethod
    def make(cls, type_: type[T]) -> Self:
        raise NotImplementedError()
    
t = Test.make(int)

in previous versions t was recognized as Test[int], but now it shows Test[Unknown] and two errors are reported:

Type of "make" is partially unknown
  Type of "make" is "(type_: Unknown) -> Test[Unknown]"

and

Type of "t" is partially unknown
  Type of "t" is "Test[Unknown]"

@erictraut
Copy link
Collaborator Author

I am not sure if this is related

This isn't related. The behavior you're seeing here was due to a recent change for spec compliance. The current behavior is correct. Since you haven't specified a type argument for the Test class, it defaults to Unknown when binding Test to the make class method.

@peku33
Copy link

peku33 commented Mar 26, 2024

Okay, but isn't the type_ parameter with type T forcing return type to also be specialized with T?

Do you know what is the current approach to specialize a classmethod returning Self with concrete type from one of its arguments?

@erictraut
Copy link
Collaborator Author

Do you know what is the current approach to specialize a classmethod returning Self with concrete type from one of its arguments?

If you want to use a classmethod in this manner, you would need explicitly specialize the class that you're binding to the class method.

t = Test[int].make(int)

Or if you're using the new PEP 696 TypeVar defaults, you can rely on the default value of the TypeVar.

from typing import Generic, Self
from typing_extensions import TypeVar

T = TypeVar("T", default=int)

class Test(Generic[T]):
    @classmethod
    def make(cls, type_: type[T]) -> Self:
        raise NotImplementedError()

t = Test.make(int)

@peku33
Copy link

peku33 commented Mar 26, 2024

Okay, can you provide more details (any source to read more details) on change for spec compliance? mypy in current version reveals type correctly (as pyright in previous versions) and does not require this double typing. I would like to understand in which scenario (and why) the same T in type_: type[T] and Generic[T] refer to different types, so return type is unknown.

@erictraut
Copy link
Collaborator Author

erictraut commented Mar 27, 2024

We're quite off topic for this issue, but since you asked... This was previously an under-specified (and somewhat ambiguous) part of the typing spec, but the recent adoption of PEP 696 clarifies how this must work. The PEP 696 specification was recently incorporated into the official Python typing spec. The latest published version of mypy (1.9) doesn't have support for PEP 696, but the next version (1.10) will have partial (possibly complete) support.

@erictraut erictraut changed the title Regression: Constructor call within generic class confuses type arguments Constructor call within generic class confuses type arguments May 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants