Skip to content

Commit 8bf834b

Browse files
authored
Support dot notation for Member (#76)
This adds a general mechanism of allowing dot notation to access type aliases defined in a class if the class inherits from `typing.SupportAliases`. I updated one of the tests for it. Thoughts?
1 parent f66ff99 commit 8bf834b

File tree

3 files changed

+81
-31
lines changed

3 files changed

+81
-31
lines changed

tests/test_fastapilike_2.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ class Field[T: FieldArgs](typing.InitField[T]):
5959
type Public[T] = typing.NewProtocol[
6060
*[
6161
typing.Member[
62-
typing.GetName[p],
63-
FixPublicType[typing.GetType[p], typing.GetInit[p]],
64-
typing.GetQuals[p],
62+
p.name,
63+
FixPublicType[p.type, p.init],
64+
p.quals,
6565
]
6666
for p in typing.Iter[typing.Attrs[T]]
6767
if not typing.IsAssignable[
68-
Literal[True], GetFieldItem[typing.GetInit[p], Literal["hidden"]]
68+
Literal[True], GetFieldItem[p.init, Literal["hidden"]]
6969
]
7070
]
7171
]
@@ -89,15 +89,15 @@ class Field[T: FieldArgs](typing.InitField[T]):
8989
type Create[T] = typing.NewProtocol[
9090
*[
9191
typing.Member[
92-
typing.GetName[p],
93-
typing.GetType[p],
94-
typing.GetQuals[p],
95-
GetDefault[typing.GetInit[p]],
92+
p.name,
93+
p.type,
94+
p.quals,
95+
GetDefault[p.init],
9696
]
9797
for p in typing.Iter[typing.Attrs[T]]
9898
if not typing.IsAssignable[
9999
Literal[True],
100-
GetFieldItem[typing.GetInit[p], Literal["primary_key"]],
100+
GetFieldItem[p.init, Literal["primary_key"]],
101101
]
102102
]
103103
]
@@ -123,15 +123,15 @@ class Field[T: FieldArgs](typing.InitField[T]):
123123
type Update[T] = typing.NewProtocol[
124124
*[
125125
typing.Member[
126-
typing.GetName[p],
127-
typing.GetType[p] | None,
128-
typing.GetQuals[p],
126+
p.name,
127+
p.type | None,
128+
p.quals,
129129
Literal[None],
130130
]
131131
for p in typing.Iter[typing.Attrs[T]]
132132
if not typing.IsAssignable[
133133
Literal[True],
134-
GetFieldItem[typing.GetInit[p], Literal["primary_key"]],
134+
GetFieldItem[p.init, Literal["primary_key"]],
135135
]
136136
]
137137
]
@@ -148,13 +148,13 @@ class Field[T: FieldArgs](typing.InitField[T]):
148148
typing.Param[Literal["self"], Self],
149149
*[
150150
typing.Param[
151-
typing.GetName[p],
152-
typing.GetType[p],
151+
p.name,
152+
p.type,
153153
# All arguments are keyword-only
154154
# It takes a default if a default is specified in the class
155155
Literal["keyword"]
156156
if typing.IsAssignable[
157-
GetDefault[typing.GetInit[p]],
157+
GetDefault[p.init],
158158
Never,
159159
]
160160
else Literal["keyword", "default"],

typemap/type_eval/_eval_typing.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
_UnpackGenericAlias as typing_UnpackGenericAlias,
1616
)
1717

18+
from typemap.typing import _NestedGenericAlias
19+
1820

1921
if typing.TYPE_CHECKING:
2022
from typing import Any, Sequence
@@ -397,6 +399,27 @@ def _eval_applied_type_alias(obj: types.GenericAlias, ctx: EvalContext):
397399
return evaled
398400

399401

402+
@_eval_types_impl.register
403+
def _eval_nested_generic_alias(obj: _NestedGenericAlias, ctx: EvalContext):
404+
base, alias = obj.__args__
405+
406+
# TODO: what if it has parameters of its own
407+
408+
named_args = dict(
409+
zip(
410+
(p.__name__ for p in base.__origin__.__type_params__),
411+
base.__args__,
412+
strict=False,
413+
)
414+
)
415+
416+
unpacked = _apply_generic.get_annotations(
417+
alias, named_args, key='evaluate_value'
418+
)
419+
420+
return _eval_types(unpacked, ctx)
421+
422+
400423
@_eval_types_impl.register
401424
def _eval_applied_class(obj: typing_GenericAlias, ctx: EvalContext):
402425
"""Eval a typing._GenericAlias -- an applied user-defined class"""

typemap/typing.py

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,29 @@ def __typing_unpacked_tuple_args__(self):
5757
###
5858

5959

60+
class SupportAliases:
61+
@classmethod
62+
def __class_getitem__(cls, args):
63+
# Return an _AliasSupportingGenericAlias instead of a _GenericAlias
64+
res = super().__class_getitem__(args)
65+
return _AliasSupportingGenericAlias(res.__origin__, res.__args__)
66+
67+
68+
class _NestedGenericAlias(_GenericAlias, _root=True):
69+
pass
70+
71+
72+
class _AliasSupportingGenericAlias(_GenericAlias, _root=True):
73+
def __getattr__(self, attr):
74+
res = super().__getattr__(attr)
75+
if isinstance(res, typing.TypeAliasType):
76+
res = _NestedGenericAlias(NestedAlias, (self, res))
77+
return res
78+
79+
80+
###
81+
82+
6083
# Not type-level computation but related
6184

6285

@@ -160,21 +183,21 @@ class Member[
160183
Q: MemberQuals = typing.Never,
161184
I = typing.Never,
162185
D = typing.Never,
163-
]:
164-
name: N
165-
typ: T
166-
quals: Q
167-
init: I
168-
definer: D
186+
](SupportAliases):
187+
type name = N
188+
type type = T
189+
type quals = Q
190+
type init = I
191+
type definer = D
169192

170193

171194
ParamQuals = Literal["*", "**", "keyword", "positional", "default"]
172195

173196

174-
class Param[N: str | None, T, Q: ParamQuals = typing.Never]:
175-
name: N
176-
typ: T
177-
quals: Q
197+
class Param[N: str | None, T, Q: ParamQuals = typing.Never](SupportAliases):
198+
type name = N
199+
type type = T
200+
type quals = Q
178201

179202

180203
type PosParam[N: str | None, T] = Param[N, T, Literal["positional"]]
@@ -188,11 +211,15 @@ class Param[N: str | None, T, Q: ParamQuals = typing.Never]:
188211
type KwargsParam[T] = Param[Literal[None], T, Literal["**"]]
189212

190213

191-
type GetName[T: Member | Param] = GetMemberType[T, Literal["name"]]
192-
type GetType[T: Member | Param] = GetMemberType[T, Literal["typ"]]
193-
type GetQuals[T: Member | Param] = GetMemberType[T, Literal["quals"]]
194-
type GetInit[T: Member] = GetMemberType[T, Literal["init"]]
195-
type GetDefiner[T: Member] = GetMemberType[T, Literal["definer"]]
214+
type GetName[T: Member | Param] = T.name
215+
type GetType[T: Member | Param] = T.type
216+
type GetQuals[T: Member | Param] = T.quals
217+
type GetInit[T: Member] = T.init
218+
type GetDefiner[T: Member] = T.definer
219+
220+
221+
class NestedAlias[Obj, Alias]:
222+
pass
196223

197224

198225
class Attrs[T](_TupleLikeOperator):

0 commit comments

Comments
 (0)