Skip to content

Commit

Permalink
Merge branch 'master' into issubclass
Browse files Browse the repository at this point in the history
  • Loading branch information
pkch committed Apr 13, 2017
2 parents a260b79 + 73acdb8 commit 75bee74
Show file tree
Hide file tree
Showing 21 changed files with 136 additions and 48 deletions.
15 changes: 14 additions & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
result = type_object_type(node, self.named_type)
elif isinstance(node, MypyFile):
# Reference to a module object.
result = self.named_type('builtins.module')
result = self.named_type('types.ModuleType')
elif isinstance(node, Decorator):
result = self.analyze_var_ref(node.var, e)
else:
Expand All @@ -178,6 +178,19 @@ def visit_call_expr(self, e: CallExpr, allow_none_return: bool = False) -> Type:
e.callee.node.typeddict_type is not None:
return self.check_typeddict_call(e.callee.node.typeddict_type,
e.arg_kinds, e.arg_names, e.args, e)
if isinstance(e.callee, NameExpr) and e.callee.name in ('isinstance', 'issubclass'):
for typ in mypy.checker.flatten(e.args[1]):
if isinstance(typ, NameExpr):
try:
node = self.chk.lookup_qualified(typ.name)
except KeyError:
# Undefined names should already be reported in semantic analysis.
node = None
if (isinstance(typ, IndexExpr)
and isinstance(typ.analyzed, (TypeApplication, TypeAliasExpr))
# node.kind == TYPE_ALIAS only for aliases like It = Iterable[int].
or isinstance(typ, NameExpr) and node and node.kind == nodes.TYPE_ALIAS):
self.msg.type_arguments_not_allowed(e)
self.try_infer_partial_type(e)
callee_type = self.accept(e.callee)
if (self.chk.options.disallow_untyped_calls and
Expand Down
2 changes: 1 addition & 1 deletion mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def analyze_class_attribute_access(itype: Instance,

if isinstance(node.node, MypyFile):
# Reference to a module object.
return builtin_type('builtins.module')
return builtin_type('types.ModuleType')

if is_decorated:
# TODO: Return type of decorated function. This is quick hack to work around #998.
Expand Down
3 changes: 3 additions & 0 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,9 @@ def typeddict_item_name_not_found(self,
self.fail('\'{}\' is not a valid item name; expected one of {}'.format(
item_name, format_item_name_list(typ.items.keys())), context)

def type_arguments_not_allowed(self, context: Context) -> None:
self.fail('Parameterized generics cannot be used with class or instance checks', context)


def capitalize(s: str) -> str:
"""Capitalize the first character of a string."""
Expand Down
9 changes: 9 additions & 0 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@
'typing.typevar': 'typing.TypeVar',
}

# Rename objects placed in _importlib_modulespec due to circular imports
module_rename_map = {
'_importlib_modulespec.ModuleType': 'types.ModuleType',
'_importlib_modulespec.ModuleSpec': 'importlib.machinery.ModuleSpec',
'_importlib_modulespec.Loader': 'importlib.abc.Loader'
}

# Hard coded type promotions (shared between all Python versions).
# These add extra ad-hoc edges to the subtyping relation. For example,
# int is considered a subtype of float, even though there is no
Expand Down Expand Up @@ -3445,6 +3452,8 @@ def visit_file(self, file: MypyFile, fnam: str, mod_id: str, options: Options) -

for d in defs:
d.accept(self)
if isinstance(d, ClassDef):
d.info._fullname = module_rename_map.get(d.info._fullname, d.info._fullname)

# Add implicit definition of literals/keywords to builtins, as we
# cannot define a variable with them explicitly.
Expand Down
6 changes: 4 additions & 2 deletions mypy/server/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,12 @@ def visit_tuple_type(self, typ: TupleType) -> List[str]:
raise NotImplementedError

def visit_type_type(self, typ: TypeType) -> List[str]:
raise NotImplementedError
# TODO: replace with actual implementation
return []

def visit_type_var(self, typ: TypeVarType) -> List[str]:
raise NotImplementedError
# TODO: replace with actual implementation
return []

def visit_typeddict_type(self, typ: TypedDictType) -> List[str]:
raise NotImplementedError
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-ignore.test
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import b # type: ignore
reveal_type(a.foo) # E: Revealed type is 'Any'
reveal_type(b.foo) # E: Revealed type is 'builtins.int'
a.bar()
b.bar() # E: "module" has no attribute "bar"
b.bar() # E: "ModuleType" has no attribute "bar"

[file b.py]
foo = 3
Expand Down Expand Up @@ -76,7 +76,7 @@ class B(A):
import m
m.x = object # type: ignore
m.f() # type: ignore
m.y # E: "module" has no attribute "y"
m.y # E: "ModuleType" has no attribute "y"
[file m.py]
[builtins fixtures/module.pyi]

Expand Down
6 changes: 3 additions & 3 deletions test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ const = 3
[stale mod3]
[builtins fixtures/module.pyi]
[out2]
tmp/mod1.py:3: error: "module" has no attribute "mod4"
tmp/mod1.py:3: error: "ModuleType" has no attribute "mod4"

[case testIncrementalLongBrokenCascade]
import mod1
Expand Down Expand Up @@ -335,7 +335,7 @@ const = 3
[stale mod6]
[builtins fixtures/module.pyi]
[out2]
tmp/mod1.py:3: error: "module" has no attribute "mod7"
tmp/mod1.py:3: error: "ModuleType" has no attribute "mod7"

[case testIncrementalNestedBrokenCascade]
import mod1
Expand All @@ -361,7 +361,7 @@ const = 3
[stale mod2.mod3]
[builtins fixtures/module.pyi]
[out2]
tmp/mod1.py:3: error: "module" has no attribute "mod4"
tmp/mod1.py:3: error: "ModuleType" has no attribute "mod4"

[case testIncrementalNestedBrokenCascadeWithType1]
import mod1, mod2.mod3.mod5
Expand Down
39 changes: 39 additions & 0 deletions test-data/unit/check-isinstance.test
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,45 @@ def f(cls: Type[object]) -> None:

[builtins fixtures/isinstancelist.pyi]

[case testIsinstanceTypeArgs]
from typing import Iterable, TypeVar
x = 1
T = TypeVar('T')

isinstance(x, Iterable)
isinstance(x, Iterable[int]) # E: Parameterized generics cannot be used with class or instance checks
isinstance(x, Iterable[T]) # E: Parameterized generics cannot be used with class or instance checks
isinstance(x, (int, Iterable[int])) # E: Parameterized generics cannot be used with class or instance checks
isinstance(x, (int, (str, Iterable[int]))) # E: Parameterized generics cannot be used with class or instance checks

[builtins fixtures/isinstancelist.pyi]

[case testIsinstanceTypeArgsAliases]
from typing import Iterable, TypeVar
x = 1
T = TypeVar('T')
It = Iterable
It2 = Iterable[T]

isinstance(x, It[int]) # E: Parameterized generics cannot be used with class or instance checks
isinstance(x, It)
isinstance(x, It2[int]) # E: Parameterized generics cannot be used with class or instance checks
isinstance(x, It2) # E: Parameterized generics cannot be used with class or instance checks

[builtins fixtures/isinstance.pyi]


[case testIssubclassTypeArgs]
from typing import Iterable, TypeVar
x = int
T = TypeVar('T')
issubclass(x, Iterable)
issubclass(x, Iterable[int]) # E: Parameterized generics cannot be used with class or instance checks
issubclass(x, Iterable[T]) # E: Parameterized generics cannot be used with class or instance checks
issubclass(x, (int, Iterable[int])) # E: Parameterized generics cannot be used with class or instance checks

[builtins fixtures/isinstance.pyi]

[case testIsinstanceAndNarrowTypeVariable]
from typing import TypeVar

Expand Down
26 changes: 18 additions & 8 deletions test-data/unit/check-modules.test
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,18 @@ 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")
m() # E: "ModuleType" not callable
a = m # type: A # E: Incompatible types in assignment (expression has type "ModuleType", variable has type "A")
m + None # E: Unsupported left operand type for + ("ModuleType")
[file m.py]
[builtins fixtures/module.pyi]

[case testNameDefinedInDifferentModule]
import m, n
import typing
m.x # E: "module" has no attribute "x"
m.x # E: "ModuleType" has no attribute "x"
[file m.py]
y = object()
[file n.py]
Expand Down Expand Up @@ -329,7 +330,7 @@ import nonexistent
[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"
main:3: error: "ModuleType" has no attribute "z"

[case testUnknownModuleImportedWithinFunction]
def f():
Expand Down Expand Up @@ -647,7 +648,7 @@ def f(x: str) -> None: pass
if object():
import m
else:
m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "module")
m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "ModuleType")
[file m.py]
[builtins fixtures/module.pyi]
[out]
Expand Down Expand Up @@ -751,7 +752,7 @@ value = 3.2
[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"
b.c.value # E: "ModuleType" has no attribute "c"
a.value # E: Name 'a' is not defined

[file a/__init__.py]
Expand Down Expand Up @@ -852,7 +853,7 @@ 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"
tmp/parent/child.py:9: error: "ModuleType" has no attribute "unrelated"

[case testSubmoduleMixingImportFromAndImport2]
import parent.child
Expand Down Expand Up @@ -1406,3 +1407,12 @@ reveal_type(cb) # E: Revealed type is 'def (*Any, **Any) -> Any'
from typing import Callable, Any
AnyCallable = Callable[..., Any]
[out]

[case testRevealType]
import types
def f() -> types.ModuleType:
return types
reveal_type(f()) # E: Revealed type is 'types.ModuleType'
reveal_type(types) # E: Revealed type is 'types.ModuleType'

[builtins fixtures/module.pyi]
8 changes: 4 additions & 4 deletions test-data/unit/cmdline.test
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,8 @@ x += '' # Error reported here
a.py:2: error: Unsupported operand types for + ("int" and "str")
main.py:3: error: Unsupported operand types for + ("int" and "str")
main.py:6: error: Unsupported operand types for + ("int" and "str")
main.py:7: error: "module" has no attribute "y"
main.py:8: error: Unsupported operand types for + ("module" and "int")
main.py:7: error: "ModuleType" has no attribute "y"
main.py:8: error: Unsupported operand types for + ("ModuleType" and "int")

[case testConfigFollowImportsSilent]
# cmd: mypy main.py
Expand All @@ -386,8 +386,8 @@ x += '' # No error reported
[out]
main.py:2: error: Unsupported operand types for + ("int" and "str")
main.py:4: error: Unsupported operand types for + ("int" and "str")
main.py:5: error: "module" has no attribute "y"
main.py:6: error: Unsupported operand types for + ("module" and "int")
main.py:5: error: "ModuleType" has no attribute "y"
main.py:6: error: Unsupported operand types for + ("ModuleType" and "int")

[case testConfigFollowImportsSkip]
# cmd: mypy main.py
Expand Down
24 changes: 12 additions & 12 deletions test-data/unit/fine-grained.test
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def g(x: str) -> None: pass
[builtins fixtures/fine_grained.pyi]
[out]
==
main:3: error: "module" has no attribute "f"
main:3: error: "ModuleType" has no attribute "f"

[case testTopLevelMissingModuleAttribute]
import m
Expand All @@ -81,7 +81,7 @@ def g(x: int) -> None: pass
[builtins fixtures/fine_grained.pyi]
[out]
==
main:2: error: "module" has no attribute "f"
main:2: error: "ModuleType" has no attribute "f"

[case testClassChangedIntoFunction]
import m
Expand Down Expand Up @@ -241,7 +241,7 @@ class A: pass
[builtins fixtures/fine_grained.pyi]
[out]
==
main:3: error: "module" has no attribute "A"
main:3: error: "ModuleType" has no attribute "A"
==

[case testContinueToReportTypeCheckError]
Expand Down Expand Up @@ -281,10 +281,10 @@ class A: pass
[builtins fixtures/fine_grained.pyi]
[out]
==
main:3: error: "module" has no attribute "A"
main:5: error: "module" has no attribute "B"
main:3: error: "ModuleType" has no attribute "A"
main:5: error: "ModuleType" has no attribute "B"
==
main:5: error: "module" has no attribute "B"
main:5: error: "ModuleType" has no attribute "B"

[case testContinueToReportErrorAtTopLevel]
import n
Expand Down Expand Up @@ -348,9 +348,9 @@ def g() -> None: pass
[builtins fixtures/fine_grained.pyi]
[out]
main:3: error: Too few arguments for "f"
main:5: error: "module" has no attribute "g"
main:5: error: "ModuleType" has no attribute "g"
==
main:5: error: "module" has no attribute "g"
main:5: error: "ModuleType" has no attribute "g"
==

[case testKeepReportingErrorIfNoChanges]
Expand All @@ -361,9 +361,9 @@ def h() -> None:
[file m.py.2]
[builtins fixtures/fine_grained.pyi]
[out]
main:3: error: "module" has no attribute "g"
main:3: error: "ModuleType" has no attribute "g"
==
main:3: error: "module" has no attribute "g"
main:3: error: "ModuleType" has no attribute "g"

[case testFixErrorAndReintroduce]
import m
Expand All @@ -375,10 +375,10 @@ def g() -> None: pass
[file m.py.3]
[builtins fixtures/fine_grained.pyi]
[out]
main:3: error: "module" has no attribute "g"
main:3: error: "ModuleType" has no attribute "g"
==
==
main:3: error: "module" has no attribute "g"
main:3: error: "ModuleType" has no attribute "g"

[case testAddBaseClassMethodCausingInvalidOverride]
import m
Expand Down
1 change: 0 additions & 1 deletion test-data/unit/fixtures/args.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,3 @@ class int:
class str: pass
class bool: pass
class function: pass
class module: pass
6 changes: 5 additions & 1 deletion test-data/unit/fixtures/async_await.pyi
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import typing

T = typing.TypeVar('T')
class list(typing.Generic[T], typing.Sequence[T]): pass

class object:
def __init__(self): pass
class type: pass
class function: pass
class int: pass
class str: pass
class dict: pass
class list: pass
class set: pass
class tuple: pass
class BaseException: pass
class StopIteration(BaseException): pass
class StopAsyncIteration(BaseException): pass
def iter(obj: typing.Any) -> typing.Any: pass
def next(obj: typing.Any) -> typing.Any: pass
class ellipsis: ...
4 changes: 3 additions & 1 deletion test-data/unit/fixtures/fine_grained.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# TODO: Migrate to regular stubs once fine-grained incremental is robust
# enough to handle them.

import types

class Any: pass

class object:
Expand All @@ -21,4 +23,4 @@ class bytes: pass
class tuple: pass
class function: pass
class ellipsis: pass
class module: pass
class list: pass
1 change: 1 addition & 0 deletions test-data/unit/fixtures/isinstance.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class tuple(Generic[T]): pass
class function: pass

def isinstance(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass
def issubclass(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass

class int:
def __add__(self, other: 'int') -> 'int': pass
Expand Down
Loading

0 comments on commit 75bee74

Please sign in to comment.