Skip to content

Commit 9aeec1d

Browse files
committed
Add a bunch of typing tests
1 parent 24add8e commit 9aeec1d

File tree

7 files changed

+159
-26
lines changed

7 files changed

+159
-26
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ include = ["typemap", "typemap.*", "typemap_extensions"]
1313
test = [
1414
"pytest>=7.0",
1515
"ruff",
16-
"mypy @ git+https://github.com/msullivan/mypy-typemap@f49083e5cd7124df93ea1a0a844d60adf901c250",
16+
"mypy @ git+https://github.com/msullivan/mypy-typemap@9744d25fbd2a42ddb8b0cc6e5a74388e08c9ea7b",
1717
]
1818

1919
[tool.uv]

tests/test_dataclass_like.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from typing import (
2+
assert_type,
23
Callable,
34
Literal,
45
ReadOnly,
@@ -35,6 +36,15 @@ class Field[T: FieldArgs](typing.InitField[T]):
3536
)
3637

3738

39+
def _check_hero_init() -> None:
40+
# required only
41+
h = Hero(name='test', secret_name='secret')
42+
assert_type(h, Hero)
43+
# all keyword args
44+
h2 = Hero(id=1, name='test', age=25, secret_name='secret')
45+
assert_type(h2, Hero)
46+
47+
3848
# TODO: what could we do to make dataclass_ish work at runtime?
3949

4050

tests/test_fastapilike_2.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
# SKIP MYPY: Invalid use of Self
2-
# TODO: resolve
1+
# TODO: resolve the invalid Self use issue that is type: ignored
32

43
from typing import (
54
Callable,
@@ -9,7 +8,6 @@
98
TypedDict,
109
Never,
1110
Self,
12-
TYPE_CHECKING,
1311
)
1412

1513
import typemap_extensions as typing
@@ -146,7 +144,7 @@ class Field[T: FieldArgs](typing.InitField[T]):
146144
Literal["__init__"],
147145
Callable[
148146
typing.Params[
149-
typing.Param[Literal["self"], Self],
147+
typing.Param[Literal["self"], Self], # type: ignore[misc]
150148
*[
151149
typing.Param[
152150
p.name,
@@ -212,10 +210,44 @@ class Hero:
212210
secret_name: str = Field(hidden=True)
213211

214212

215-
# Quick reveal_type test for running mypy against this
216-
if TYPE_CHECKING:
217-
pubhero: Public[Hero]
218-
reveal_type(pubhero) # noqa
213+
from typing import assert_type
214+
215+
216+
def _check_public(x: Public[Hero]) -> None:
217+
# id becomes required int (primary_key strips | None), secret_name hidden
218+
assert_type(
219+
x,
220+
typing.NewProtocol[
221+
typing.Member[Literal["id"], int],
222+
typing.Member[Literal["name"], str],
223+
typing.Member[Literal["age"], int | None],
224+
],
225+
)
226+
227+
228+
def _check_create(x: Create[Hero]) -> None:
229+
# primary key excluded, rest preserved
230+
assert_type(
231+
x,
232+
typing.NewProtocol[
233+
typing.Member[Literal["name"], str],
234+
typing.Member[Literal["age"], int | None],
235+
typing.Member[Literal["secret_name"], str],
236+
],
237+
)
238+
239+
240+
def _check_update(x: Update[Hero]) -> None:
241+
# primary key excluded, all fields optional (| None)
242+
assert_type(
243+
x,
244+
typing.NewProtocol[
245+
typing.Member[Literal["name"], str | None],
246+
typing.Member[Literal["age"], int | None],
247+
typing.Member[Literal["secret_name"], str | None],
248+
],
249+
)
250+
219251

220252
#######
221253

tests/test_nplike.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Literal
1+
from typing import assert_type, Literal
22

33
import typemap_extensions as typing
44

@@ -64,6 +64,21 @@ def __add__[*Shape2](
6464

6565
type Apply[T, S] = Array[GetElem[T], *Broadcast[GetShape[T], GetShape[S]]]
6666

67+
68+
def _check_merge_one_broadcast(x: MergeOne[Literal[4], Literal[1]]) -> None:
69+
assert_type(x, Literal[4])
70+
71+
72+
def _check_merge_one_equal(x: MergeOne[Literal[3], Literal[3]]) -> None:
73+
assert_type(x, Literal[3])
74+
75+
76+
def _check_broadcast(
77+
x: Broadcast[tuple[Literal[4], Literal[1]], tuple[Literal[3]]],
78+
) -> None:
79+
assert_type(x, tuple[Literal[4], Literal[3]])
80+
81+
6782
######
6883
from typemap.type_eval import eval_typing, TypeMapError
6984

tests/test_qblike_2.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import textwrap
22

3-
from typing import Literal, Unpack, TYPE_CHECKING
3+
from typing import assert_type, Literal, Unpack
44

55
from typemap.type_eval import eval_call, eval_typing
66
import typemap_extensions as typing
@@ -152,16 +152,31 @@ class User:
152152
posts: MultiLink[Post]
153153

154154

155-
def test_qblike_typing_only_1() -> None:
156-
# Quick reveal_type test for running mypy against this
157-
if TYPE_CHECKING:
158-
_test_select = select(
159-
Post,
160-
title=True,
161-
comments=True,
162-
author=True,
163-
)
164-
reveal_type(_test_select) # noqa
155+
def _check_select_user() -> None:
156+
r = select(User, id=True, name=True)
157+
assert_type(
158+
r,
159+
list[
160+
typing.NewProtocol[
161+
typing.Member[Literal["id"], int],
162+
typing.Member[Literal["name"], str],
163+
]
164+
],
165+
)
166+
167+
168+
def _check_select_post_with_links() -> None:
169+
r = select(Post, title=True, comments=True, author=True)
170+
assert_type(
171+
r,
172+
list[
173+
typing.NewProtocol[
174+
typing.Member[Literal["title"], str],
175+
typing.Member[Literal["comments"], list[PropsOnly[Comment]]],
176+
typing.Member[Literal["author"], PropsOnly[User]],
177+
]
178+
],
179+
)
165180

166181

167182
def test_qblike2_1():

tests/test_ts_utility.py

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
# mypy: ignore-errors
21
"""
32
TypeScript-style utility type operators: Pick, Omit, Partial.
43
54
See https://www.typescriptlang.org/docs/handbook/utility-types.html
65
"""
76

87
import textwrap
9-
from typing import Literal, Never, NotRequired, Required, TypedDict, Union
8+
from typing import (
9+
assert_type,
10+
Literal,
11+
Never,
12+
NotRequired,
13+
Required,
14+
TypedDict,
15+
Union,
16+
)
1017

1118
import typemap_extensions as typing
1219
from typemap.type_eval import eval_typing
@@ -105,6 +112,60 @@ class TodoTD(TypedDict):
105112
# End PEP section: Utility types
106113

107114

115+
def _check_exclude(x0: Exclude[str | int | bool, int]) -> None:
116+
assert_type(x0, str)
117+
118+
119+
def _check_extract(x1: Extract[str | int | bool, int]) -> None:
120+
assert_type(x1, int | bool)
121+
122+
123+
def _check_keyof(x2: KeyOf[Todo]) -> None:
124+
assert_type(
125+
x2, Literal["title"] | Literal["description"] | Literal["completed"]
126+
)
127+
128+
129+
def _check_pick(
130+
x3: Pick[Todo, Literal["title"] | Literal["completed"]],
131+
) -> None:
132+
assert_type(x3.title, str)
133+
assert_type(x3.completed, bool)
134+
assert_type(
135+
x3,
136+
typing.NewProtocol[
137+
typing.Member[Literal["title"], str],
138+
typing.Member[Literal["completed"], bool],
139+
],
140+
)
141+
142+
143+
def _check_omit(x4: Omit[Todo, Literal["description"]]) -> None:
144+
assert_type(x4.title, str)
145+
assert_type(x4.completed, bool)
146+
assert_type(
147+
x4,
148+
typing.NewProtocol[
149+
typing.Member[Literal["title"], str],
150+
typing.Member[Literal["completed"], bool],
151+
],
152+
)
153+
154+
155+
def _check_partial(x5: Partial[Todo]) -> None:
156+
assert_type(x5.title, str | None)
157+
assert_type(x5.description, str | None)
158+
assert_type(x5.completed, bool | None)
159+
assert_type(
160+
x5,
161+
typing.NewProtocol[
162+
typing.Member[Literal["title"], str | None],
163+
typing.Member[Literal["description"], str | None],
164+
typing.Member[Literal["completed"], bool | None],
165+
],
166+
)
167+
168+
108169
def test_pick():
109170
tgt = eval_typing(Pick[Todo, Literal["title"] | Literal["completed"]])
110171
fmt = format_helper.format_class(tgt)

uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)