8000 Don't crash on aliases like C = C (#5632) · python/mypy@5e97a68 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5e97a68

Browse files
authored
Don't crash on aliases like C = C (#5632)
Fixes #5631 Unfortunately one still needs to use `# type: ignores`, mypy has troubles understanding complex conditional definitions like in the issue: ```python try: ConnectionError = ConnectionError except NameError: class ConnectionError(Exception): pass ``` But this is a separate problem, that is harder to solve.
1 parent 6e7c296 commit 5e97a68

File tree

5 files changed

+162
-1
lines changed

5 files changed

+162
-1
lines changed

mypy/fixup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,10 @@ def lookup_qualified_typeinfo(modules: Dict[str, MypyFile], name: str,
236236
return node
237237
else:
238238
# Looks like a missing TypeInfo in quick mode, put something there
239-
assert quick_and_dirty, "Should never get here in normal mode"
239+
assert quick_and_dirty, "Should never get here in normal mode," \
240+
" got {}:{} instead of TypeInfo".format(type(node).__name__,
241+
node.fullname() if node
242+
else '')
240243
return stale_info(modules)
241244

242245

mypy/semanal.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,10 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> None:
19311931
res, alias_tvars, depends_on, qualified_tvars = self.analyze_alias(rvalue)
19321932
if not res:
19331933
return
1934+
if (isinstance(res, Instance) and res.type.name() == lvalue.name and
1935+
res.type.module_name == self.cur_mod_id):
1936+
# Aliases like C = C is a no-op.
1937+
return
19341938
s.is_alias_def = True
19351939
node = self.lookup(lvalue.name, lvalue)
19361940
assert node is not None

test-data/unit/check-incremental.test

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5193,3 +5193,117 @@ def f(x: str) -> None: pass
51935193
[out]
51945194
[out2]
51955195
tmp/main.py:2: error: Argument 1 to "f" has incompatible type "int"; expected "str"
5196+
5197+
[case testOverrideByIdemAlias]
5198+
import a
5199+
[file a.py]
5200+
import lib
5201+
x = 1
5202+
[file a.py.2]
5203+
import lib
5204+
x = 2
5205+
[file lib.py]
5206+
C = C
5207+
class C: # type: ignore
5208+
pass
5209+
[out]
5210+
[out2]
5211+
5212+
[case testOverrideByIdemAliasReversed]
5213+
import a
5214+
[file a.py]
5215+
import lib
5216+
x = 1
5217+
[file a.py.2]
5218+
import lib
5219+
x = 2
5220+
[file lib.py]
5221+
class C:
5222+
pass
5223+
C = C # type: ignore
5224+
x: C
5225+
[out]
5226+
[out2]
5227+
5228+
[case testOverrideByIdemAliasGeneric]
5229+
import a
5230+
[file a.py]
5231+
import lib
5232+
x = 1
5233+
[file a.py.2]
5234+
import lib
5235+
x = 2
5236+
[file lib.py]
5237+
from typing import Generic, TypeVar
5238+
5239+
T = TypeVar('T')
5240+
5241+
class C(Generic[T]):
5242+
pass
5243+
C = C[int] # type: ignore
5244+
x: C
5245+
[out]
5246+
[out2]
5247+
5248+
[case testOverrideByIdemAliasImported]
5249+
import a
5250+
[file a.py]
5251+
import lib
5252+
x = 1
5253+
[file a.py.2]
5254+
import lib
5255+
x = 2
5256+
[file lib.py]
5257+
from other import C
5258+
C = C # type: ignore
5259+
x: C
5260+
[file other.py]
5261+
class C:
5262+
pass
5263+
[out]
5264+
[out2]
5265+
5266+
[case testOverrideByIdemAliasImportedReversed]
5267+
import a
5268+
[file a.py]
5269+
import lib
5270+
x = 1
5271+
[file a.py.2]
5272+
import lib
5273+
x = 2
5274+
[file lib.py]
5275+
C = C # type: ignore
5276+
from other import C
5277+
[file other.py]
5278+
class C:
5279+
pass
5280+
[out]
5281+
[out2]
5282+
5283+
[case testConditionalExceptionAliasOverride]
5284+
import a
5285+
[file a.py]
5286+
import lib
5287+
try:
5288+
x = 1
5289+
except lib.Exception as e:
5290+
pass
5291+
[file a.py.2]
5292+
import lib
5293+
try:
5294+
x = 2
5295+
except lib.Exception as e:
5296+
pass
5297+
[file lib.py]
5298+
try:
5299+
Exception = Exception
5300+
except BaseException:
5301+
class Exception(BaseException): pass # type: ignore
5302+
5303+
try:
5304+
pass
5305+
except Exception as e:
5306+
pass
5307+
[builtins fixtures/exception.pyi]
5308+
[out]
5309+
[out2]

test-data/unit/check-type-aliases.test

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,42 @@ def foo(x: Bogus[int]) -> None:
518518
reveal_type(x) # E: Revealed type is 'builtins.int'
519519

520520
[builtins fixtures/dict.pyi]
521+
522+
[case testOverrideByIdemAliasCorrectType]
523+
C = C
524+
class C: # type: ignore
525+
pass
526+
x: C
527+
reveal_type(x) # E: Revealed type is '__main__.C'
528+
[out]
529+
530+
[case testOverrideByIdemAliasCorrectTypeReversed]
531+
class C:
532+
pass
533+
C = C # type: ignore
534+
x: C
535+
reveal_type(x) # E: Revealed type is '__main__.C'
536+
[out]
537+
538+
[case testOverrideByIdemAliasCorrectTypeImported]
539+
from other import C as B
540+
C = B
541+
x: C
542+
reveal_type(x) # E: Revealed type is 'other.C'
543+
[file other.py]
544+
class C:
545+
pass
546+
[out]
547+
548+
[case testConditionalExceptionAlias]
549+
try:
550+
E = E
551+
except BaseException:
552+
class E(BaseException): pass # type: ignore
553+
554+
try:
555+
pass
556+
except E as e:
557+
reveal_type(e) # E: Revealed type is '__main__.E'
558+
[builtins fixtures/exception.pyi]
559+
[out]

test-data/unit/fixtures/exception.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ class bool: pass
1414
class ellipsis: pass
1515

1616
class BaseException: pass
17+
class Exception(BaseException): pass

0 commit comments

Comments
 (0)
0