10000 [PEP 747] Recognize TypeForm[T] type and values (#9773) by davidfstr · Pull Request #18690 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

[PEP 747] Recognize TypeForm[T] type and values (#9773) #18690

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

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ca4c79f
[PEP 747] Recognize TypeForm[T] type and values (#9773)
davidfstr Sep 29, 2024
9dcfc23
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 16, 2025
5cb1da5
Eliminate use of Type Parameter Syntax, which only works on Python >=…
davidfstr Feb 19, 2025
3ece208
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 19, 2025
799bc48
Remove INPUTS directory
davidfstr Feb 19, 2025
6bda848
WIP: Don't declare attributes on Expression to avoid confusing mypyc
davidfstr Feb 20, 2025
9df0e6b
SQ -> WIP: Don't declare attributes on Expression to avoid confusing …
davidfstr Feb 21, 2025
a2c318b
SQ -> WIP: Don't declare attributes on Expression to avoid confusing …
davidfstr Feb 21, 2025
f398374
Recognize non-string type expressions everywhere lazily. Optimize eag…
davidfstr Feb 25, 2025
bd5911f
NOMERGE: Disable test that is already failing on master branch
davidfstr Mar 4, 2025
3801bcc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 4, 2025
c4db784
Fix mypyc errors: Replace EllipsisType with NotParsed type
davidfstr Mar 4, 2025
29fe65a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 4, 2025
4134250
mypy_primer: Enable TypeForm feature when checking effects on open so…
davidfstr Mar 5, 2025
5fb5bd8
Revert "mypy_primer: Enable TypeForm feature when checking effects on…
davidfstr Mar 8, 2025
54cd64d
NOMERGE: mypy_primer: Enable --enable-incomplete-feature=TypeForm whe…
davidfstr Mar 8, 2025
075980b
Ignore warnings like: <type_comment>:1: SyntaxWarning: invalid escape…
davidfstr Mar 14, 2025
6797cac
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 14, 2025
4162a35
Rerun CI
davidfstr Mar 17, 2025
d1aafcd
Improve warning message when string annotation used in TypeForm context
davidfstr Mar 18, 2025
1d9620d
Print error code for the MAYBE_UNRECOGNIZED_STR_TYPEFORM note
davidfstr Mar 26, 2025
76cae61
Document the [maybe-unrecognized-str-typeform] error code
davidfstr Mar 26, 2025
170a5e7
Fix doc generation warning
davidfstr Mar 26, 2025
84c06a6
Merge branch 'master' into f/typeform3
davidfstr Apr 28, 2025
File filter

Filter by extension

Filter by extension

Conversations 10000
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Eliminate use of Type Parameter Syntax, which only works on Python >=…
… 3.12
  • Loading branch information
davidfstr committed Feb 19, 2025
commit 5cb1da59a2a1518d89defa0e2aa2f9abff6b48c2
5 changes: 5 additions & 0 deletions INPUTS/required/import_typing_notrequired.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import typing
import typing_extensions

assert typing.Required is typing_extensions.Required
assert typing.NotRequired is typing_extensions.NotRequired
5 changes: 5 additions & 0 deletions INPUTS/required/import_typing_notrequired2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import typing
import typing_extensions

assert typing.Required is typing_extensions.Required
assert typing.NotRequired is typing_extensions.NotRequired
85 changes: 85 additions & 0 deletions INPUTS/required/required.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from typing import TypedDict, Tuple, Union
from typing_extensions import NotRequired, Required


# --- Class Based TypedDict ---
class Movie(TypedDict, total=False):
title: Required[str] # 5
year: int


m = Movie(title='The Matrix', year=1999)
# m = Movie()
print(m)


# --- Assignment Based TypedDict ---
Movie2 = TypedDict('Movie2', {
'title': Required[str],
'year': int,
}, total=False)


m2 = Movie2(title='The Matrix Reloaded', year=2003)
# m2 = Movie2()
print(m2)


# --- Required[] outside of TypedDict (error) ---
x: int = 5
# x: Required[int] = 5


# --- Required[] inside other Required[] (error) ---
'''
Movie3 = TypedDict('Movie3', {
'title': Required[Union[
Required[str],
bytes
]],
'year': int,
}, total=False)
'''


# --- Required[] used within TypedDict but not at top level (error) ---
'''
Movie4 = TypedDict('Movie4', {
'title': Union[
Required[str],
bytes
],
'year': int,
}, total=False)
Movie5 = TypedDict('Movie5', {
'title': Tuple[
Required[str],
bytes
],
'year': int,
}, total=False)
'''


# ==============================================================================
# --- Class Based TypedDict ---
class MovieN(TypedDict):
title: str
year: NotRequired[int]


m = MovieN(title='The Matrix', year=1999)
# m = MovieN()
print(m)


# --- Assignment Based TypedDict ---
MovieN2 = TypedDict('MovieN2', {
'title': str,
'year': NotRequired[int],
})


m2 = MovieN2(title='The Matrix Reloaded', year=2003)
# m2 = MovieN2()
print(m2)
8 changes: 8 additions & 0 deletions INPUTS/required/required_py3_11.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import typing

class Movie(typing.TypedDict):
title: str
year: typing.NotRequired[int]

m = Movie(title='The Matrix')
print(m)
38 changes: 38 additions & 0 deletions D7AF INPUTS/test_typeform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from typing import Any, Callable, cast, Never, NoReturn, Optional, reveal_type, Type, TypeVar, TypedDict
from typing_extensions import TypeForm, TypeGuard

dict_with_typx_keys: dict[TypeForm, int] = {
int | str: 1,
str | None: 2,
}
dict_with_typx_keys[int | str] += 1

#typx1: TypeForm[int | str] = 'int | str' # OK
#typx2: TypeForm[int] = 'str' # E: Incompatible types in assignment (expression has type "TypeForm[str]", variable has type "TypeForm[int]")

'''
from typing import Any

T = TypeVar('T')

def as_typeform(typx: TypeForm[T]) -> TypeForm[T]:
return typx

def as_type(typx: TypeForm[T]) -> Type[T] | None:
if isinstance(typx, type):
return typx
else:
return None

def as_instance(typx: TypeForm[T]) -> T | None:
if isinstance(typx, type):
return typx()
else:
return None

reveal_type(as_typeform(int | str)) # actual=TypeForm[Never], expect=TypeForm[int | str]
reveal_type(as_type(int | str))
reveal_type(as_type(int))
reveal_type(as_instance(int | str))
reveal_type(as_instance(int))
'''
5 changes: 5 additions & 0 deletions INPUTS/typeform_assign_to_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from typing import TypeAlias, reveal_type

alias: TypeAlias = int | None
reveal_type(alias)

9 changes: 9 additions & 0 deletions INPUTS/typeform_assignment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
typ: type
typ = int

# E: Incompatible types in assignment (expression has type "UnionType", variable has type "type") [assignment]
typ = str | None

#from typing_extensions import TypeExpr as TypeForm
#typx: TypeForm
#typx = int | None
5 changes: 5 additions & 0 deletions INPUTS/typeform_call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def expect_type(typ: type) -> None:
pass

# E: Argument 1 to "expect_type" has incompatible type "UnionType"; expected "type" [arg-type]
expect_type(str | None)
5 changes: 5 additions & 0 deletions INPUTS/typeform_return.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def return_type() -> type:
# E: Incompatible return value type (got "UnionType", expected "type") [return-value]
return str | None

return_type()
10 changes: 6 additions & 4 deletions test-data/unit/check-typeform.test
Original file line number Diff line number Diff line change
Expand Up @@ -515,9 +515,10 @@ reveal_type(as_instance(int)) # N: Revealed type is "Union[builtins.int, None]"

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

[case testLinkTypeFormToTypeGuardWithTypeVariable]
# flags: --python-version 3.14 --enable-incomplete-feature=TypeForm
from typing import TypeForm
from typing import TypeForm, TypeVar
from typing_extensions import TypeGuard
def isassignable[T](value: object, typx: TypeForm[T]) -> TypeGuard[T]:
T = TypeVar('T')
def isassignable(value: object, typx: TypeForm[T]) -> TypeGuard[T]:
raise BaseException()
count: int | str = 1
if isassignable(count, int):
Expand Down
Loading
0