Skip to content

Commit 5cb1da5

Browse files
committed
Eliminate use of Type Parameter Syntax, which only works on Python >= 3.12
1 parent 9dcfc23 commit 5cb1da5

File tree

10 files changed

+171
-4
lines changed

10 files changed

+171
-4
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import typing
2+
import typing_extensions
3+
4+
assert typing.Required is typing_extensions.Required
5+
assert typing.NotRequired is typing_extensions.NotRequired
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import typing
2+
import typing_extensions
3+
4+
assert typing.Required is typing_extensions.Required
5+
assert typing.NotRequired is typing_extensions.NotRequired

INPUTS/required/required.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from typing import TypedDict, Tuple, Union
2+
from typing_extensions import NotRequired, Required
3+
4+
5+
# --- Class Based TypedDict ---
6+
class Movie(TypedDict, total=False):
7+
title: Required[str] # 5
8+
year: int
9+
10+
11+
m = Movie(title='The Matrix', year=1999)
12+
# m = Movie()
13+
print(m)
14+
15+
16+
# --- Assignment Based TypedDict ---
17+
Movie2 = TypedDict('Movie2', {
18+
'title': Required[str],
19+
'year': int,
20+
}, total=False)
21+
22+
23+
m2 = Movie2(title='The Matrix Reloaded', year=2003)
24+
# m2 = Movie2()
25+
print(m2)
26+
27+
28+
# --- Required[] outside of TypedDict (error) ---
29+
x: int = 5
30+
# x: Required[int] = 5
31+
32+
33+
# --- Required[] inside other Required[] (error) ---
34+
'''
35+
Movie3 = TypedDict('Movie3', {
36+
'title': Required[Union[
37+
Required[str],
38+
bytes
39+
]],
40+
'year': int,
41+
}, total=False)
42+
'''
43+
44+
45+
# --- Required[] used within TypedDict but not at top level (error) ---
46+
'''
47+
Movie4 = TypedDict('Movie4', {
48+
'title': Union[
49+
Required[str],
50+
bytes
51+
],
52+
'year': int,
53+
}, total=False)
54+
Movie5 = TypedDict('Movie5', {
55+
'title': Tuple[
56+
Required[str],
57+
bytes
58+
],
59+
'year': int,
60+
}, total=False)
61+
'''
62+
63+
64+
# ==============================================================================
65+
# --- Class Based TypedDict ---
66+
class MovieN(TypedDict):
67+
title: str
68+
year: NotRequired[int]
69+
70+
71+
m = MovieN(title='The Matrix', year=1999)
72+
# m = MovieN()
73+
print(m)
74+
75+
76+
# --- Assignment Based TypedDict ---
77+
MovieN2 = TypedDict('MovieN2', {
78+
'title': str,
79+
'year': NotRequired[int],
80+
})
81+
82+
83+
m2 = MovieN2(title='The Matrix Reloaded', year=2003)
84+
# m2 = MovieN2()
85+
print(m2)

INPUTS/required/required_py3_11.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import typing
2+
3+
class Movie(typing.TypedDict):
4+
title: str
5+
year: typing.NotRequired[int]
6+
7+
m = Movie(title='The Matrix')
8+
print(m)

INPUTS/test_typeform.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from typing import Any, Callable, cast, Never, NoReturn, Optional, reveal_type, Type, TypeVar, TypedDict
2+
from typing_extensions import TypeForm, TypeGuard
3+
4+
dict_with_typx_keys: dict[TypeForm, int] = {
5+
int | str: 1,
6+
str | None: 2,
7+
}
8+
dict_with_typx_keys[int | str] += 1
9+
10+
#typx1: TypeForm[int | str] = 'int | str' # OK
11+
#typx2: TypeForm[int] = 'str' # E: Incompatible types in assignment (expression has type "TypeForm[str]", variable has type "TypeForm[int]")
12+
13+
'''
14+
from typing import Any
15+
16+
T = TypeVar('T')
17+
18+
def as_typeform(typx: TypeForm[T]) -> TypeForm[T]:
19+
return typx
20+
21+
def as_type(typx: TypeForm[T]) -> Type[T] | None:
22+
if isinstance(typx, type):
23+
return typx
24+
else:
25+
return None
26+
27+
def as_instance(typx: TypeForm[T]) -> T | None:
28+
if isinstance(typx, type):
29+
return typx()
30+
else:
31+
return None
32+
33+
reveal_type(as_typeform(int | str)) # actual=TypeForm[Never], expect=TypeForm[int | str]
34+
reveal_type(as_type(int | str))
35+
reveal_type(as_type(int))
36+
reveal_type(as_instance(int | str))
37+
reveal_type(as_instance(int))
38+
'''

INPUTS/typeform_assign_to_alias.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from typing import TypeAlias, reveal_type
2+
3+
alias: TypeAlias = int | None
4+
reveal_type(alias)
5+

INPUTS/typeform_assignment.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
typ: type
2+
typ = int
3+
4+
# E: Incompatible types in assignment (expression has type "UnionType", variable has type "type") [assignment]
5+
typ = str | None
6+
7+
#from typing_extensions import TypeExpr as TypeForm
8+
#typx: TypeForm
9+
#typx = int | None

INPUTS/typeform_call.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def expect_type(typ: type) -> None:
2+
pass
3+
4+
# E: Argument 1 to "expect_type" has incompatible type "UnionType"; expected "type" [arg-type]
5+
expect_type(str | None)

INPUTS/typeform_return.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def return_type() -> type:
2+
# E: Incompatible return value type (got "UnionType", expected "type") [return-value]
3+
return str | None
4+
5+
return_type()

test-data/unit/check-typeform.test

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,10 @@ reveal_type(as_instance(int)) # N: Revealed type is "Union[builtins.int, None]"
515515

516516
[case testLinkTypeFormToTypeIsWithTypeVariable]
517517
# flags: --python-version 3.14 --enable-incomplete-feature=TypeForm
518-
from typing import TypeForm
518+
from typing import TypeForm, TypeVar
519519
from typing_extensions import TypeIs
520-
def isassignable[T](value: object, typx: TypeForm[T]) -> TypeIs[T]:
520+
T = TypeVar('T')
521+
def isassignable(value: object, typx: TypeForm[T]) -> TypeIs[T]:
521522
raise BaseException()
522523
count: int | str = 1
523524
if isassignable(count, int):
@@ -529,9 +530,10 @@ else:
529530

530531
[case testLinkTypeFormToTypeGuardWithTypeVariable]
531532
# flags: --python-version 3.14 --enable-incomplete-feature=TypeForm
532-
from typing import TypeForm
533+
from typing import TypeForm, TypeVar
533534
from typing_extensions import TypeGuard
534-
def isassignable[T](value: object, typx: TypeForm[T]) -> TypeGuard[T]:
535+
T = TypeVar('T')
536+
def isassignable(value: object, typx: TypeForm[T]) -> TypeGuard[T]:
535537
raise BaseException()
536538
count: int | str = 1
537539
if isassignable(count, int):

0 commit comments

Comments
 (0)