Skip to content

Commit 7281285

Browse files
committed
Dedupe logic to see if new syntax is allowed
1 parent 9ca93de commit 7281285

File tree

3 files changed

+30
-26
lines changed

3 files changed

+30
-26
lines changed

mypy/semanal.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,19 @@ def is_typeshed_stub_file(self) -> bool:
482482
def final_iteration(self) -> bool:
483483
return self._final_iteration
484484

485+
@property
486+
def always_allow_new_syntax(self) -> bool:
487+
return self.is_stub_file or self.is_future_flag_set("annotations")
488+
489+
def check_pep585_name(self, fullname: str, name: str) -> bool:
490+
return fullname == "typing." + name.capitalize() or (
491+
fullname == "builtins." + name.lower()
492+
and (
493+
self.always_allow_new_syntax
494+
or self.options.python_version >= (3, 9)
495+
)
496+
)
497+
485498
@contextmanager
486499
def allow_unbound_tvars_set(self) -> Iterator[None]:
487500
old = self.allow_unbound_tvars
@@ -1011,17 +1024,7 @@ def is_expected_self_type(self, typ: Type, is_classmethod: bool) -> bool:
10111024
if (
10121025
sym is not None
10131026
and typ.args
1014-
and (
1015-
sym.fullname == "typing.Type"
1016-
or (
1017-
sym.fullname == "builtins.type"
1018-
and (
1019-
self.is_stub_file
1020-
or self.is_future_flag_set("annotations")
1021-
or self.options.python_version >= (3, 9)
1022-
)
1023-
)
1024-
)
1027+
and self.check_pep585_name(sym.fullname or "", "type")
10251028
):
10261029
return self.is_expected_self_type(typ.args[0], is_classmethod=False)
10271030
return False

mypy/semanal_shared.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ def is_future_flag_set(self, flag: str) -> bool:
128128
def is_stub_file(self) -> bool:
129129
raise NotImplementedError
130130

131+
@property
132+
@abstractmethod
133+
def always_allow_new_syntax(self) -> bool:
134+
"""Should we allow new type syntax when targeting older Python versions
135+
like 'list[int]' or 'X | Y' (allowed in stubs and with `__future__` import)?
136+
"""
137+
raise NotImplementedError
138+
139+
@abstractmethod
140+
def check_pep585_name(self, fullname: str, name: str) -> bool:
141+
raise NotImplementedError
142+
131143
@abstractmethod
132144
def is_func_scope(self) -> bool:
133145
raise NotImplementedError

mypy/typeanal.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,6 @@ def __init__(
209209
self.allow_tuple_literal = allow_tuple_literal
210210
# Positive if we are analyzing arguments of another (outer) type
211211
self.nesting_level = 0
212-
# Should we allow new type syntax when targeting older Python versions
213-
# like 'list[int]' or 'X | Y' (allowed in stubs and with `__future__` import)?
214-
self.always_allow_new_syntax = self.api.is_stub_file or self.api.is_future_flag_set(
215-
"annotations"
216-
)
217212
# Should we accept unbound type variables? This is currently used for class bases,
218213
# and alias right hand sides (before they are analyzed as type aliases).
219214
self.allow_unbound_tvars = allow_unbound_tvars
@@ -297,7 +292,7 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
297292
if (
298293
fullname in get_nongen_builtins(self.options.python_version)
299294
and t.args
300-
and not self.always_allow_new_syntax
295+
and not self.api.always_allow_new_syntax
301296
):
302297
self.fail(
303298
no_subscript_builtin_alias(fullname, propose_alt=not self.defining_alias), t
@@ -514,10 +509,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ
514509
code=codes.VALID_TYPE,
515510
)
516511
return AnyType(TypeOfAny.from_error)
517-
elif fullname == "typing.Tuple" or (
518-
fullname == "builtins.tuple"
519-
and (self.always_allow_new_syntax or self.options.python_version >= (3, 9))
520-
):
512+
elif self.api.check_pep585_name(fullname, "tuple"):
521513
# Tuple is special because it is involved in builtin import cycle
522514
# and may be not ready when used.
523515
sym = self.api.lookup_fully_qualified_or_none("builtins.tuple")
@@ -550,10 +542,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ
550542
return make_optional_type(item)
551543
elif fullname == "typing.Callable":
552544
return self.analyze_callable_type(t)
553-
elif fullname == "typing.Type" or (
554-
fullname == "builtins.type"
555-
and (self.always_allow_new_syntax or self.options.python_version >= (3, 9))
556-
):
545+
elif self.api.check_pep585_name(fullname, "type"):
557546
if len(t.args) == 0:
558547
if fullname == "typing.Type":
559548
any_type = self.get_omitted_any(t)
@@ -1103,7 +1092,7 @@ def visit_union_type(self, t: UnionType) -> Type:
11031092
if (
11041093
t.uses_pep604_syntax is True
11051094
and t.is_evaluated is True
1106-
and not self.always_allow_new_syntax
1095+
and not self.api.always_allow_new_syntax
11071096
and not self.options.python_version >= (3, 10)
11081097
):
11091098
self.fail("X | Y syntax for unions requires Python 3.10", t, code=codes.SYNTAX)

0 commit comments

Comments
 (0)