Skip to content

Commit 6571c74

Browse files
authored
Wrap extended callable params in a Params type (#110)
The type serves as a quasi-bound on ParamSpec. See python/peps#4866
1 parent 534374b commit 6571c74

File tree

10 files changed

+243
-228
lines changed

10 files changed

+243
-228
lines changed

tests/test_dataclass_like.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class Field[T: FieldArgs](typing.InitField[T]):
5353
type InitFnType[T] = typing.Member[
5454
Literal["__init__"],
5555
Callable[
56-
[
56+
typing.Params[
5757
typing.Param[Literal["self"], Self],
5858
*[
5959
typing.Param[

tests/test_eval_call_with_types.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
Iter,
1111
Members,
1212
Param,
13+
Params,
1314
)
1415

1516

@@ -19,36 +20,46 @@ def test_eval_call_with_types_callable_01():
1920

2021

2122
def test_eval_call_with_types_callable_02():
22-
res = eval_call_with_types(Callable[[Param[Literal["x"], int]], int], int)
23+
res = eval_call_with_types(
24+
Callable[Params[Param[Literal["x"], int]], int], int
25+
)
2326
assert res is int
2427

2528

2629
def test_eval_call_with_types_callable_03():
2730
res = eval_call_with_types(
28-
Callable[[Param[Literal["x"], int, Literal["keyword"]]], int], x=int
31+
Callable[Params[Param[Literal["x"], int, Literal["keyword"]]], int],
32+
x=int,
2933
)
3034
assert res is int
3135

3236

3337
def test_eval_call_with_types_callable_04():
3438
class C: ...
3539

36-
res = eval_call_with_types(Callable[[Param[Literal["self"], Self]], int], C)
40+
res = eval_call_with_types(
41+
Callable[Params[Param[Literal["self"], Self]], int], C
42+
)
3743
assert res is int
3844

3945

4046
def test_eval_call_with_types_callable_05():
4147
class C: ...
4248

43-
res = eval_call_with_types(Callable[[Param[Literal["self"], Self]], C], C)
49+
res = eval_call_with_types(
50+
Callable[Params[Param[Literal["self"], Self]], C], C
51+
)
4452
assert res is C
4553

4654

4755
def test_eval_call_with_types_callable_06():
4856
class C: ...
4957

5058
res = eval_call_with_types(
51-
Callable[[Param[Literal["self"], Self], Param[Literal["x"], int]], int],
59+
Callable[
60+
Params[Param[Literal["self"], Self], Param[Literal["x"], int]],
61+
int,
62+
],
5263
C,
5364
int,
5465
)
@@ -60,7 +71,7 @@ class C: ...
6071

6172
res = eval_call_with_types(
6273
Callable[
63-
[
74+
Params[
6475
Param[Literal["self"], Self],
6576
Param[Literal["x"], int, Literal["keyword"]],
6677
],
@@ -74,13 +85,15 @@ class C: ...
7485

7586
def test_eval_call_with_types_callable_08():
7687
T = TypeVar("T")
77-
res = eval_call_with_types(Callable[[Param[Literal["x"], T]], str], int)
88+
res = eval_call_with_types(
89+
Callable[Params[Param[Literal["x"], T]], str], int
90+
)
7891
assert res is str
7992

8093

8194
def test_eval_call_with_types_callable_09():
8295
T = TypeVar("T")
83-
res = eval_call_with_types(Callable[[Param[Literal["x"], T]], T], int)
96+
res = eval_call_with_types(Callable[Params[Param[Literal["x"], T]], T], int)
8497
assert res is int
8598

8699

@@ -89,7 +102,9 @@ def test_eval_call_with_types_callable_10():
89102

90103
class C(Generic[T]): ...
91104

92-
res = eval_call_with_types(Callable[[Param[Literal["x"], C[T]]], T], C[int])
105+
res = eval_call_with_types(
106+
Callable[Params[Param[Literal["x"], C[T]]], T], C[int]
107+
)
93108
assert res is int
94109

95110

@@ -102,9 +117,13 @@ class D(C[int]): ...
102117

103118
class E(D): ...
104119

105-
res = eval_call_with_types(Callable[[Param[Literal["x"], C[T]]], T], D)
120+
res = eval_call_with_types(
121+
Callable[Params[Param[Literal["x"], C[T]]], T], D
122+
)
106123
assert res is int
107-
res = eval_call_with_types(Callable[[Param[Literal["x"], C[T]]], T], E)
124+
res = eval_call_with_types(
125+
Callable[Params[Param[Literal["x"], C[T]]], T], E
126+
)
108127
assert res is int
109128

110129

@@ -206,7 +225,10 @@ def test_eval_call_with_types_bind_error_01():
206225
ValueError, match="Type variable T is already bound to int, but got str"
207226
):
208227
eval_call_with_types(
209-
Callable[[Param[Literal["x"], T], Param[Literal["y"], T]], T],
228+
Callable[
229+
Params[Param[Literal["x"], T], Param[Literal["y"], T]],
230+
T,
231+
],
210232
int,
211233
str,
212234
)
@@ -230,7 +252,10 @@ class C(Generic[T]): ...
230252
ValueError, match="Type variable T is already bound to int, but got str"
231253
):
232254
eval_call_with_types(
233-
Callable[[Param[Literal["x"], C[T]], Param[Literal["y"], C[T]]], T],
255+
Callable[
256+
Params[Param[Literal["x"], C[T]], Param[Literal["y"], C[T]]],
257+
T,
258+
],
234259
C[int],
235260
C[str],
236261
)

tests/test_fastapilike_1.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
Member,
2020
Members,
2121
Param,
22+
Params,
2223
)
2324

2425
from . import format_helper
@@ -47,7 +48,7 @@ class _Default:
4748
type InitFnType[T] = Member[
4849
Literal["__init__"],
4950
Callable[
50-
[
51+
Params[
5152
Param[Literal["self"], Self],
5253
*[
5354
Param[

tests/test_fastapilike_2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class Field[T: FieldArgs](typing.InitField[T]):
142142
type InitFnType[T] = typing.Member[
143143
Literal["__init__"],
144144
Callable[
145-
[
145+
typing.Params[
146146
typing.Param[Literal["self"], Self],
147147
*[
148148
typing.Param[

tests/test_schemalike.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
Member,
1111
NamedParam,
1212
Param,
13+
Params,
1314
Concat,
1415
)
1516

@@ -46,7 +47,7 @@ class Property:
4647
Member[
4748
Concat[Literal["get_"], p.name],
4849
Callable[
49-
[
50+
Params[
5051
Param[Literal["self"], Schemaify[T]],
5152
NamedParam[Literal["schema"], Schema, Literal["keyword"]],
5253
],
@@ -63,16 +64,17 @@ def test_schema_like_1():
6364
tgt = eval_typing(Schemaify[Property])
6465
fmt = format_helper.format_class(tgt)
6566

66-
assert fmt == textwrap.dedent("""\
67+
getter_params = "self: Self, *, schema: tests.test_schemalike.Schema"
68+
assert fmt == textwrap.dedent(f"""\
6769
class Schemaify[tests.test_schemalike.Property]:
6870
name: str
6971
required: bool
7072
multi: bool
7173
typ: tests.test_schemalike.Type
7274
expr: tests.test_schemalike.Expression | None
73-
def get_name(self: Self, *, schema: tests.test_schemalike.Schema) -> str: ...
74-
def get_required(self: Self, *, schema: tests.test_schemalike.Schema) -> bool: ...
75-
def get_multi(self: Self, *, schema: tests.test_schemalike.Schema) -> bool: ...
76-
def get_typ(self: Self, *, schema: tests.test_schemalike.Schema) -> tests.test_schemalike.Type: ...
77-
def get_expr(self: Self, *, schema: tests.test_schemalike.Schema) -> tests.test_schemalike.Expression | None: ...
75+
def get_name({getter_params}) -> str: ...
76+
def get_required({getter_params}) -> bool: ...
77+
def get_multi({getter_params}) -> bool: ...
78+
def get_typ({getter_params}) -> tests.test_schemalike.Type: ...
79+
def get_expr({getter_params}) -> tests.test_schemalike.Expression | None: ...
7880
""")

tests/test_type_dir.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,8 @@ def test_type_members_func_1():
381381
assert (
382382
str(typ)
383383
== "\
384-
typing.Callable[[\
385-
typemap.typing.Param[typing.Literal['self'], tests.test_type_dir.Base[int], typing.Never], \
384+
typing.Callable[\
385+
typemap.typing.Params[typemap.typing.Param[typing.Literal['self'], tests.test_type_dir.Base[int], typing.Never], \
386386
typemap.typing.Param[typing.Literal['a'], int | None, typing.Never], \
387387
typemap.typing.Param[typing.Literal['b'], int, typing.Literal['keyword', \
388388
'default']]], \
@@ -403,7 +403,7 @@ def test_type_members_func_2():
403403
assert (
404404
str(typ)
405405
== "\
406-
classmethod[tests.test_type_dir.Base[int], tuple[typemap.typing.Param[typing.Literal['a'], int | None, typing.Never], typemap.typing.Param[typing.Literal['b'], ~K, typing.Never]], dict[str, int]]"
406+
classmethod[tests.test_type_dir.Base[int], typemap.typing.Params[typemap.typing.Param[typing.Literal['a'], int | None, typing.Never], typemap.typing.Param[typing.Literal['b'], ~K, typing.Never]], dict[str, int]]"
407407
)
408408

409409

@@ -422,7 +422,7 @@ def test_type_members_func_3():
422422
)
423423
assert (
424424
str(evaled)
425-
== "staticmethod[tuple[typemap.typing.Param[typing.Literal['a'], int | typing.Literal['gotcha!'] | Z | None, typing.Never], typemap.typing.Param[typing.Literal['b'], ~K, typing.Never]], dict[str, int | Z]]"
425+
== "staticmethod[typemap.typing.Params[typemap.typing.Param[typing.Literal['a'], int | typing.Literal['gotcha!'] | Z | None, typing.Never], typemap.typing.Param[typing.Literal['b'], ~K, typing.Never]], dict[str, int | Z]]"
426426
)
427427

428428

0 commit comments

Comments
 (0)