Skip to content

Commit 22307d9

Browse files
committed
Add flag to reveal simpler types
1 parent 6d30d75 commit 22307d9

5 files changed

Lines changed: 56 additions & 7 deletions

File tree

mypy/main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,12 @@ def add_invertible_flag(
989989
help="Show links to error code documentation",
990990
group=error_group,
991991
)
992+
add_invertible_flag(
993+
"--reveal-simple-types",
994+
default=False,
995+
help="Use compact (but potentially ambiguous) type representation in reveal_type()",
996+
group=error_group,
997+
)
992998
add_invertible_flag(
993999
"--pretty",
9941000
default=False,

mypy/messages.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,7 @@ def reveal_type(self, typ: Type, context: Context) -> None:
17441744

17451745
# Nothing special here; just create the note:
17461746
visitor = TypeStrVisitor(options=self.options)
1747+
visitor.reveal_simple_types = self.options.reveal_simple_types
17471748
self.note(f'Revealed type is "{typ.accept(visitor)}"', context)
17481749

17491750
def reveal_locals(self, type_map: dict[str, Type | None], context: Context) -> None:
@@ -1754,6 +1755,7 @@ def reveal_locals(self, type_map: dict[str, Type | None], context: Context) -> N
17541755
self.note("Revealed local types are:", context)
17551756
for k, v in sorted_locals.items():
17561757
visitor = TypeStrVisitor(options=self.options)
1758+
visitor.reveal_simple_types = self.options.reveal_simple_types
17571759
self.note(f" {k}: {v.accept(visitor) if v is not None else None}", context)
17581760
else:
17591761
self.note("There are no locals to reveal", context)

mypy/options.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ def __init__(self) -> None:
371371
self.show_error_end: bool = False
372372
self.hide_error_codes = False
373373
self.show_error_code_links = False
374+
self.reveal_simple_types = False
374375
# Use soft word wrap and show trimmed source snippets with error location markers.
375376
self.pretty = False
376377
self.dump_graph = False

mypy/types.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3719,6 +3719,9 @@ def __init__(self, id_mapper: IdMapper | None = None, *, options: Options) -> No
37193719
self.id_mapper = id_mapper
37203720
self.options = options
37213721
self.dotted_aliases: set[TypeAliasType] | None = None
3722+
# This visitor is used in other contexts (not just reveal_type()), so only
3723+
# use this option when explicitly set by the caller.
3724+
self.reveal_simple_types = False
37223725

37233726
def visit_unbound_type(self, t: UnboundType, /) -> str:
37243727
s = t.name + "?"
@@ -3759,6 +3762,8 @@ def visit_instance(self, t: Instance, /) -> str:
37593762
# Instances with a literal fallback should never be generic. If they are,
37603763
# something went wrong so we fall back to showing the full Instance repr.
37613764
s = f"{t.last_known_value.accept(self)}?"
3765+
elif self.reveal_simple_types:
3766+
s = t.type.name or "<???>"
37623767
else:
37633768
s = t.type.fullname or t.type.name or "<???>"
37643769

@@ -3775,10 +3780,13 @@ def visit_instance(self, t: Instance, /) -> str:
37753780
return s
37763781

37773782
def visit_type_var(self, t: TypeVarType, /) -> str:
3778-
s = f"{t.name}`{t.id}"
3783+
if self.reveal_simple_types:
3784+
s = t.name
3785+
else:
3786+
s = f"{t.name}`{t.id}"
37793787
if self.id_mapper and t.upper_bound:
37803788
s += f"(upper_bound={t.upper_bound.accept(self)})"
3781-
if t.has_default():
3789+
if t.has_default() and not self.reveal_simple_types:
37823790
s += f" = {t.default.accept(self)}"
37833791
return s
37843792

@@ -3787,7 +3795,10 @@ def visit_param_spec(self, t: ParamSpecType, /) -> str:
37873795
s = ""
37883796
if t.prefix.arg_types:
37893797
s += f"[{self.list_str(t.prefix.arg_types)}, **"
3790-
s += f"{t.name_with_suffix()}`{t.id}"
3798+
if self.reveal_simple_types:
3799+
s += t.name_with_suffix()
3800+
else:
3801+
s += f"{t.name_with_suffix()}`{t.id}"
37913802
if t.prefix.arg_types:
37923803
s += "]"
37933804
if t.has_default():
@@ -3824,8 +3835,11 @@ def visit_parameters(self, t: Parameters, /) -> str:
38243835
return f"[{s}]"
38253836

38263837
def visit_type_var_tuple(self, t: TypeVarTupleType, /) -> str:
3827-
s = f"{t.name}`{t.id}"
3828-
if t.has_default():
3838+
if self.reveal_simple_types:
3839+
s = t.name
3840+
else:
3841+
s = f"{t.name}`{t.id}"
3842+
if t.has_default() and not self.reveal_simple_types:
38293843
s += f" = {t.default.accept(self)}"
38303844
return s
38313845

@@ -3854,7 +3868,10 @@ def visit_callable_type(self, t: CallableType, /) -> str:
38543868
s += name + ": "
38553869
type_str = t.arg_types[i].accept(self)
38563870
if t.arg_kinds[i] == ARG_STAR2 and t.unpack_kwargs:
3857-
type_str = f"Unpack[{type_str}]"
3871+
if self.reveal_simple_types:
3872+
type_str = f"**{type_str}"
3873+
else:
3874+
type_str = f"Unpack[{type_str}]"
38583875
s += type_str
38593876
if t.arg_kinds[i].is_optional():
38603877
s += " ="
@@ -3933,7 +3950,10 @@ def item_str(name: str, typ: str) -> str:
39333950
prefix = ""
39343951
if t.fallback and t.fallback.type:
39353952
if t.fallback.type.fullname not in TPDICT_FB_NAMES:
3936-
prefix = repr(t.fallback.type.fullname) + ", "
3953+
if self.reveal_simple_types:
3954+
prefix = t.fallback.type.name + ", "
3955+
else:
3956+
prefix = repr(t.fallback.type.fullname) + ", "
39373957
return f"TypedDict({prefix}{s})"
39383958

39393959
def visit_raw_expression_type(self, t: RawExpressionType, /) -> str:
@@ -3967,6 +3987,8 @@ def visit_placeholder_type(self, t: PlaceholderType, /) -> str:
39673987
def visit_type_alias_type(self, t: TypeAliasType, /) -> str:
39683988
if t.alias is None:
39693989
return "<alias (unfixed)>"
3990+
if self.reveal_simple_types:
3991+
return t.alias.name
39703992
if not t.is_recursive:
39713993
return get_proper_type(t).accept(self)
39723994
if self.dotted_aliases is None:
@@ -3979,6 +4001,8 @@ def visit_type_alias_type(self, t: TypeAliasType, /) -> str:
39794001
return type_str
39804002

39814003
def visit_unpack_type(self, t: UnpackType, /) -> str:
4004+
if self.reveal_simple_types:
4005+
return f"*{t.type.accept(self)}"
39824006
return f"Unpack[{t.type.accept(self)}]"
39834007

39844008
def list_str(self, a: Iterable[Type], *, use_or_syntax: bool = False) -> str:

test-data/unit/check-flags.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2737,3 +2737,19 @@ def f() -> None:
27372737
[file mypy.ini]
27382738
\[mypy]
27392739
disallow_redefinition = true
2740+
2741+
[case testRevealSimpleTypes]
2742+
# flags: --reveal-simple-types
2743+
from typing_extensions import TypeVarTuple, Unpack, TypedDict
2744+
2745+
Ts = TypeVarTuple("Ts")
2746+
def foo(x: int, *xs: Unpack[Ts]) -> tuple[int, Unpack[Ts]]: ...
2747+
reveal_type(foo) # N: Revealed type is "def [Ts] (x: int, *xs: *Ts) -> tuple[int, *Ts]"
2748+
2749+
class Options(TypedDict):
2750+
rate: int
2751+
template: str
2752+
2753+
def bar(x: int, **kwargs: Unpack[Options]) -> None: ...
2754+
reveal_type(bar) # N: Revealed type is "def (x: int, **kwargs: **TypedDict(Options, {'rate': int, 'template': str}))"
2755+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)