From 73b9e61bd6d4b734d84128a2016363ff9d1ffce4 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Sat, 20 Aug 2022 20:51:26 +0100 Subject: [PATCH 1/3] Use `--strict` for selfcheck --- misc/analyze_cache.py | 4 ++-- misc/incremental_checker.py | 4 +++- misc/upload-pypi.py | 2 ++ mypy/build.py | 2 ++ mypy/config_parser.py | 2 +- mypy/dmypy_server.py | 4 +++- mypy/fastparse.py | 13 ++++++++++--- mypy/ipc.py | 4 +++- mypy/literals.py | 6 +++--- mypy/metastore.py | 8 ++++++-- mypy/nodes.py | 6 ++++-- mypy/stubtest.py | 4 ++-- mypy/test/data.py | 4 +++- mypy/types.py | 12 ++++++------ mypy_self_check.ini | 19 +------------------ mypyc/analysis/dataflow.py | 2 +- mypyc/irbuild/constant_fold.py | 4 +++- 17 files changed, 55 insertions(+), 45 deletions(-) diff --git a/misc/analyze_cache.py b/misc/analyze_cache.py index e5ccc8456862..8b805d8da0bc 100644 --- a/misc/analyze_cache.py +++ b/misc/analyze_cache.py @@ -89,7 +89,7 @@ def compress(chunk: JsonDict) -> JsonDict: cache: dict[int, JsonDict] = {} counter = 0 - def helper(chunk: Any) -> Any: + def helper(chunk: JsonDict) -> JsonDict: nonlocal counter if not isinstance(chunk, dict): return chunk @@ -121,7 +121,7 @@ def helper(chunk: Any) -> Any: def decompress(chunk: JsonDict) -> JsonDict: cache: dict[int, JsonDict] = {} - def helper(chunk: Any) -> Any: + def helper(chunk: JsonDict) -> JsonDict: if not isinstance(chunk, dict): return chunk if ".id" in chunk: diff --git a/misc/incremental_checker.py b/misc/incremental_checker.py index 3f5393717ba6..3c1288e4eeb5 100755 --- a/misc/incremental_checker.py +++ b/misc/incremental_checker.py @@ -197,7 +197,9 @@ def stop_daemon() -> None: def load_cache(incremental_cache_path: str = CACHE_PATH) -> JsonDict: if os.path.exists(incremental_cache_path): with open(incremental_cache_path) as stream: - return json.load(stream) + cache = json.load(stream) + assert isinstance(cache, dict) + return cache else: return {} diff --git a/misc/upload-pypi.py b/misc/upload-pypi.py index 4d18b7d78ade..3c9b0b0736a6 100644 --- a/misc/upload-pypi.py +++ b/misc/upload-pypi.py @@ -32,12 +32,14 @@ def is_whl_or_tar(name: str) -> bool: def get_release_for_tag(tag: str) -> dict[str, Any]: with urlopen(f"{BASE}/{REPO}/releases/tags/{tag}") as f: data = json.load(f) + assert isinstance(data, dict) assert data["tag_name"] == tag return data def download_asset(asset: dict[str, Any], dst: Path) -> Path: name = asset["name"] + assert isinstance(name, str) download_url = asset["browser_download_url"] assert is_whl_or_tar(name) with urlopen(download_url) as src_file: diff --git a/mypy/build.py b/mypy/build.py index c409b90d0b73..def8ef8da9f9 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -1124,6 +1124,7 @@ def read_deps_cache(manager: BuildManager, graph: Graph) -> dict[str, FgDepMeta] return None module_deps_metas = deps_meta["deps_meta"] + assert isinstance(module_deps_metas, dict) if not manager.options.skip_cache_mtime_checks: for id, meta in module_deps_metas.items(): try: @@ -1168,6 +1169,7 @@ def _load_json_file( ) return None else: + assert isinstance(result, dict) return result diff --git a/mypy/config_parser.py b/mypy/config_parser.py index 55cc0fea3720..281edceab56a 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -132,7 +132,7 @@ def check_follow_imports(choice: str) -> str: # types. ini_config_types: Final[dict[str, _INI_PARSER_CALLABLE]] = { "python_version": parse_version, - "strict_optional_whitelist": lambda s: s.split(), + "strict_optional_whitelist": str.split, "custom_typing_module": str, "custom_typeshed_dir": expand_path, "mypy_path": lambda s: [expand_path(p.strip()) for p in re.split("[,:]", s)], diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index 4b12bcbe9a29..36cfa4acc8c3 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -267,7 +267,9 @@ def run_command(self, command: str, data: dict[str, object]) -> dict[str, object # Only the above commands use some error formatting. del data["is_tty"] del data["terminal_width"] - return method(self, **data) + ret = method(self, **data) + assert isinstance(ret, dict) + return ret # Command functions (run in the server via RPC). diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 2f749af6a467..2199d01fa7d3 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -303,6 +303,7 @@ def parse( if raise_on_error and errors.is_errors(): errors.raise_error() + assert isinstance(tree, MypyFile) return tree @@ -1630,7 +1631,9 @@ def visit_ExtSlice(self, n: ast3.ExtSlice) -> TupleExpr: # Index(expr value) def visit_Index(self, n: Index) -> Node: # cast for mypyc's benefit on Python 3.9 - return self.visit(cast(Any, n).value) + value = self.visit(cast(Any, n).value) + assert isinstance(value, Node) + return value # Match(expr subject, match_case* cases) # python 3.10 and later def visit_Match(self, n: Match) -> MatchStmt: @@ -1760,7 +1763,9 @@ def visit(self, node: AST | None) -> ProperType | None: method = "visit_" + node.__class__.__name__ visitor = getattr(self, method, None) if visitor is not None: - return visitor(node) + typ = visitor(node) + assert isinstance(typ, ProperType) + return typ else: return self.invalid_type(node) finally: @@ -1947,7 +1952,9 @@ def visit_Bytes(self, n: Bytes) -> Type: def visit_Index(self, n: ast3.Index) -> Type: # cast for mypyc's benefit on Python 3.9 - return self.visit(cast(Any, n).value) + value = self.visit(cast(Any, n).value) + assert isinstance(value, Type) + return value def visit_Slice(self, n: ast3.Slice) -> Type: return self.invalid_type(n, note="did you mean to use ',' instead of ':' ?") diff --git a/mypy/ipc.py b/mypy/ipc.py index 8e693169ab36..db775935ac7a 100644 --- a/mypy/ipc.py +++ b/mypy/ipc.py @@ -270,4 +270,6 @@ def connection_name(self) -> str: if sys.platform == "win32": return self.name else: - return self.sock.getsockname() + name = self.sock.getsockname() + assert isinstance(name, str) + return name diff --git a/mypy/literals.py b/mypy/literals.py index 43425755aae8..2e28eeb7314c 100644 --- a/mypy/literals.py +++ b/mypy/literals.py @@ -173,7 +173,7 @@ def visit_op_expr(self, e: OpExpr) -> Key: return ("Binary", e.op, literal_hash(e.left), literal_hash(e.right)) def visit_comparison_expr(self, e: ComparisonExpr) -> Key: - rest: Any = tuple(e.operators) + rest: tuple[Any, ...] = tuple(e.operators) rest += tuple(literal_hash(o) for o in e.operands) return ("Comparison",) + rest @@ -182,7 +182,7 @@ def visit_unary_expr(self, e: UnaryExpr) -> Key: def seq_expr(self, e: ListExpr | TupleExpr | SetExpr, name: str) -> Key | None: if all(literal(x) == LITERAL_YES for x in e.items): - rest: Any = tuple(literal_hash(x) for x in e.items) + rest: tuple[Any, ...] = tuple(literal_hash(x) for x in e.items) return (name,) + rest return None @@ -191,7 +191,7 @@ def visit_list_expr(self, e: ListExpr) -> Key | None: def visit_dict_expr(self, e: DictExpr) -> Key | None: if all(a and literal(a) == literal(b) == LITERAL_YES for a, b in e.items): - rest: Any = tuple( + rest: tuple[Any, ...] = tuple( (literal_hash(a) if a else None, literal_hash(b)) for a, b in e.items ) return ("Dict",) + rest diff --git a/mypy/metastore.py b/mypy/metastore.py index 8a8a3088ca76..16cbd5adc9c8 100644 --- a/mypy/metastore.py +++ b/mypy/metastore.py @@ -185,10 +185,14 @@ def _query(self, name: str, field: str) -> Any: return results[0][0] def getmtime(self, name: str) -> float: - return self._query(name, "mtime") + mtime = self._query(name, "mtime") + assert isinstance(mtime, float) + return mtime def read(self, name: str) -> str: - return self._query(name, "data") + data = self._query(name, "data") + assert isinstance(data, str) + return data def write(self, name: str, data: str, mtime: float | None = None) -> bool: import sqlite3 diff --git a/mypy/nodes.py b/mypy/nodes.py index 765feb171b9b..3ee7bd6cdad4 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -3146,10 +3146,12 @@ class FakeInfo(TypeInfo): def __init__(self, msg: str) -> None: self.msg = msg - def __getattribute__(self, attr: str) -> None: + def __getattribute__(self, attr: str) -> type: # Handle __class__ so that isinstance still works... if attr == "__class__": - return object.__getattribute__(self, attr) + klass = object.__getattribute__(self, attr) + assert isinstance(klass, type) + return klass raise AssertionError(object.__getattribute__(self, "msg")) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 378f61471437..0f533fd0016f 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -315,7 +315,7 @@ def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool: except Exception: return False if obj_mod is not None: - return obj_mod == r.__name__ + return bool(obj_mod == r.__name__) return not isinstance(obj, types.ModuleType) runtime_public_contents = ( @@ -569,7 +569,7 @@ def get_type(arg: Any) -> str | None: def has_default(arg: Any) -> bool: if isinstance(arg, inspect.Parameter): - return arg.default != inspect.Parameter.empty + return bool(arg.default != inspect.Parameter.empty) if isinstance(arg, nodes.Argument): return arg.kind.is_optional() raise AssertionError diff --git a/mypy/test/data.py b/mypy/test/data.py index e08b95fedbde..6a2b5558afeb 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -680,7 +680,9 @@ class DataFileCollector(pytest.Collector): def from_parent( # type: ignore[override] cls, parent: DataSuiteCollector, *, name: str ) -> DataFileCollector: - return super().from_parent(parent, name=name) + collector = super().from_parent(parent, name=name) + assert isinstance(collector, DataFileCollector) + return collector def collect(self) -> Iterator[DataDrivenTestCase]: yield from split_test_cases( diff --git a/mypy/types.py b/mypy/types.py index cfb6c62de147..b7e58243caca 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -868,7 +868,7 @@ def __init__( def accept(self, visitor: TypeVisitor[T]) -> T: assert isinstance(visitor, SyntheticTypeVisitor) - return visitor.visit_callable_argument(self) + return cast(T, visitor.visit_callable_argument(self)) def serialize(self) -> JsonDict: assert False, "Synthetic types don't serialize" @@ -893,7 +893,7 @@ def __init__(self, items: list[Type], line: int = -1, column: int = -1) -> None: def accept(self, visitor: TypeVisitor[T]) -> T: assert isinstance(visitor, SyntheticTypeVisitor) - return visitor.visit_type_list(self) + return cast(T, visitor.visit_type_list(self)) def serialize(self) -> JsonDict: assert False, "Synthetic types don't serialize" @@ -2322,7 +2322,7 @@ def simple_name(self) -> str: def accept(self, visitor: TypeVisitor[T]) -> T: assert isinstance(visitor, SyntheticTypeVisitor) - return visitor.visit_raw_expression_type(self) + return cast(T, visitor.visit_raw_expression_type(self)) def serialize(self) -> JsonDict: assert False, "Synthetic types don't serialize" @@ -2445,7 +2445,7 @@ def __init__(self, type: Type, line: int = -1, column: int = -1) -> None: def accept(self, visitor: TypeVisitor[T]) -> T: assert isinstance(visitor, SyntheticTypeVisitor) - return visitor.visit_star_type(self) + return cast(T, visitor.visit_star_type(self)) def serialize(self) -> JsonDict: assert False, "Synthetic types don't serialize" @@ -2587,7 +2587,7 @@ class EllipsisType(ProperType): def accept(self, visitor: TypeVisitor[T]) -> T: assert isinstance(visitor, SyntheticTypeVisitor) - return visitor.visit_ellipsis_type(self) + return cast(T, visitor.visit_ellipsis_type(self)) def serialize(self) -> JsonDict: assert False, "Synthetic types don't serialize" @@ -2696,7 +2696,7 @@ def __init__(self, fullname: str | None, args: list[Type], line: int) -> None: def accept(self, visitor: TypeVisitor[T]) -> T: assert isinstance(visitor, SyntheticTypeVisitor) - return visitor.visit_placeholder_type(self) + return cast(T, visitor.visit_placeholder_type(self)) def serialize(self) -> str: # We should never get here since all placeholders should be replaced diff --git a/mypy_self_check.ini b/mypy_self_check.ini index 5dc497528fab..1e07a5332e59 100644 --- a/mypy_self_check.ini +++ b/mypy_self_check.ini @@ -1,23 +1,6 @@ [mypy] -warn_unused_configs = True -disallow_any_generics = True -disallow_subclassing_any = True -disallow_untyped_calls = True -disallow_untyped_defs = True -disallow_incomplete_defs = True -check_untyped_defs = True -disallow_untyped_decorators = True -no_implicit_optional = True -warn_redundant_casts = True -warn_unused_ignores = True -no_implicit_reexport = True -strict_equality = True -strict_concatenate = True - -; This is the only setting in --strict that we don't have enabled -warn_return_any = False - +strict = True warn_no_return = True strict_optional = True disallow_any_unimported = True diff --git a/mypyc/analysis/dataflow.py b/mypyc/analysis/dataflow.py index 824d64a1bf4b..21c4da8981d1 100644 --- a/mypyc/analysis/dataflow.py +++ b/mypyc/analysis/dataflow.py @@ -68,7 +68,7 @@ def __init__( def __str__(self) -> str: lines = [] - lines.append("exits: %s" % sorted(self.exits, key=lambda e: e.label)) + lines.append("exits: %s" % sorted(self.exits, key=lambda e: int(e.label))) lines.append("succ: %s" % self.succ) lines.append("pred: %s" % self.pred) return "\n".join(lines) diff --git a/mypyc/irbuild/constant_fold.py b/mypyc/irbuild/constant_fold.py index 08cf75d9e5ca..8d0a7fea5d90 100644 --- a/mypyc/irbuild/constant_fold.py +++ b/mypyc/irbuild/constant_fold.py @@ -80,7 +80,9 @@ def constant_fold_binary_int_op(op: str, left: int, right: int) -> int | None: return left >> right elif op == "**": if right >= 0: - return left**right + ret = left**right + assert isinstance(ret, int) + return ret return None From 7910728cd47c8b778939204b6010f055ea2fddaa Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Sun, 21 Aug 2022 11:28:05 +0100 Subject: [PATCH 2/3] Address review --- mypy/literals.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mypy/literals.py b/mypy/literals.py index 2e28eeb7314c..9d91cf728b06 100644 --- a/mypy/literals.py +++ b/mypy/literals.py @@ -173,7 +173,7 @@ def visit_op_expr(self, e: OpExpr) -> Key: return ("Binary", e.op, literal_hash(e.left), literal_hash(e.right)) def visit_comparison_expr(self, e: ComparisonExpr) -> Key: - rest: tuple[Any, ...] = tuple(e.operators) + rest: tuple[str | Key | None, ...] = tuple(e.operators) rest += tuple(literal_hash(o) for o in e.operands) return ("Comparison",) + rest @@ -182,7 +182,7 @@ def visit_unary_expr(self, e: UnaryExpr) -> Key: def seq_expr(self, e: ListExpr | TupleExpr | SetExpr, name: str) -> Key | None: if all(literal(x) == LITERAL_YES for x in e.items): - rest: tuple[Any, ...] = tuple(literal_hash(x) for x in e.items) + rest: tuple[Key | None, ...] = tuple(literal_hash(x) for x in e.items) return (name,) + rest return None @@ -191,7 +191,7 @@ def visit_list_expr(self, e: ListExpr) -> Key | None: def visit_dict_expr(self, e: DictExpr) -> Key | None: if all(a and literal(a) == literal(b) == LITERAL_YES for a, b in e.items): - rest: tuple[Any, ...] = tuple( + rest: tuple[Key | None, ...] = tuple( (literal_hash(a) if a else None, literal_hash(b)) for a, b in e.items ) return ("Dict",) + rest From 136394686c77839832a3fe2b805049315e7e9510 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Sun, 21 Aug 2022 11:31:54 +0100 Subject: [PATCH 3/3] Tweak `FakeInfo.__getattribute__` --- mypy/nodes.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mypy/nodes.py b/mypy/nodes.py index 3ee7bd6cdad4..764dc8898ef5 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -3149,9 +3149,7 @@ def __init__(self, msg: str) -> None: def __getattribute__(self, attr: str) -> type: # Handle __class__ so that isinstance still works... if attr == "__class__": - klass = object.__getattribute__(self, attr) - assert isinstance(klass, type) - return klass + return object.__getattribute__(self, attr) # type: ignore[no-any-return] raise AssertionError(object.__getattribute__(self, "msg"))