Skip to content

Commit

Permalink
selfcheck: Enable the redundant-expr error code (#13547)
Browse files Browse the repository at this point in the history
* selfcheck: Enable the `redundant-expr` error code

* Remove unnecessary `type: ignore`

* Revert changes to `mypy/build.py`, add a TODO

* Use a `cast` instead

* Use explicit annotation instead of `assert_type`

* Bump `types-typed-ast`, remove unneeded `type: ignore`
  • Loading branch information
AlexWaygood authored Aug 31, 2022
1 parent d9bdd6d commit 840a310
Show file tree
Hide file tree
Showing 14 changed files with 31 additions and 36 deletions.
2 changes: 1 addition & 1 deletion build-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-r mypy-requirements.txt
types-psutil
types-setuptools
types-typed-ast>=1.5.0,<1.6.0
types-typed-ast>=1.5.8,<1.6.0
10 changes: 7 additions & 3 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1292,11 +1292,15 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> CacheMeta | No
)

# Don't check for path match, that is dealt with in validate_meta().
#
# TODO: these `type: ignore`s wouldn't be necessary
# if the type annotations for CacheMeta were more accurate
# (all of these attributes can be `None`)
if (
m.id != id
or m.mtime is None
or m.size is None
or m.dependencies is None
or m.mtime is None # type: ignore[redundant-expr]
or m.size is None # type: ignore[redundant-expr]
or m.dependencies is None # type: ignore[redundant-expr]
or m.data_mtime is None
):
manager.log(f"Metadata abandoned for {id}: attributes are missing")
Expand Down
12 changes: 4 additions & 8 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None:
bound_type = bind_self(typ, self_type, is_classmethod=True)
# Check that __new__ (after binding cls) returns an instance
# type (or any).
if isinstance(fdef.info, TypeInfo) and fdef.info.is_metaclass():
if fdef.info.is_metaclass():
# This is a metaclass, so it must return a new unrelated type.
self.check_subtype(
bound_type.ret_type,
Expand Down Expand Up @@ -1901,7 +1901,7 @@ def check_override(
):
fail = True
op_method_wider_note = True
if isinstance(original, FunctionLike) and isinstance(override, FunctionLike):
if isinstance(override, FunctionLike):
if original_class_or_static and not override_class_or_static:
fail = True
elif isinstance(original, CallableType) and isinstance(override, CallableType):
Expand Down Expand Up @@ -2804,12 +2804,8 @@ def check_compatibility_all_supers(
# The type of "__slots__" and some other attributes usually doesn't need to
# be compatible with a base class. We'll still check the type of "__slots__"
# against "object" as an exception.
if (
isinstance(lvalue_node, Var)
and lvalue_node.allow_incompatible_override
and not (
lvalue_node.name == "__slots__" and base.fullname == "builtins.object"
)
if lvalue_node.allow_incompatible_override and not (
lvalue_node.name == "__slots__" and base.fullname == "builtins.object"
):
continue

Expand Down
2 changes: 1 addition & 1 deletion mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def analyze_instance_member_access(
# the first argument.
pass
else:
if isinstance(signature, FunctionLike) and name != "__call__":
if name != "__call__":
# TODO: use proper treatment of special methods on unions instead
# of this hack here and below (i.e. mx.self_type).
dispatched_type = meet.meet_types(mx.original_type, typ)
Expand Down
10 changes: 4 additions & 6 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ def _check_ifstmt_for_overloads(
if stmt.else_body is None:
return overload_name

if isinstance(stmt.else_body, Block) and len(stmt.else_body.body) == 1:
if len(stmt.else_body.body) == 1:
# For elif: else_body contains an IfStmt itself -> do a recursive check.
if (
isinstance(stmt.else_body.body[0], (Decorator, FuncDef, OverloadedFuncDef))
Expand Down Expand Up @@ -901,13 +901,11 @@ def do_func_def(
# PEP 484 disallows both type annotations and type comments
if n.returns or any(a.type_annotation is not None for a in args):
self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset)
translated_args = TypeConverter(
translated_args: list[Type] = TypeConverter(
self.errors, line=lineno, override_column=n.col_offset
).translate_expr_list(func_type_ast.argtypes)
arg_types = [
a if a is not None else AnyType(TypeOfAny.unannotated)
for a in translated_args
]
# Use a cast to work around `list` invariance
arg_types = cast(List[Optional[Type]], translated_args)
return_type = TypeConverter(self.errors, line=lineno).visit(func_type_ast.returns)

# add implicit self type
Expand Down
8 changes: 2 additions & 6 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2486,11 +2486,7 @@ def [T <: int] f(self, x: int, y: T) -> None
slash = True

# If we got a "special arg" (i.e: self, cls, etc...), prepend it to the arg list
if (
isinstance(tp.definition, FuncDef)
and tp.definition.name is not None
and hasattr(tp.definition, "arguments")
):
if isinstance(tp.definition, FuncDef) and hasattr(tp.definition, "arguments"):
definition_arg_names = [arg.variable.name for arg in tp.definition.arguments]
if (
len(definition_arg_names) > len(tp.arg_names)
Expand Down Expand Up @@ -2684,7 +2680,7 @@ def find_defining_module(modules: dict[str, MypyFile], typ: CallableType) -> Myp
if not typ.definition:
return None
fullname = typ.definition.fullname
if fullname is not None and "." in fullname:
if "." in fullname:
for i in range(fullname.count(".")):
module_name = fullname.rsplit(".", i + 1)[0]
try:
Expand Down
5 changes: 4 additions & 1 deletion mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3580,7 +3580,10 @@ def serialize(self, prefix: str, name: str) -> JsonDict:
if prefix is not None:
fullname = self.node.fullname
if (
fullname is not None
# See the comment above SymbolNode.fullname -- fullname can often be None,
# but for complex reasons it's annotated as being `Bogus[str]` instead of `str | None`,
# meaning mypy erroneously thinks the `fullname is not None` check here is redundant
fullname is not None # type: ignore[redundant-expr]
and "." in fullname
and fullname != prefix + "." + name
and not (isinstance(self.node, Var) and self.node.from_module_getattr)
Expand Down
2 changes: 1 addition & 1 deletion mypy/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ def visit_func_def(self, defn: FuncDef) -> None:
if cur_indent is None:
# Consume the line, but don't mark it as belonging to the function yet.
cur_line += 1
elif start_indent is not None and cur_indent > start_indent:
elif cur_indent > start_indent:
# A non-blank line that belongs to the function.
cur_line += 1
end_line = cur_line
Expand Down
2 changes: 1 addition & 1 deletion mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5892,7 +5892,7 @@ def in_checked_function(self) -> bool:
current_index = len(self.function_stack) - 1
while current_index >= 0:
current_func = self.function_stack[current_index]
if isinstance(current_func, FuncItem) and not isinstance(current_func, LambdaExpr):
if not isinstance(current_func, LambdaExpr):
return not current_func.is_dynamic()

# Special case, `lambda` inherits the "checked" state from its parent.
Expand Down
6 changes: 2 additions & 4 deletions mypy/stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ def visit_overloaded_func_def(self, o: OverloadedFuncDef) -> None:
self.visit_func_def(item.func, is_abstract=is_abstract, is_overload=is_overload)
if is_overload:
overload_chain = True
elif overload_chain and is_overload:
elif is_overload:
self.visit_func_def(item.func, is_abstract=is_abstract, is_overload=is_overload)
else:
# skip the overload implementation and clear the decorator we just processed
Expand Down Expand Up @@ -725,9 +725,7 @@ def visit_func_def(
retname = None # implicit Any
else:
retname = self.print_annotation(o.unanalyzed_type.ret_type)
elif isinstance(o, FuncDef) and (
o.abstract_status == IS_ABSTRACT or o.name in METHODS_WITH_RETURN_VALUE
):
elif o.abstract_status == IS_ABSTRACT or o.name in METHODS_WITH_RETURN_VALUE:
# Always assume abstract methods return Any unless explicitly annotated. Also
# some dunder methods should not have a None return type.
retname = None # implicit Any
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/testsemanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ class TypeInfoMap(Dict[str, TypeInfo]):
def __str__(self) -> str:
a: list[str] = ["TypeInfoMap("]
for x, y in sorted(self.items()):
if isinstance(x, str) and (
if (
not x.startswith("builtins.")
and not x.startswith("typing.")
and not x.startswith("abc.")
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/testtypegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def run_case(self, testcase: DataDrivenTestCase) -> None:
# Filter nodes that should be included in the output.
keys = []
for node in nodes:
if node.line is not None and node.line != -1 and map[node]:
if node.line != -1 and map[node]:
if ignore_node(node) or node in ignored:
continue
if re.match(mask, short_type(node)) or (
Expand Down
2 changes: 1 addition & 1 deletion mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1939,7 +1939,7 @@ def with_unpacked_kwargs(self) -> NormalizedCallableType:
if not self.unpack_kwargs:
return NormalizedCallableType(self.copy_modified())
last_type = get_proper_type(self.arg_types[-1])
assert isinstance(last_type, ProperType) and isinstance(last_type, TypedDictType)
assert isinstance(last_type, TypedDictType)
extra_kinds = [
ArgKind.ARG_NAMED if name in last_type.required_keys else ArgKind.ARG_NAMED_OPT
for name in last_type.items
Expand Down
2 changes: 1 addition & 1 deletion mypy_self_check.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ always_false = MYPYC
plugins = misc/proper_plugin.py
python_version = 3.7
exclude = mypy/typeshed/|mypyc/test-data/|mypyc/lib-rt/
enable_error_code = ignore-without-code
enable_error_code = ignore-without-code,redundant-expr

0 comments on commit 840a310

Please sign in to comment.