diff options
author | Marc Mueller <30130371+cdce8p@users.noreply.github.com> | 2021-03-27 00:15:40 +0100 |
---|---|---|
committer | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2021-03-28 22:48:56 +0200 |
commit | 454b3defc39a90a60ddc81dd1cf40b4360b0028f (patch) | |
tree | 0940b48697e4e8c877c762a796965e83b0ac3a68 | |
parent | b6764a41c1f5d76c4cdea6008ef4456c78ebd8bc (diff) | |
download | pylint-git-454b3defc39a90a60ddc81dd1cf40b4360b0028f.tar.gz |
Refactor and cleanup of PEP 604 check
-rw-r--r-- | pylint/checkers/typecheck.py | 81 |
1 files changed, 47 insertions, 34 deletions
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 6d73c34ec..1724ed705 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -101,6 +101,11 @@ BUILTINS = builtins.__name__ STR_FORMAT = {"%s.str.format" % BUILTINS} ASYNCIO_COROUTINE = "asyncio.coroutines.coroutine" BUILTIN_TUPLE = "builtins.tuple" +TYPE_ANNOTATION_NODES_TYPES = ( + astroid.AnnAssign, + astroid.Arguments, + astroid.FunctionDef, +) def _unflatten(iterable): @@ -1652,50 +1657,58 @@ accessed. Python regular expressions are accepted.", @check_messages("unsupported-binary-operation") def visit_binop(self, node: astroid.BinOp): - # Test alternative Union syntax PEP 604 - int | None - msg = "unsupported operand type(s) for |" - if node.op == "|" and ( - not is_postponed_evaluation_enabled(node) - and isinstance( - node.parent, (astroid.AnnAssign, astroid.Arguments, astroid.FunctionDef) - ) - or not PY310_PLUS - and isinstance( - node.parent, - ( - astroid.Assign, - astroid.Call, - astroid.Keyword, - astroid.Dict, - astroid.Tuple, - astroid.Set, - astroid.List, - astroid.BinOp, - ), - ) + if node.op == "|": + self._detect_unsupported_alternative_union_syntax(node) + + def _detect_unsupported_alternative_union_syntax(self, node: astroid.BinOp) -> None: + """Detect if unsupported alternative Union syntax (PEP 604) was used.""" + if PY310_PLUS: # 310+ supports the new syntax + return + + if isinstance( + node.parent, TYPE_ANNOTATION_NODES_TYPES + ) and not is_postponed_evaluation_enabled(node): + # Use in type annotations only allowed if + # postponed evaluation is enabled. + self._check_unsupported_alternative_union_syntax(node) + + if isinstance( + node.parent, + ( + astroid.Assign, + astroid.Call, + astroid.Keyword, + astroid.Dict, + astroid.Tuple, + astroid.Set, + astroid.List, + astroid.BinOp, + ), ): + # Check other contexts the syntax might appear, but are invalid. + # Make sure to filter context if postponed evaluation is enabled + # and parent is allowed node type. allowed_nested_syntax = False if is_postponed_evaluation_enabled(node): parent_node = node.parent while True: - if isinstance( - parent_node, - (astroid.AnnAssign, astroid.Arguments, astroid.FunctionDef), - ): + if isinstance(parent_node, TYPE_ANNOTATION_NODES_TYPES): allowed_nested_syntax = True break parent_node = parent_node.parent if isinstance(parent_node, astroid.Module): break - if allowed_nested_syntax is False: - for n in (node.left, node.right): - n = helpers.object_type(n) - if isinstance(n, astroid.ClassDef): - if is_classdef_type(n): - self.add_message( - "unsupported-binary-operation", args=msg, node=node - ) - break + if not allowed_nested_syntax: + self._check_unsupported_alternative_union_syntax(node) + + def _check_unsupported_alternative_union_syntax(self, node: astroid.BinOp) -> None: + """Check if left or right node is of type `type`.""" + msg = msg = "unsupported operand type(s) for |" + for n in (node.left, node.right): + n = helpers.object_type(n) + if isinstance(n, astroid.ClassDef) and is_classdef_type(n): + self.add_message("unsupported-binary-operation", args=msg, node=node) + break @check_messages("unsupported-binary-operation") def _visit_binop(self, node): |