can’t create a type variable with a default on Python < 3.13 (false positive for invalid-legacy-type-variable)
Summary
https://play.ty.dev/1f971569-26a4-4e0b-bfd4-158f9d46fa7f
if TYPE_CHECKING or sys.version_info > (3, 13):
T = TypeVar("T", default=int)
else: # runtime on Python < 3.13
T = TypeVar("T")
outputs
The
defaultparameter oftyping.TypeVarwas added in Python 3.13 (invalid-legacy-type-variable) [Ln 5, Col 22]
yeah I know, that’s why I only specify it in valid contexts.
Version
0.0.3
Thanks! Definitely a bug. We need to suppress this error when we can see we're in unreachable code blocks
Is this a bug? If I change the or to an and (or drop TYPE_CHECKING completely) ty detects the correct branch is Never then updating python version in ty.json to 3.14 the Never branches switch places and ty is still happy. 🤔
https://play.ty.dev/e1f55066-d80f-436a-b7dd-5336c6951107
Ah, good point @sinon.
Hmm, yes, it looks like we've correctly deduced that the first branch is always reachable, because you've used an or rather than an and, @flying-sheep, and TYPE_CHECKING is treated as always-true by type checkers. Because the first branch is always reachable, we'll therefore emit the diagnostic there. You can make ty happy by doing something like this:
import sys
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# type checkers think typing_extensions is part of the stdlib,
# so it's fine to import in an `if TYPE_CHECKING` block
# even if it's not a dependency
from typing_extensions import TypeVar
T = TypeVar("T", default=int)
elif sys.version_info >= (3, 13):
from typing import TypeVar
T = TypeVar("T", default=int)
else:
from typing import TypeVar
T = TypeVar("T")
But that's admittedly a bit verbose. We could consider just switching this specific rule off if we see you're in an if TYPE_CHECKING block?
@sinon, I updated the playground link to show why your suggestion doesn’t work: https://play.ty.dev/1f971569-26a4-4e0b-bfd4-158f9d46fa7f
I of course want to actually use the TypeVar’s default, which wouldn’t exist anymore if you change the logic to and:
Type
intdoes not match asserted typeUnknown(type-assertion-failure) [Ln 12, Col 1]
The else branch is there to be executed at runtime and needs to be be ignored at type checking time.
We could consider just switching this specific rule off if we see you're in an if
TYPE_CHECKINGblock?
@AlexWaygood yeah, that would work! If type checkers treat typing_extensions as special in a type checking block, they can also treat later feature addition to typing APIs (like default) in a special way.