Skip to content

Commit 93ff49d

Browse files
authored
Support several more constructs in stubgen's AliasPrinter (#18888)
Fixes #18886. Added implementations for UnaryExpr, SetExpr and SliceExpr, and also fallback to _Incomplete for several other constructs that can sensibly appear in a dataclass field definition.
1 parent 8ed16d1 commit 93ff49d

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

mypy/stubgen.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,31 +78,38 @@
7878
Block,
7979
BytesExpr,
8080
CallExpr,
81+
CastExpr,
8182
ClassDef,
8283
ComparisonExpr,
8384
ComplexExpr,
85+
ConditionalExpr,
8486
Decorator,
8587
DictExpr,
88+
DictionaryComprehension,
8689
EllipsisExpr,
8790
Expression,
8891
ExpressionStmt,
8992
FloatExpr,
9093
FuncBase,
9194
FuncDef,
95+
GeneratorExpr,
9296
IfStmt,
9397
Import,
9498
ImportAll,
9599
ImportFrom,
96100
IndexExpr,
97101
IntExpr,
98102
LambdaExpr,
103+
ListComprehension,
99104
ListExpr,
100105
MemberExpr,
101106
MypyFile,
102107
NameExpr,
103108
OpExpr,
104109
OverloadedFuncDef,
110+
SetComprehension,
105111
SetExpr,
112+
SliceExpr,
106113
StarExpr,
107114
Statement,
108115
StrExpr,
@@ -355,6 +362,9 @@ def visit_tuple_expr(self, node: TupleExpr) -> str:
355362
def visit_list_expr(self, node: ListExpr) -> str:
356363
return f"[{', '.join(n.accept(self) for n in node.items)}]"
357364

365+
def visit_set_expr(self, node: SetExpr) -> str:
366+
return f"{{{', '.join(n.accept(self) for n in node.items)}}}"
367+
358368
def visit_dict_expr(self, o: DictExpr) -> str:
359369
dict_items = []
360370
for key, value in o.items:
@@ -369,13 +379,50 @@ def visit_ellipsis(self, node: EllipsisExpr) -> str:
369379
def visit_op_expr(self, o: OpExpr) -> str:
370380
return f"{o.left.accept(self)} {o.op} {o.right.accept(self)}"
371381

382+
def visit_unary_expr(self, o: UnaryExpr, /) -> str:
383+
return f"{o.op}{o.expr.accept(self)}"
384+
385+
def visit_slice_expr(self, o: SliceExpr, /) -> str:
386+
blocks = [
387+
o.begin_index.accept(self) if o.begin_index is not None else "",
388+
o.end_index.accept(self) if o.end_index is not None else "",
389+
]
390+
if o.stride is not None:
391+
blocks.append(o.stride.accept(self))
392+
return ":".join(blocks)
393+
372394
def visit_star_expr(self, o: StarExpr) -> str:
373395
return f"*{o.expr.accept(self)}"
374396

375397
def visit_lambda_expr(self, o: LambdaExpr) -> str:
376398
# TODO: Required for among other things dataclass.field default_factory
377399
return self.stubgen.add_name("_typeshed.Incomplete")
378400

401+
def _visit_unsupported_expr(self, o: object) -> str:
402+
# Something we do not understand.
403+
return self.stubgen.add_name("_typeshed.Incomplete")
404+
405+
def visit_comparison_expr(self, o: ComparisonExpr) -> str:
406+
return self._visit_unsupported_expr(o)
407+
408+
def visit_cast_expr(self, o: CastExpr) -> str:
409+
return self._visit_unsupported_expr(o)
410+
411+
def visit_conditional_expr(self, o: ConditionalExpr) -> str:
412+
return self._visit_unsupported_expr(o)
413+
414+
def visit_list_comprehension(self, o: ListComprehension) -> str:
415+
return self._visit_unsupported_expr(o)
416+
417+
def visit_set_comprehension(self, o: SetComprehension) -> str:
418+
return self._visit_unsupported_expr(o)
419+
420+
def visit_dictionary_comprehension(self, o: DictionaryComprehension) -> str:
421+
return self._visit_unsupported_expr(o)
422+
423+
def visit_generator_expr(self, o: GeneratorExpr) -> str:
424+
return self._visit_unsupported_expr(o)
425+
379426

380427
def find_defined_names(file: MypyFile) -> set[str]:
381428
finder = DefinitionFinder()

test-data/unit/stubgen.test

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4277,6 +4277,35 @@ class Y(missing.Base):
42774277
generated_kwargs: float
42784278
generated_kwargs_: float
42794279

4280+
[case testDataclassAliasPrinterVariations_semanal]
4281+
from dataclasses import dataclass, field
4282+
4283+
@dataclass
4284+
class X:
4285+
a: int = field(default=-1)
4286+
b: set[int] = field(default={0})
4287+
c: list[int] = field(default=[x for x in range(5)])
4288+
d: dict[int, int] = field(default={x: x for x in range(5)})
4289+
e: tuple[int, int] = field(default=(1, 2, 3)[1:])
4290+
f: tuple[int, int] = field(default=(1, 2, 3)[:2])
4291+
g: tuple[int, int] = field(default=(1, 2, 3)[::2])
4292+
h: tuple[int] = field(default=(1, 2, 3)[1::2])
4293+
4294+
[out]
4295+
from _typeshed import Incomplete
4296+
from dataclasses import dataclass, field
4297+
4298+
@dataclass
4299+
class X:
4300+
a: int = field(default=-1)
4301+
b: set[int] = field(default={0})
4302+
c: list[int] = field(default=Incomplete)
4303+
d: dict[int, int] = field(default=Incomplete)
4304+
e: tuple[int, int] = field(default=(1, 2, 3)[1:])
4305+
f: tuple[int, int] = field(default=(1, 2, 3)[:2])
4306+
g: tuple[int, int] = field(default=(1, 2, 3)[::2])
4307+
h: tuple[int] = field(default=(1, 2, 3)[1::2])
4308+
42804309
[case testDataclassTransform]
42814310
# dataclass_transform detection only works with semantic analysis.
42824311
# Test stubgen doesn't break too badly without it.

0 commit comments

Comments
 (0)