| -- Type checker test cases dealing with modules and imports. |
| |
| [case testAccessImportedDefinitions] |
| import m |
| import typing |
| m.f() # E: Too few arguments for "f" |
| m.f(object()) # E: Argument 1 to "f" has incompatible type "object"; expected "A" |
| m.x = object() # E: Incompatible types in assignment (expression has type "object", variable has type "A") |
| m.f(m.A()) |
| m.x = m.A() |
| [file m.py] |
| class A: pass |
| def f(a: A) -> None: pass |
| x = A() |
| |
| [case testAccessImportedDefinitions] |
| import m |
| import typing |
| m.f(object()) # E: Argument 1 to "f" has incompatible type "object"; expected "A" |
| m.f(m.A()) |
| [file m.py] |
| class A: pass |
| def f(a: A) -> None: pass |
| |
| [case testAccessImportedDefinitions2] |
| from m import f, A |
| import typing |
| f(object()) # E: Argument 1 to "f" has incompatible type "object"; expected "A" |
| f(A()) |
| [file m.py] |
| class A: pass |
| def f(a: A) -> None: pass |
| |
| [case testImportedExceptionType] |
| import m |
| import typing |
| try: |
| pass |
| except m.Err: |
| pass |
| except m.Bad: # E: Exception type must be derived from BaseException |
| pass |
| [file m.py] |
| class Err(BaseException): pass |
| class Bad: pass |
| [builtins fixtures/exception.pyi] |
| |
| [case testImportedExceptionType2] |
| from m import Err, Bad |
| import typing |
| try: |
| pass |
| except Err: |
| pass |
| except Bad: # E: Exception type must be derived from BaseException |
| pass |
| [file m.py] |
| class Err(BaseException): pass |
| class Bad: pass |
| [builtins fixtures/exception.pyi] |
| |
| [case testImportWithinBlock] |
| import typing |
| if 1: |
| import m |
| m.a = m.b # E: Incompatible types in assignment (expression has type "B", variable has type "A") |
| m.a = m.a |
| m.f() |
| m.f(m.a) # E: Too many arguments for "f" |
| m.a = m.A() |
| m.a = m.B() # E: Incompatible types in assignment (expression has type "B", variable has type "A") |
| [file m.py] |
| class A: pass |
| class B: pass |
| a = A() |
| b = B() |
| def f() -> None: pass |
| |
| [case testImportWithinFunction] |
| import typing |
| def f() -> None: |
| from m import a, b, f, A, B |
| a = b # E: Incompatible types in assignment (expression has type "B", variable has type "A") |
| a = a |
| f() |
| f(a) # E: Too many arguments for "f" |
| a = A() |
| a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A") |
| [file m.py] |
| class A: pass |
| class B: pass |
| a = A() |
| b = B() |
| def f() -> None: pass |
| [out] |
| |
| [case testImportWithinMethod] |
| import typing |
| class C: |
| def f(self) -> None: |
| from m import * |
| a = b # E: Incompatible types in assignment (expression has type "B", variable has type "A") |
| a = a |
| f() |
| f(a) # E: Too many arguments for "f" |
| a = A() |
| a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A") |
| [file m.py] |
| class A: pass |
| class B: pass |
| a = A() |
| b = B() |
| def f() -> None: pass |
| [out] |
| |
| [case testImportWithinClassBody] |
| import typing |
| class C: |
| import m |
| m.f() |
| m.f(C) # E: Too many arguments for "f" |
| [file m.py] |
| def f() -> None: pass |
| [out] |
| |
| [case testImportWithinClassBody2] |
| import typing |
| class C: |
| from m import f |
| f() |
| f(C) # E: Too many arguments for "f" |
| [file m.py] |
| def f() -> None: pass |
| [out] |
| |
| [case testImportWithStub] |
| import _m |
| _m.f("hola") |
| [file _m.pyi] |
| def f(c:str) -> None: pass |
| [out] |
| |
| [case testImportWithStubIncompatibleType] |
| import _m |
| _m.f("hola") |
| _m.f(12) # E: Argument 1 to "f" has incompatible type "int"; expected "str" |
| [file _m.py] |
| def f(c): |
| print(c) |
| [file _m.pyi] |
| def f(c:str) -> None: pass |
| |
| [case testInvalidOperationsOnModules] |
| import m |
| import typing |
| class A: pass |
| m() # E: "module" not callable |
| a = m # type: A # E: Incompatible types in assignment (expression has type "module", variable has type "A") |
| m + None # E: Unsupported left operand type for + ("module") |
| [file m.py] |
| [builtins fixtures/module.pyi] |
| |
| [case testNameDefinedInDifferentModule] |
| import m, n |
| import typing |
| m.x # E: "module" has no attribute "x" |
| [file m.py] |
| y = object() |
| [file n.py] |
| x = object() |
| [builtins fixtures/module.pyi] |
| |
| [case testChainedAssignmentAndImports] |
| import m |
| |
| i, s = None, None # type: (int, str) |
| i = m.x |
| i = m.y |
| s = m.x # E: Incompatible types in assignment (expression has type "int", variable has type "str") |
| s = m.y # E: Incompatible types in assignment (expression has type "int", variable has type "str") |
| [file m.py] |
| x = y = 1 |
| [builtins fixtures/primitives.pyi] |
| |
| [case testConditionalFunctionDefinitionAndImports] |
| import m |
| import typing |
| m.f(1) |
| m.f('x') # E: Argument 1 to "f" has incompatible type "str"; expected "int" |
| [file m.py] |
| x = object() |
| if x: |
| def f(x: int) -> None: pass |
| else: |
| def f(x: int) -> None: pass |
| |
| [case testTypeCheckWithUnknownModule] |
| import nonexistent |
| None + '' |
| [out] |
| main:1: error: Cannot find module named 'nonexistent' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckWithUnknownModule2] |
| import m, nonexistent |
| None + '' |
| m.x = 1 |
| m.x = '' |
| [file m.py] |
| x = 1 |
| [out] |
| main:1: error: Cannot find module named 'nonexistent' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Unsupported left operand type for + (None) |
| main:4: error: Incompatible types in assignment (expression has type "str", variable has type "int") |
| |
| [case testTypeCheckWithUnknownModule3] |
| import nonexistent, m |
| None + '' |
| m.x = 1 |
| m.x = '' |
| [file m.py] |
| x = 1 |
| [out] |
| main:1: error: Cannot find module named 'nonexistent' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Unsupported left operand type for + (None) |
| main:4: error: Incompatible types in assignment (expression has type "str", variable has type "int") |
| |
| [case testTypeCheckWithUnknownModule4] |
| import nonexistent, another |
| None + '' |
| [out] |
| main:1: error: Cannot find module named 'nonexistent' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:1: error: Cannot find module named 'another' |
| main:2: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckWithUnknownModule5] |
| import nonexistent as x |
| None + '' |
| [out] |
| main:1: error: Cannot find module named 'nonexistent' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckWithUnknownModuleUsingFromImport] |
| from nonexistent import x |
| None + '' |
| [out] |
| main:1: error: Cannot find module named 'nonexistent' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckWithUnknownModuleUsingImportStar] |
| from nonexistent import * |
| None + '' |
| [out] |
| main:1: error: Cannot find module named 'nonexistent' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Unsupported left operand type for + (None) |
| |
| [case testAccessingUnknownModule] |
| import xyz |
| xyz.foo() |
| xyz() |
| [out] |
| main:1: error: Cannot find module named 'xyz' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| |
| [case testAccessingUnknownModule2] |
| import xyz, bar |
| xyz.foo() |
| bar() |
| [out] |
| main:1: error: Cannot find module named 'xyz' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:1: error: Cannot find module named 'bar' |
| |
| [case testAccessingUnknownModule3] |
| import xyz as z |
| xyz.foo() |
| z() |
| [out] |
| main:1: error: Cannot find module named 'xyz' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Name 'xyz' is not defined |
| |
| [case testAccessingNameImportedFromUnknownModule] |
| from xyz import y, z |
| y.foo() |
| z() |
| [out] |
| main:1: error: Cannot find module named 'xyz' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| |
| [case testAccessingNameImportedFromUnknownModule2] |
| from xyz import * |
| y |
| [out] |
| main:1: error: Cannot find module named 'xyz' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Name 'y' is not defined |
| |
| [case testAccessingNameImportedFromUnknownModule3] |
| from xyz import y as z |
| y |
| z |
| [out] |
| main:1: error: Cannot find module named 'xyz' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:2: error: Name 'y' is not defined |
| |
| [case testUnknownModuleRedefinition] |
| import xab |
| def xab(): pass |
| [out] |
| main:1: error: Cannot find module named 'xab' |
| main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| |
| [case testAccessingUnknownModuleFromOtherModule] |
| import x |
| x.nonexistent.foo |
| x.z |
| [file x.py] |
| import nonexistent |
| [builtins fixtures/module.pyi] |
| [out] |
| tmp/x.py:1: error: Cannot find module named 'nonexistent' |
| tmp/x.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:3: error: "module" has no attribute "z" |
| |
| [case testUnknownModuleImportedWithinFunction] |
| def f(): |
| import foobar |
| def foobar(): pass |
| foobar('') |
| [out] |
| main:2: error: Cannot find module named 'foobar' |
| main:2: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:4: error: Too many arguments for "foobar" |
| |
| [case testUnknownModuleImportedWithinFunction2] |
| def f(): |
| from foobar import x |
| def x(): pass |
| x('') |
| [out] |
| main:2: error: Cannot find module named 'foobar' |
| main:2: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help) |
| main:4: error: Too many arguments for "x" |
| |
| [case testRelativeImports] |
| import typing |
| import m.a |
| m.a.x = m.a.y # Error |
| [file m/__init__.py] |
| [file m/a.py] |
| import typing |
| from .b import A, B, x, y |
| z = x |
| z = y # Error |
| [file m/b.py] |
| import typing |
| class A: pass |
| class B: pass |
| x = A() |
| y = B() |
| [out] |
| tmp/m/a.py:4: error: Incompatible types in assignment (expression has type "B", variable has type "A") |
| main:3: error: Incompatible types in assignment (expression has type "B", variable has type "A") |
| |
| [case testRelativeImports2] |
| import typing |
| import m.a |
| m.a.x = m.a.y # E: Incompatible types in assignment (expression has type "B", variable has type "A") |
| [file m/__init__.py] |
| [file m/a.py] |
| import typing |
| from .b import A, B, x, y |
| [file m/b.py] |
| import typing |
| class A: pass |
| class B: pass |
| x = A() |
| y = B() |
| |
| [case testExportedValuesInImportAll] |
| import typing |
| from m import * |
| _ = a |
| _ = b |
| _ = c |
| _ = d |
| _ = e |
| _ = f # E: Name 'f' is not defined |
| _ = _g # E: Name '_g' is not defined |
| [file m.py] |
| __all__ = ['a'] |
| __all__ += ('b',) |
| __all__.append('c') |
| __all__.extend(('d', 'e')) |
| |
| a = b = c = d = e = f = _g = 1 |
| [builtins fixtures/module_all.pyi] |
| |
| [case testAllMustBeSequenceStr] |
| import typing |
| __all__ = [1, 2, 3] |
| [builtins fixtures/module_all.pyi] |
| [out] |
| main:2: error: Type of __all__ must be Sequence[str], not List[int] |
| |
| [case testAllMustBeSequenceStr_python2] |
| import typing |
| __all__ = [1, 2, 3] |
| [builtins_py2 fixtures/module_all_python2.pyi] |
| [out] |
| main:2: error: Type of __all__ must be Sequence[unicode], not List[int] |
| |
| [case testAllUnicodeSequenceOK_python2] |
| import typing |
| __all__ = [u'a', u'b', u'c'] |
| [builtins_py2 fixtures/module_all_python2.pyi] |
| |
| [out] |
| |
| [case testEllipsisInitializerInStubFileWithType] |
| import m |
| m.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int") |
| [file m.pyi] |
| x = ... # type: int |
| |
| [case testEllipsisInitializerInStubFileWithoutType] |
| import m |
| m.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "ellipsis") |
| [file m.pyi] |
| # Ellipsis is only special with a # type: comment (not sure though if this is great) |
| x = ... |
| |
| [case testEllipsisInitializerInModule] |
| x = ... # type: int # E: Incompatible types in assignment (expression has type "ellipsis", variable has type "int") |
| |
| [case testEllipsisDefaultArgValueInStub] |
| import m |
| m.f(1) |
| m.f('') # E: Argument 1 to "f" has incompatible type "str"; expected "int" |
| [file m.pyi] |
| def f(x: int = ...) -> None: pass |
| |
| [case testEllipsisDefaultArgValueInStub2] |
| import m |
| def f(x: int = ...) -> None: pass |
| [file m.pyi] |
| def g(x: int = '') -> None: pass |
| [out] |
| tmp/m.pyi:1: error: Incompatible types in assignment (expression has type "str", variable has type "int") |
| main:2: error: Incompatible types in assignment (expression has type "ellipsis", variable has type "int") |
| |
| [case testEllipsisDefaultArgValueInNonStub] |
| def f(x: int = ...) -> None: pass # E: Incompatible types in assignment (expression has type "ellipsis", variable has type "int") |
| [out] |
| |
| [case testStarImportOverlapping] |
| from m1 import * |
| from m2 import * |
| j = '' |
| [file m1.py] |
| x = 1 |
| [file m2.py] |
| x = 1 |
| |
| [case testStarImportOverlappingMismatch] |
| from m1 import * |
| from m2 import * # E: Incompatible import of "x" (imported name has type "int", local name has type "str") |
| j = '' |
| [file m1.py] |
| x = '' |
| [file m2.py] |
| x = 1 |
| |
| [case testStarImportOverridingLocalImports-skip] |
| from m1 import * |
| from m2 import * |
| x = '' # E: TODO (cannot assign str to int) |
| [file m1.py] |
| x = 1 |
| [file m2.py] |
| x = 1 |
| |
| [case testAssignToFuncDefViaImport] |
| from m import * # E: Incompatible import of "x" (imported name has type "int", local name has type "str") |
| f = None # E: Need type annotation for variable |
| x = '' |
| [file m.py] |
| def f(): pass |
| x = 1+0 |
| [out] |
| |
| |
| -- Conditional definitions and function redefinitions via module object |
| -- -------------------------------------------------------------------- |
| |
| |
| [case testConditionalImportAndAssign] |
| try: |
| from m import x |
| except: |
| x = None |
| try: |
| from m import x as y |
| except: |
| y = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str") |
| [file m.py] |
| x = '' |
| |
| [case testAssignAndConditionalImport] |
| x = '' |
| try: |
| from m import x |
| except: |
| pass |
| y = 1 |
| try: |
| from m import x as y # E: Incompatible import of "y" (imported name has type "str", local name has type "int") |
| except: |
| pass |
| [file m.py] |
| x = '' |
| |
| [case testAssignAndConditionalStarImport] |
| x = '' |
| y = 1 |
| try: |
| from m import * # E: Incompatible import of "y" (imported name has type "str", local name has type "int") |
| except: |
| pass |
| [file m.py] |
| x = '' |
| y = '' |
| |
| [case testRedefineImportedFunctionViaImport] |
| try: |
| from m import f, g |
| except: |
| def f(x): pass |
| def g(x): pass # E: All conditional function variants must have identical signatures |
| [file m.py] |
| def f(x): pass |
| def g(x, y): pass |
| |
| [case testImportedVariableViaImport] |
| try: |
| from m import x |
| except: |
| from n import x # E: Incompatible import of "x" (imported name has type "str", local name has type "int") |
| [file m.py] |
| x = 1 |
| [file n.py] |
| x = '' |
| |
| [case testRedefineFunctionViaImport] |
| def f(x): pass |
| def g(x): pass |
| try: |
| from m import f, g # E: Incompatible import of "g" (imported name has type Callable[[Any, Any], Any], local name has type Callable[[Any], Any]) |
| except: |
| pass |
| [file m.py] |
| def f(x): pass |
| def g(x, y): pass |
| |
| [case testImportVariableAndAssignNone] |
| try: |
| from m import x |
| except: |
| x = None |
| [file m.py] |
| x = 1 |
| |
| [case testImportFunctionAndAssignNone] |
| try: |
| from m import f |
| except: |
| f = None |
| [file m.py] |
| def f(): pass |
| |
| [case testImportFunctionAndAssignFunction] |
| def g(x): pass |
| try: |
| from m import f |
| except: |
| f = g |
| [file m.py] |
| def f(x): pass |
| |
| [case testImportFunctionAndAssignIncompatible] |
| try: |
| from m import f |
| except: |
| f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any]) |
| [file m.py] |
| def f(): pass |
| |
| [case testAssignToFuncDefViaGlobalDecl2] |
| import typing |
| from m import f |
| def g() -> None: |
| global f |
| f = None |
| f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any]) |
| [file m.py] |
| def f(): pass |
| [out] |
| |
| [case testAssignToFuncDefViaNestedModules] |
| import m.n |
| m.n.f = None |
| m.n.f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any]) |
| [file m/__init__.py] |
| [file m/n.py] |
| def f(): pass |
| [out] |
| |
| [case testAssignToFuncDefViaModule] |
| import m |
| m.f = None |
| m.f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any]) |
| [file m.py] |
| def f(): pass |
| [out] |
| |
| [case testConditionalImportAndAssignNoneToModule] |
| if object(): |
| import m |
| else: |
| m = None |
| m.f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "str" |
| [file m.py] |
| def f(x: str) -> None: pass |
| [builtins fixtures/module.pyi] |
| [out] |
| |
| [case testConditionalImportAndAssignInvalidToModule] |
| if object(): |
| import m |
| else: |
| m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "module") |
| [file m.py] |
| [builtins fixtures/module.pyi] |
| [out] |
| |
| [case testImportAndAssignToModule] |
| import m |
| m = None |
| m.f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "str" |
| [file m.py] |
| def f(x: str) -> None: pass |
| [builtins fixtures/module.pyi] |
| [out] |
| |
| |
| -- Test cases that simulate 'mypy -m modname' |
| -- |
| -- The module name to import is encoded in a comment. |
| |
| [case testTypeCheckNamedModule] |
| # cmd: mypy -m m.a |
| [file m/__init__.py] |
| None + 1 |
| [file m/a.py] |
| [out] |
| tmp/m/__init__.py:1: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckNamedModule2] |
| # cmd: mypy -m m.a |
| [file m/__init__.py] |
| [file m/a.py] |
| None + 1 |
| [out] |
| tmp/m/a.py:1: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckNamedModule3] |
| # cmd: mypy -m m |
| [file m/__init__.py] |
| None + 1 |
| [file m/a.py] |
| [out] |
| tmp/m/__init__.py:1: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckNamedModule4] |
| # cmd: mypy -m m |
| [file m/__init__.py] |
| [file m/a.py] |
| None + 1 # Not analyzed. |
| [out] |
| |
| [case testTypeCheckNamedModule5] |
| # cmd: mypy -m m |
| None + '' # Not analyzed. |
| [file m.py] |
| None + 1 |
| [out] |
| tmp/m.py:1: error: Unsupported left operand type for + (None) |
| |
| [case testTypeCheckNamedModuleWithImportCycle] |
| # cmd: mypy -m m.a |
| None + 1 # Does not generate error, as this file won't be analyzed. |
| [file m/__init__.py] |
| import m.a |
| [file m/a.py] |
| [out] |
| |
| |
| -- Checks dealing with submodules and different kinds of imports |
| -- ------------------------------------------------------------- |
| |
| [case testSubmoduleRegularImportAddsAllParents] |
| import a.b.c |
| reveal_type(a.value) # E: Revealed type is 'builtins.int' |
| reveal_type(a.b.value) # E: Revealed type is 'builtins.str' |
| reveal_type(a.b.c.value) # E: Revealed type is 'builtins.float' |
| b.value # E: Name 'b' is not defined |
| c.value # E: Name 'c' is not defined |
| |
| [file a/__init__.py] |
| value = 3 |
| [file a/b/__init__.py] |
| value = "a" |
| [file a/b/c.py] |
| value = 3.2 |
| [out] |
| |
| [case testSubmoduleImportAsDoesNotAddParents] |
| import a.b.c as foo |
| reveal_type(foo.value) # E: Revealed type is 'builtins.float' |
| a.value # E: Name 'a' is not defined |
| b.value # E: Name 'b' is not defined |
| c.value # E: Name 'c' is not defined |
| |
| [file a/__init__.py] |
| value = 3 |
| [file a/b/__init__.py] |
| value = "a" |
| [file a/b/c.py] |
| value = 3.2 |
| [out] |
| |
| [case testSubmoduleImportFromDoesNotAddParents] |
| from a import b |
| reveal_type(b.value) # E: Revealed type is 'builtins.str' |
| b.c.value # E: "module" has no attribute "c" |
| a.value # E: Name 'a' is not defined |
| |
| [file a/__init__.py] |
| value = 3 |
| [file a/b/__init__.py] |
| value = "a" |
| [file a/b/c.py] |
| value = 3.2 |
| [builtins fixtures/module.pyi] |
| [out] |
| |
| [case testSubmoduleImportFromDoesNotAddParents2] |
| from a.b import c |
| reveal_type(c.value) # E: Revealed type is 'builtins.float' |
| a.value # E: Name 'a' is not defined |
| b.value # E: Name 'b' is not defined |
| |
| [file a/__init__.py] |
| value = 3 |
| [file a/b/__init__.py] |
| value = "a" |
| [file a/b/c.py] |
| value = 3.2 |
| [out] |
| |
| [case testSubmoduleRegularImportNotDirectlyAddedToParent] |
| import a.b.c |
| def accept_float(x: float) -> None: pass |
| accept_float(a.b.c.value) |
| |
| [file a/__init__.py] |
| value = 3 |
| b.value |
| a.b.value |
| |
| [file a/b/__init__.py] |
| value = "a" |
| c.value |
| a.b.c.value |
| |
| [file a/b/c.py] |
| value = 3.2 |
| [out] |
| tmp/a/b/__init__.py:2: error: Name 'c' is not defined |
| tmp/a/b/__init__.py:3: error: Name 'a' is not defined |
| tmp/a/__init__.py:2: error: Name 'b' is not defined |
| tmp/a/__init__.py:3: error: Name 'a' is not defined |
| |
| [case testSubmoduleMixingLocalAndQualifiedNames] |
| from a.b import MyClass |
| val1 = None # type: a.b.MyClass # E: Name 'a' is not defined |
| val2 = None # type: MyClass |
| |
| [file a/__init__.py] |
| [file a/b.py] |
| class MyClass: pass |
| [out] |
| |
| [case testSubmoduleMixingImportFrom] |
| import parent.child |
| |
| [file parent/__init__.py] |
| |
| [file parent/common.py] |
| class SomeClass: pass |
| |
| [file parent/child.py] |
| from parent.common import SomeClass |
| from parent import common |
| foo = parent.common.SomeClass() |
| |
| [builtins fixtures/module.pyi] |
| [out] |
| tmp/parent/child.py:3: error: Name 'parent' is not defined |
| |
| [case testSubmoduleMixingImportFromAndImport] |
| import parent.child |
| |
| [file parent/__init__.py] |
| |
| [file parent/common.py] |
| class SomeClass: pass |
| |
| [file parent/unrelated.py] |
| class ShouldNotLoad: pass |
| |
| [file parent/child.py] |
| from parent.common import SomeClass |
| import parent |
| |
| # Note, since this might be unintuitive -- when `parent.common` is loaded in any way, |
| # shape, or form, it's added to `parent`'s namespace, which is why the below line |
| # succeeds. |
| foo = parent.common.SomeClass() |
| reveal_type(foo) |
| bar = parent.unrelated.ShouldNotLoad() |
| |
| [builtins fixtures/module.pyi] |
| [out] |
| tmp/parent/child.py:8: error: Revealed type is 'parent.common.SomeClass' |
| tmp/parent/child.py:9: error: "module" has no attribute "unrelated" |
| |
| [case testSubmoduleMixingImportFromAndImport2] |
| import parent.child |
| |
| [file parent/__init__.py] |
| |
| [file parent/common.py] |
| class SomeClass: pass |
| |
| [file parent/child.py] |
| from parent import common |
| import parent |
| foo = parent.common.SomeClass() |
| reveal_type(foo) |
| |
| [builtins fixtures/module.pyi] |
| [out] |
| tmp/parent/child.py:4: error: Revealed type is 'parent.common.SomeClass' |
| |
| -- Tests repeated imports |
| |
| [case testIdenticalImportFromTwice] |
| from a import x, y, z |
| from b import x, y, z |
| [file a.py] |
| from common import x, y, z |
| [file b.py] |
| from common import x, y, z |
| [file common.py] |
| x = 3 |
| def y() -> int: return 3 |
| class z: pass |
| [out] |
| |
| [case testIdenticalImportStarTwice] |
| from a import * |
| from b import * |
| [file a.py] |
| from common import x, y, z |
| [file b.py] |
| from common import x, y, z |
| [file common.py] |
| x = 3 |
| def y() -> int: return 3 |
| class z: pass |
| [out] |
| |
| [case testDifferentImportSameNameTwice] |
| from a import x, y, z |
| from b import x, y, z |
| [file a.py] |
| x = 3 |
| def y() -> int: return 1 |
| class z: pass |
| [file b.py] |
| x = "foo" |
| def y() -> str: return "foo" |
| class z: pass |
| [out] |
| main:2: error: Incompatible import of "x" (imported name has type "str", local name has type "int") |
| main:2: error: Incompatible import of "y" (imported name has type Callable[[], str], local name has type Callable[[], int]) |
| main:2: error: Incompatible import of "z" (imported name has type "z" (type object), local name has type "z" (type object)) |
| |
| -- Misc |
| |
| [case testInheritFromBadImport] |
| # cmd: mypy -m bar |
| [file foo.py] |
| pass |
| [file bar.py] |
| from foo import B |
| class C(B): |
| pass |
| [out] |
| tmp/bar.py:1: error: Module 'foo' has no attribute 'B' |
| |
| [case testImportSuppressedWhileAlmostSilent] |
| # cmd: mypy -m main |
| # flags: --follow-imports=error |
| [file main.py] |
| import mod |
| [file mod.py] |
| [builtins fixtures/module.pyi] |
| [out] |
| tmp/main.py:1: note: Import of 'mod' ignored |
| tmp/main.py:1: note: (Using --follow-imports=error, module not passed on command line) |
| |
| [case testAncestorSuppressedWhileAlmostSilent] |
| # cmd: mypy -m foo.bar |
| # flags: --follow-imports=error |
| [file foo/bar.py] |
| [file foo/__init__.py] |
| [builtins fixtures/module.pyi] |
| [out] |
| tmp/foo/bar.py: note: Ancestor package 'foo' ignored |
| tmp/foo/bar.py: note: (Using --follow-imports=error, submodule passed on command line) |
| |
| [case testStubImportNonStubWhileSilent] |
| # cmd: mypy -m main |
| # flags: --follow-imports=skip |
| [file main.py] |
| from stub import x # Permitted |
| from other import y # Disallowed |
| x + '' # Error here |
| y + '' # But not here |
| [file stub.pyi] |
| from non_stub import x |
| [file non_stub.py] |
| x = 42 |
| [file other.py] |
| y = 42 |
| [builtins fixtures/module.pyi] |
| [out] |
| tmp/main.py:3: error: Unsupported left operand type for + ("int") |
| |
| [case testSilentSubmoduleImport] |
| # cmd: mypy -m foo |
| # flags: --follow-imports=skip |
| [file foo/__init__.py] |
| from foo import bar |
| [file foo/bar.py] |
| pass |
| |
| [case testSuperclassInImportCycle] |
| import a |
| import d |
| a.A().f(d.D()) |
| [file a.py] |
| if 0: |
| import d |
| class B: pass |
| class C(B): pass |
| class A: |
| def f(self, x: B) -> None: pass |
| [file d.py] |
| import a |
| class D(a.C): pass |
| |
| [case testSuperclassInImportCycleReversedImports] |
| import d |
| import a |
| a.A().f(d.D()) |
| [file a.py] |
| if 0: |
| import d |
| class B: pass |
| class C(B): pass |
| class A: |
| def f(self, x: B) -> None: pass |
| [file d.py] |
| import a |
| class D(a.C): pass |
| |
| [case testPreferPackageOverFile] |
| import a |
| [file a.py] |
| / # intentional syntax error -- this file shouldn't be parsed |
| [file a/__init__.py] |
| pass |
| [out] |
| |
| [case testPreferPackageOverFile2] |
| from a import x |
| [file a.py] |
| / # intentional syntax error -- this file shouldn't be parsed |
| [file a/__init__.py] |
| x = 0 |
| [out] |
| |
| [case testImportInClass] |
| class C: |
| import foo |
| reveal_type(C.foo.bar) # E: Revealed type is 'builtins.int' |
| [file foo.py] |
| bar = 0 |
| [builtins fixtures/module.pyi] |
| [out] |
| |
| [case testIfFalseImport] |
| if False: |
| import a |
| def f(x: 'a.A') -> int: |
| return x.f() |
| [file a.py] |
| class A: |
| def f(self) -> int: |
| return 0 |
| [builtins fixtures/bool.pyi] |
| |
| |
| -- Test stability under import cycles |
| -- ---------------------------------- |
| |
| -- The first two tests are identical except one main has 'import x' |
| -- and the other 'import y'. Previously (before build.order_ascc() |
| -- was added) one of these would fail because the imports were |
| -- processed in the (reverse) order in which the files were |
| -- encountered. |
| |
| [case testImportCycleStability1] |
| import x |
| [file x.py] |
| def f() -> str: return '' |
| class Base: |
| attr = f() |
| def foo(): |
| import y |
| [file y.py] |
| import x |
| class Sub(x.Base): |
| attr = x.Base.attr |
| [out] |
| |
| [case testImportCycleStability2] |
| import y |
| [file x.py] |
| def f() -> str: return '' |
| class Base: |
| attr = f() |
| def foo(): |
| import y |
| [file y.py] |
| import x |
| class Sub(x.Base): |
| attr = x.Base.attr |
| [out] |
| |
| -- This case isn't fixed by order_ascc(), but is fixed by the |
| -- lightweight type inference added to semanal.py |
| -- (analyze_simple_literal_type()). |
| |
| [case testImportCycleStability3] |
| import y |
| [file x.py] |
| class Base: |
| pass |
| def foo() -> int: |
| import y |
| reveal_type(y.Sub.attr) |
| return y.Sub.attr |
| [file y.py] |
| import x |
| class Sub(x.Base): |
| attr = 0 |
| [out] |
| tmp/x.py:5: error: Revealed type is 'builtins.int' |
| |
| -- This case has a symmetrical cycle, so it doesn't matter in what |
| -- order the files are processed. It depends on the lightweight type |
| -- interference. |
| |
| [case testImportCycleStability4] |
| import x |
| [file x.py] |
| import y |
| class C: |
| attr = '' |
| def foo() -> int: |
| return y.D.attr |
| [file y.py] |
| import x |
| class D: |
| attr = 0 |
| def bar() -> str: |
| return x.C.attr |
| |
| -- These cases test all supported literal types. |
| |
| [case testImportCycleStability5] |
| import y |
| [file x.py] |
| class Base: |
| pass |
| def foo() -> None: |
| import y |
| i = y.Sub.iattr # type: int |
| f = y.Sub.fattr # type: float |
| s = y.Sub.sattr # type: str |
| b = y.Sub.battr # type: bytes |
| [file y.py] |
| import x |
| class Sub(x.Base): |
| iattr = 0 |
| fattr = 0.0 |
| sattr = '' |
| battr = b'' |
| [out] |
| |
| [case testImportCycleStability6_python2] |
| import y |
| [file x.py] |
| class Base: |
| pass |
| def foo(): |
| # type: () -> None |
| import y |
| i = y.Sub.iattr # type: int |
| f = y.Sub.fattr # type: float |
| s = y.Sub.sattr # type: str |
| u = y.Sub.uattr # type: unicode |
| [file y.py] |
| import x |
| class Sub(x.Base): |
| iattr = 0 |
| fattr = 0.0 |
| sattr = '' |
| uattr = u'' |
| [out] |
| |
| -- This case tests module-level variables. |
| |
| [case testImportCycleStability7] |
| import x |
| [file x.py] |
| def foo() -> int: |
| import y |
| reveal_type(y.value) |
| return y.value |
| [file y.py] |
| import x |
| value = 12 |
| [out] |
| tmp/x.py:3: error: Revealed type is 'builtins.int' |
| |
| -- This is not really cycle-related but still about the lightweight |
| -- type checker. |
| |
| [case testImportCycleStability8] |
| x = 1 # type: str |
| reveal_type(x) |
| [out] |
| main:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") |
| main:2: error: Revealed type is 'builtins.str' |
| |
| -- Tests for cross-module second_pass checking. |
| |
| [case testSymmetricImportCycle1] |
| import a |
| [file a.py] |
| import b |
| def f() -> int: |
| return b.x |
| y = 0 + 0 |
| [file b.py] |
| import a |
| def g() -> int: |
| reveal_type(a.y) |
| return a.y |
| x = 1 + 1 |
| [out] |
| tmp/b.py:3: error: Revealed type is 'builtins.int' |
| |
| [case testSymmetricImportCycle2] |
| import b |
| [file a.py] |
| import b |
| def f() -> int: |
| reveal_type(b.x) |
| return b.x |
| y = 0 + 0 |
| [file b.py] |
| import a |
| def g() -> int: |
| return a.y |
| x = 1 + 1 |
| [out] |
| tmp/a.py:3: error: Revealed type is 'builtins.int' |
| |
| [case testThreePassesRequired] |
| import b |
| [file a.py] |
| import b |
| class C: |
| def f1(self) -> None: |
| self.x2 |
| def f2(self) -> None: |
| self.x2 = b.b |
| [file b.py] |
| import a |
| b = 1 + 1 |
| [out] |
| tmp/a.py:4: error: Cannot determine type of 'x2' |
| |
| [case testErrorInPassTwo1] |
| import b |
| [file a.py] |
| import b |
| def f() -> None: |
| a = b.x + 1 |
| a + '' |
| [file b.py] |
| import a |
| x = 1 + 1 |
| [out] |
| tmp/a.py:4: error: Unsupported operand types for + ("int" and "str") |
| |
| [case testErrorInPassTwo2] |
| import a |
| [file a.py] |
| import b |
| def f() -> None: |
| a = b.x + 1 |
| a + '' |
| [file b.py] |
| import a |
| x = 1 + 1 |
| [out] |
| tmp/a.py:4: error: Unsupported operand types for + ("int" and "str") |
| |
| [case testDeferredDecorator] |
| import a |
| [file a.py] |
| import b |
| def g() -> None: |
| f('') |
| @b.deco |
| def f(a: str) -> int: pass |
| reveal_type(f) |
| x = 1 + 1 |
| [file b.py] |
| from typing import Callable, TypeVar |
| import a |
| T = TypeVar('T') |
| def deco(f: Callable[[T], int]) -> Callable[[T], int]: |
| a.x |
| return f |
| [out] |
| tmp/a.py:6: error: Revealed type is 'def (builtins.str*) -> builtins.int' |
| |
| [case testDeferredClassContext] |
| class A: |
| def f(self) -> str: return 'foo' |
| class B(A): |
| def f(self) -> str: return self.x |
| def initialize(self): self.x = 'bar' |
| [out] |
| |
| |
| -- Scripts and __main__ |
| |
| [case testScriptsAreModules] |
| # flags: --scripts-are-modules |
| [file a] |
| pass |
| [file b] |
| pass |
| |
| [case testScriptsAreNotModules] |
| # cmd: mypy a b |
| [file a] |
| pass |
| [file b] |
| pass |
| [out] |
| |
| [case testTypeCheckPrio] |
| # cmd: mypy -m part1 part2 part3 part4 |
| |
| [file part1.py] |
| from part3 import Thing |
| class FirstThing: pass |
| |
| [file part2.py] |
| from part4 import part4_thing as Thing |
| |
| [file part3.py] |
| from part2 import Thing |
| reveal_type(Thing) |
| |
| [file part4.py] |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| from part1 import FirstThing |
| def part4_thing(a: int) -> str: pass |
| |
| [builtins fixtures/bool.pyi] |
| [out] |
| tmp/part3.py:2: error: Revealed type is 'def (a: builtins.int) -> builtins.str' |
| |
| [case testImportStarAliasAnyList] |
| import bar |
| |
| [file bar.py] |
| from foo import * |
| def bar(y: AnyAlias) -> None: pass |
| |
| l = None # type: ListAlias[int] |
| reveal_type(l) |
| |
| [file foo.py] |
| from typing import Any, List |
| AnyAlias = Any |
| ListAlias = List |
| [builtins fixtures/list.pyi] |
| [out] |
| tmp/bar.py:5: error: Revealed type is 'builtins.list[builtins.int]' |
| |
| [case testImportStarAliasSimpleGeneric] |
| from ex2a import * |
| |
| def do_something(dic: Row) -> None: |
| pass |
| |
| def do_another() -> Row: |
| return {} |
| |
| do_something({'good': 'bad'}) # E: List item 0 has incompatible type "Tuple[str, str]" |
| reveal_type(do_another()) # E: Revealed type is 'builtins.dict[builtins.str, builtins.int]' |
| |
| [file ex2a.py] |
| from typing import Dict |
| Row = Dict[str, int] |
| [builtins fixtures/dict.pyi] |
| [out] |
| |
| [case testImportStarAliasGeneric] |
| from y import * |
| notes = None # type: G[X] |
| another = G[X]() |
| second = XT[str]() |
| last = XT[G]() |
| |
| reveal_type(notes) # E: Revealed type is 'y.G[y.G[builtins.int]]' |
| reveal_type(another) # E: Revealed type is 'y.G[y.G*[builtins.int]]' |
| reveal_type(second) # E: Revealed type is 'y.G[builtins.str*]' |
| reveal_type(last) # E: Revealed type is 'y.G[y.G*]' |
| |
| [file y.py] |
| from typing import Generic, TypeVar |
| |
| T = TypeVar('T') |
| |
| class G(Generic[T]): |
| pass |
| |
| X = G[int] |
| XT = G[T] |
| [out] |
| |
| [case testImportStarAliasCallable] |
| from foo import * |
| from typing import Any |
| |
| def bar(x: Any, y: AnyCallable) -> Any: |
| return 'foo' |
| |
| cb = None # type: AnyCallable |
| reveal_type(cb) # E: Revealed type is 'def (*Any, **Any) -> Any' |
| |
| [file foo.py] |
| from typing import Callable, Any |
| AnyCallable = Callable[..., Any] |
| [out] |