Skip to content

Commit 2326425

Browse files
committed
Merge branch 'master' into module-alias
* master: Improve test output when a test doesn't specify the correct fixture (python#3488) Speed up tests by simplifying the stub for typing (python#3486) Clean up test fixtures (python#3485) Add additional quick mode test cases (python#3480) Add --strict-optional on by default to roadmap (python#3478) Minor speed-up in warn-return-any (python#3481)
2 parents 325ae94 + 9b172e6 commit 2326425

20 files changed

+720
-93
lines changed

ROADMAP.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,5 @@ more accurate.
9292
mode.
9393

9494
- Start work on editor plugins and support for selected IDE features.
95+
96+
- Turn on `--strict-optional` by default.

mypy/checker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,8 +1874,8 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
18741874
if isinstance(typ, AnyType):
18751875
# (Unless you asked to be warned in that case, and the
18761876
# function is not declared to return Any)
1877-
if (not is_proper_subtype(AnyType(), return_type) and
1878-
self.options.warn_return_any):
1877+
if (self.options.warn_return_any and
1878+
not is_proper_subtype(AnyType(), return_type)):
18791879
self.warn(messages.RETURN_ANY.format(return_type), s)
18801880
return
18811881

mypy/checkexpr.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,13 @@ def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
154154
result = type_object_type(node, self.named_type)
155155
elif isinstance(node, MypyFile):
156156
# Reference to a module object.
157-
result = self.named_type('types.ModuleType')
157+
try:
158+
result = self.named_type('types.ModuleType')
159+
except KeyError:
160+
# In test cases might 'types' may not be available.
161+
# Fall back to a dummy 'object' type instead to
162+
# avoid a crash.
163+
result = self.named_type('builtins.object')
158164
elif isinstance(node, Decorator):
159165
result = self.analyze_var_ref(node.var, e)
160166
else:

mypy/semanal.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,21 @@
163163
'_make', '_replace', '_asdict', '_source',
164164
'__annotations__')
165165

166+
# Map from the full name of a missing definition to the test fixture (under
167+
# test-data/unit/fixtures/) that provides the definition. This is used for
168+
# generating better error messages when running mypy tests only.
169+
SUGGESTED_TEST_FIXTURES = {
170+
'typing.List': 'list.pyi',
171+
'typing.Dict': 'dict.pyi',
172+
'typing.Set': 'set.pyi',
173+
'builtins.bool': 'bool.pyi',
174+
'builtins.Exception': 'exception.pyi',
175+
'builtins.BaseException': 'exception.pyi',
176+
'builtins.isinstance': 'isinstancelist.pyi',
177+
'builtins.property': 'property.pyi',
178+
'builtins.classmethod': 'classmethod.pyi',
179+
}
180+
166181

167182
class SemanticAnalyzer(NodeVisitor):
168183
"""Semantically analyze parsed mypy files.
@@ -1373,20 +1388,31 @@ def process_import_over_existing_name(self,
13731388
def normalize_type_alias(self, node: SymbolTableNode,
13741389
ctx: Context) -> SymbolTableNode:
13751390
normalized = False
1376-
if node.fullname in type_aliases:
1391+
fullname = node.fullname
1392+
if fullname in type_aliases:
13771393
# Node refers to an aliased type such as typing.List; normalize.
1378-
node = self.lookup_qualified(type_aliases[node.fullname], ctx)
1394+
node = self.lookup_qualified(type_aliases[fullname], ctx)
1395+
if node is None:
1396+
self.add_fixture_note(fullname, ctx)
1397+
return None
13791398
normalized = True
1380-
if node.fullname in collections_type_aliases:
1399+
if fullname in collections_type_aliases:
13811400
# Similar, but for types from the collections module like typing.DefaultDict
13821401
self.add_module_symbol('collections', '__mypy_collections__', False, ctx)
1383-
node = self.lookup_qualified(collections_type_aliases[node.fullname], ctx)
1402+
node = self.lookup_qualified(collections_type_aliases[fullname], ctx)
13841403
normalized = True
13851404
if normalized:
13861405
node = SymbolTableNode(node.kind, node.node,
13871406
node.mod_id, node.type_override, normalized=True)
13881407
return node
13891408

1409+
def add_fixture_note(self, fullname: str, ctx: Context) -> None:
1410+
self.note('Maybe your test fixture does not define "{}"?'.format(fullname), ctx)
1411+
if fullname in SUGGESTED_TEST_FIXTURES:
1412+
self.note(
1413+
'Consider adding [builtins fixtures/{}] to your test description'.format(
1414+
SUGGESTED_TEST_FIXTURES[fullname]), ctx)
1415+
13901416
def correct_relative_import(self, node: Union[ImportFrom, ImportAll]) -> str:
13911417
if node.relative == 0:
13921418
return node.id
@@ -3396,6 +3422,12 @@ def name_not_defined(self, name: str, ctx: Context) -> None:
33963422
if extra:
33973423
message += ' {}'.format(extra)
33983424
self.fail(message, ctx)
3425+
if 'builtins.{}'.format(name) in SUGGESTED_TEST_FIXTURES:
3426+
# The user probably has a missing definition in a test fixture. Let's verify.
3427+
fullname = 'builtins.{}'.format(name)
3428+
if self.lookup_fully_qualified_or_none(fullname) is None:
3429+
# Yes. Generate a helpful note.
3430+
self.add_fixture_note(fullname, ctx)
33993431

34003432
def name_already_defined(self, name: str, ctx: Context) -> None:
34013433
self.fail("Name '{}' already defined".format(name), ctx)

mypy/test/data.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def parse_test_cases(
6868
elif p[i].id == 'outfile':
6969
output_files.append(file_entry)
7070
elif p[i].id in ('builtins', 'builtins_py2'):
71-
# Use a custom source file for the std module.
71+
# Use an alternative stub file for the builtins module.
7272
arg = p[i].arg
7373
assert arg is not None
7474
mpath = join(os.path.dirname(path), arg)
@@ -79,6 +79,13 @@ def parse_test_cases(
7979
fnam = '__builtin__.pyi'
8080
with open(mpath) as f:
8181
files.append((join(base_path, fnam), f.read()))
82+
elif p[i].id == 'typing':
83+
# Use an alternative stub file for the typing module.
84+
arg = p[i].arg
85+
assert arg is not None
86+
src_path = join(os.path.dirname(path), arg)
87+
with open(src_path) as f:
88+
files.append((join(base_path, 'typing.pyi'), f.read()))
8289
elif re.match(r'stale[0-9]*$', p[i].id):
8390
if p[i].id == 'stale':
8491
passnum = 1

mypy/test/testcheck.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
'check-underscores.test',
7676
'check-classvar.test',
7777
'check-enum.test',
78+
'check-incomplete-fixture.test',
7879
]
7980

8081

test-data/unit/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,12 @@ Where the stubs for builtins come from for a given test:
6161
- The builtins used by default in unit tests live in
6262
`test-data/unit/lib-stub`.
6363

64-
- Individual test cases can override the stubs by using `[builtins fixtures/foo.pyi]`;
65-
this targets files in `test-data/unit/fixtures`. Feel free to modify existing files
66-
there or create new ones as you deem fit.
64+
- Individual test cases can override the builtins stubs by using
65+
`[builtins fixtures/foo.pyi]`; this targets files in `test-data/unit/fixtures`.
66+
Feel free to modify existing files there or create new ones as you deem fit.
67+
68+
- Test cases can also use `[typing fixtures/typing-full.pyi]` to use a more
69+
complete stub for `typing` that contains the async types, among other things.
6770

6871
- Feel free to add additional stubs to that `fixtures` directory, but
6972
generally don't expand files in `lib-stub` without first discussing the

0 commit comments

Comments
 (0)