From e1db3033168a0987dc308483e77c775e85ba01f9 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 30 Sep 2016 11:20:22 -0700 Subject: [PATCH 1/4] Fix strict none errors in the test subpackage. This shows several different approaches to dealing with #2199 for p[i].arg. --- mypy/build.py | 2 +- mypy/test/data.py | 26 +++++++++++++++----------- mypy/test/testcheck.py | 11 ++++++----- mypy/types.py | 2 +- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/mypy/build.py b/mypy/build.py index 3f50a101bde3..12d5ae67f3d3 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -770,7 +770,7 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> Optional[Cache return m -def is_meta_fresh(meta: CacheMeta, id: str, path: str, manager: BuildManager) -> bool: +def is_meta_fresh(meta: Optional[CacheMeta], id: str, path: str, manager: BuildManager) -> bool: if meta is None: return False diff --git a/mypy/test/data.py b/mypy/test/data.py index 1f4d7d68ee56..7c711879b341 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -53,11 +53,11 @@ def parse_test_cases( while i < len(p) and p[i].id != 'case': if p[i].id == 'file': # Record an extra file needed for the test case. - files.append((os.path.join(base_path, p[i].arg), + files.append((os.path.join(base_path, p[i].arg or ''), '\n'.join(p[i].data))) elif p[i].id in ('builtins', 'builtins_py2'): # Use a custom source file for the std module. - mpath = os.path.join(os.path.dirname(path), p[i].arg) + mpath = os.path.join(os.path.dirname(path), p[i].arg or '') if p[i].id == 'builtins': fnam = 'builtins.pyi' else: @@ -66,15 +66,17 @@ def parse_test_cases( with open(mpath) as f: files.append((os.path.join(base_path, fnam), f.read())) elif p[i].id == 'stale': - if p[i].arg is None: + arg = p[i].arg + if arg is None: stale_modules = set() else: - stale_modules = {item.strip() for item in p[i].arg.split(',')} + stale_modules = {item.strip() for item in arg.split(',')} elif p[i].id == 'rechecked': - if p[i].arg is None: + arg = p[i].arg + if arg is None: rechecked_modules = set() else: - rechecked_modules = {item.strip() for item in p[i].arg.split(',')} + rechecked_modules = {item.strip() for item in arg.split(',')} elif p[i].id == 'out' or p[i].id == 'out1': tcout = p[i].data if native_sep and os.path.sep == '\\': @@ -95,7 +97,9 @@ def parse_test_cases( # If the set of rechecked modules isn't specified, make it the same as the set of # modules with a stale public interface. rechecked_modules = stale_modules - if stale_modules is not None and not stale_modules.issubset(rechecked_modules): + if (stale_modules is not None + and rechecked_modules is not None + and not stale_modules.issubset(rechecked_modules)): raise ValueError( 'Stale modules must be a subset of rechecked modules ({})'.format(path)) @@ -225,7 +229,7 @@ class TestItem: """ id = '' - arg = '' + arg = '' # type: Optional[str] # Text data, array of 8-bit strings data = None # type: List[str] @@ -233,7 +237,7 @@ class TestItem: file = '' line = 0 # Line number in file - def __init__(self, id: str, arg: str, data: List[str], file: str, + def __init__(self, id: str, arg: Optional[str], data: List[str], file: str, line: int) -> None: self.id = id self.arg = arg @@ -248,8 +252,8 @@ def parse_test_data(l: List[str], fnam: str) -> List[TestItem]: ret = [] # type: List[TestItem] data = [] # type: List[str] - id = None # type: str - arg = None # type: str + id = None # type: Optional[str] + arg = None # type: Optional[str] i = 0 i0 = 0 diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index aaea713fa01c..aa5668f25098 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -8,7 +8,7 @@ import typed_ast import typed_ast.ast35 -from typing import Tuple, List, Dict, Set +from typing import Dict, List, Optional, Set, Tuple from mypy import build, defaults from mypy.main import parse_version, process_options @@ -149,15 +149,15 @@ def run_case_once(self, testcase: DataDrivenTestCase, incremental=0) -> None: sources = [] for module_name, program_path, program_text in module_data: # Always set to none so we're forced to reread the module in incremental mode - program_text = None if incremental else program_text - sources.append(BuildSource(program_path, module_name, program_text)) + sources.append(BuildSource(program_path, module_name, + None if incremental else program_text)) + res = None try: res = build.build(sources=sources, options=options, alt_lib_path=test_temp_dir) a = res.errors except CompileError as e: - res = None a = e.messages a = normalize_error_messages(a) @@ -191,7 +191,8 @@ def run_case_once(self, testcase: DataDrivenTestCase, incremental=0) -> None: testcase.expected_stale_modules, res.manager.stale_modules) - def check_module_equivalence(self, name: str, expected: Set[str], actual: Set[str]) -> None: + def check_module_equivalence(self, name: str, + expected: Optional[Set[str]], actual: Set[str]) -> None: if expected is not None: assert_string_arrays_equal( list(sorted(expected)), diff --git a/mypy/types.py b/mypy/types.py index b97937526ae4..09e473d213f4 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -560,7 +560,7 @@ class CallableType(FunctionLike): def __init__(self, arg_types: List[Type], arg_kinds: List[int], - arg_names: List[str], + arg_names: List[Optional[str]], ret_type: Type, fallback: Instance, name: str = None, From ce651707d0cc2adea953a716d5e0d416513ccf8f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 1 Oct 2016 17:03:38 -0700 Subject: [PATCH 2/4] Rewrite some more p[i].arg usages to be safe --- mypy/test/data.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mypy/test/data.py b/mypy/test/data.py index 7c711879b341..405d19b604d5 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -53,11 +53,15 @@ def parse_test_cases( while i < len(p) and p[i].id != 'case': if p[i].id == 'file': # Record an extra file needed for the test case. - files.append((os.path.join(base_path, p[i].arg or ''), + arg = p[i].arg + assert arg is not None + files.append((os.path.join(base_path, arg), '\n'.join(p[i].data))) elif p[i].id in ('builtins', 'builtins_py2'): # Use a custom source file for the std module. - mpath = os.path.join(os.path.dirname(path), p[i].arg or '') + arg = p[i].arg + assert arg is not None + mpath = os.path.join(os.path.dirname(path), p[i].arg) if p[i].id == 'builtins': fnam = 'builtins.pyi' else: From 96350b5eacea90c0add1c76254e562ffe6401154 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 1 Oct 2016 17:26:57 -0700 Subject: [PATCH 3/4] Fix oopsie --- mypy/test/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/test/data.py b/mypy/test/data.py index 405d19b604d5..4d34b9dc32e4 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -61,7 +61,7 @@ def parse_test_cases( # Use a custom source file for the std module. arg = p[i].arg assert arg is not None - mpath = os.path.join(os.path.dirname(path), p[i].arg) + mpath = os.path.join(os.path.dirname(path), arg) if p[i].id == 'builtins': fnam = 'builtins.pyi' else: From 11c3c98dd0d5ffccac596cdb73dbe7398fdb6cb1 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 1 Oct 2016 17:27:55 -0700 Subject: [PATCH 4/4] Run mypy over itself in --strict-optional mode. Add mypy.ini to suppress most errors (for now). --- mypy.ini | 5 +++++ runtests.py | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 000000000000..8776f1f391a6 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,5 @@ +[mypy] +show_none_errors = False + +[mypy-mypy/test/*] +show_none_errors = True diff --git a/runtests.py b/runtests.py index 8abc636a0206..9ca8c0d2413e 100755 --- a/runtests.py +++ b/runtests.py @@ -88,8 +88,8 @@ def add_mypy_modules(self, name: str, modules: Iterable[str], args = list(itertools.chain(*(['-m', mod] for mod in modules))) self.add_mypy_cmd(name, args, cwd=cwd) - def add_mypy_package(self, name: str, packagename: str) -> None: - self.add_mypy_cmd(name, ['-p', packagename]) + def add_mypy_package(self, name: str, packagename: str, *flags: str) -> None: + self.add_mypy_cmd(name, ['-p', packagename] + list(flags)) def add_mypy_string(self, name: str, *args: str, cwd: Optional[str] = None) -> None: self.add_mypy_cmd(name, ['-c'] + list(args), cwd=cwd) @@ -168,6 +168,7 @@ def add_basic(driver: Driver) -> None: def add_selftypecheck(driver: Driver) -> None: driver.add_mypy_package('package mypy', 'mypy') + driver.add_mypy_package('package mypy', 'mypy', '--strict-optional') def find_files(base: str, prefix: str = '', suffix: str = '') -> List[str]: