Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Improve test output when a test doesn't specify the correct fixture #3488

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,13 @@ 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('types.ModuleType')
try:
result = self.named_type('types.ModuleType')
except KeyError:
# In test cases might 'types' may not be available.
# Fall back to a dummy 'object' type instead to
# avoid a crash.
result = self.named_type('builtins.object')
elif isinstance(node, Decorator):
result = self.analyze_var_ref(node.var, e)
else:
Expand Down
40 changes: 36 additions & 4 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,21 @@
'_make', '_replace', '_asdict', '_source',
'__annotations__')

# Map from the full name of a missing definition to the test fixture (under
# test-data/unit/fixtures/) that provides the definition. This is used for
# generating better error messages when running mypy tests only.
SUGGESTED_TEST_FIXTURES = {
'typing.List': 'list.pyi',
'typing.Dict': 'dict.pyi',
'typing.Set': 'set.pyi',
'builtins.bool': 'bool.pyi',
'builtins.Exception': 'exception.pyi',
'builtins.BaseException': 'exception.pyi',
'builtins.isinstance': 'isinstancelist.pyi',
'builtins.property': 'property.pyi',
'builtins.classmethod': 'classmethod.pyi',
}


class SemanticAnalyzer(NodeVisitor):
"""Semantically analyze parsed mypy files.
Expand Down Expand Up @@ -1373,20 +1388,31 @@ def process_import_over_existing_name(self,
def normalize_type_alias(self, node: SymbolTableNode,
ctx: Context) -> SymbolTableNode:
normalized = False
if node.fullname in type_aliases:
fullname = node.fullname
if fullname in type_aliases:
# Node refers to an aliased type such as typing.List; normalize.
node = self.lookup_qualified(type_aliases[node.fullname], ctx)
node = self.lookup_qualified(type_aliases[fullname], ctx)
if node is None:
self.add_fixture_note(fullname, ctx)
return None
normalized = True
if node.fullname in collections_type_aliases:
if fullname in collections_type_aliases:
# Similar, but for types from the collections module like typing.DefaultDict
self.add_module_symbol('collections', '__mypy_collections__', False, ctx)
node = self.lookup_qualified(collections_type_aliases[node.fullname], ctx)
node = self.lookup_qualified(collections_type_aliases[fullname], ctx)
normalized = True
if normalized:
node = SymbolTableNode(node.kind, node.node,
node.mod_id, node.type_override, normalized=True)
return node

def add_fixture_note(self, fullname: str, ctx: Context) -> None:
self.note('Maybe your test fixture does not define "{}"?'.format(fullname), ctx)
if fullname in SUGGESTED_TEST_FIXTURES:
self.note(
'Consider adding [builtins fixtures/{}] to your test description'.format(
SUGGESTED_TEST_FIXTURES[fullname]), ctx)

def correct_relative_import(self, node: Union[ImportFrom, ImportAll]) -> str:
if node.relative == 0:
return node.id
Expand Down Expand Up @@ -3337,6 +3363,12 @@ def name_not_defined(self, name: str, ctx: Context) -> None:
if extra:
message += ' {}'.format(extra)
self.fail(message, ctx)
if 'builtins.{}'.format(name) in SUGGESTED_TEST_FIXTURES:
# The user probably has a missing definition in a test fixture. Let's verify.
fullname = 'builtins.{}'.format(name)
if self.lookup_fully_qualified_or_none(fullname) is None:
# Yes. Generate a helpful note.
self.add_fixture_note(fullname, ctx)

def name_already_defined(self, name: str, ctx: Context) -> None:
self.fail("Name '{}' already defined".format(name), ctx)
Expand Down
1 change: 1 addition & 0 deletions mypy/test/testcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
'check-underscores.test',
'check-classvar.test',
'check-enum.test',
'check-incomplete-fixture.test',
]


Expand Down
98 changes: 98 additions & 0 deletions test-data/unit/check-incomplete-fixture.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
-- Test cases for reporting errors when a test case uses a fixture with
-- missing definitions. At least in the most common cases this should not
-- result in an uncaught exception. These tests make sure that this behavior
-- does not regress.
--
-- NOTE: These tests do NOT test behavior of mypy outside tests.

[case testVariableUndefinedUsingDefaultFixture]
import m
# This used to cause a crash since types.ModuleType is not available
# by default. We fall back to 'object' now.
m.x # E: "object" has no attribute "x"
[file m.py]

[case testListMissingFromStubs]
from typing import List
def f(x: List[int]) -> None: pass
[out]
main:1: error: Name '__builtins__.list' is not defined
main:1: note: Maybe your test fixture does not define "typing.List"?
main:1: note: Consider adding [builtins fixtures/list.pyi] to your test description

[case testDictMissingFromStubs]
from typing import Dict
def f(x: Dict[int]) -> None: pass
[out]
main:1: error: Name '__builtins__.dict' is not defined
main:1: note: Maybe your test fixture does not define "typing.Dict"?
main:1: note: Consider adding [builtins fixtures/dict.pyi] to your test description

[case testSetMissingFromStubs]
from typing import Set
def f(x: Set[int]) -> None: pass
[out]
main:1: error: Name '__builtins__.set' is not defined
main:1: note: Maybe your test fixture does not define "typing.Set"?
main:1: note: Consider adding [builtins fixtures/set.pyi] to your test description

[case testBoolMissingFromStubs]
x: bool
[out]
main:1: error: Name 'bool' is not defined
main:1: note: Maybe your test fixture does not define "builtins.bool"?
main:1: note: Consider adding [builtins fixtures/bool.pyi] to your test description

[case testBaseExceptionMissingFromStubs]
e: BaseException
[out]
main:1: error: Name 'BaseException' is not defined
main:1: note: Maybe your test fixture does not define "builtins.BaseException"?
main:1: note: Consider adding [builtins fixtures/exception.pyi] to your test description

[case testExceptionMissingFromStubs]
e: Exception
[out]
main:1: error: Name 'Exception' is not defined
main:1: note: Maybe your test fixture does not define "builtins.Exception"?
main:1: note: Consider adding [builtins fixtures/exception.pyi] to your test description

[case testIsinstanceMissingFromStubs]
if isinstance(1, int):
pass
[out]
main:1: error: Name 'isinstance' is not defined
main:1: note: Maybe your test fixture does not define "builtins.isinstance"?
main:1: note: Consider adding [builtins fixtures/isinstancelist.pyi] to your test description

[case testInvalidTupleDefinitionFromStubs]
from typing import Tuple
x: Tuple[int, ...]
x[0]
for y in x:
pass
[out]
-- These errors are pretty bad, but keeping this test anyway to
-- avoid things getting worse.
main:2: error: "tuple" expects no type arguments, but 1 given
main:3: error: Value of type "tuple" is not indexable
main:4: error: Iterable expected
main:4: error: "tuple" has no attribute "__iter__"

[case testClassmethodMissingFromStubs]
class A:
@classmethod
def f(cls): pass
[out]
main:2: error: Name 'classmethod' is not defined
main:2: note: Maybe your test fixture does not define "builtins.classmethod"?
main:2: note: Consider adding [builtins fixtures/classmethod.pyi] to your test description

[case testPropertyMissingFromStubs]
class A:
@property
def f(self): pass
[out]
main:2: error: Name 'property' is not defined
main:2: note: Maybe your test fixture does not define "builtins.property"?
main:2: note: Consider adding [builtins fixtures/property.pyi] to your test description