Skip to content

Fix unsupported-binary-operation on classes that overload or #6664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jun 23, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
94c5cfd
Fix ``unsupported-binary-operation`` on classes that overload or
timmartin May 22, 2022
1af0924
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 22, 2022
f8b0166
Handle the case where the overload is from Python 3.10 runtime
timmartin May 28, 2022
02e7360
Merge branch 'main' into issue-4951
timmartin May 29, 2022
3f7687e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 29, 2022
262ef22
Update tests/functional/a/alternative/alternative_union_syntax_error.py
timmartin Jun 1, 2022
e2ecb8f
Defend against assigning an anonymous function to __or__
timmartin Jun 1, 2022
2d82246
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 1, 2022
4512b70
Merge branch 'main' into issue-4951
timmartin Jun 1, 2022
f8877c3
Move the release note to 2.15
timmartin Jun 1, 2022
d20a35a
Cope with multiple attributes inferred on Python 3.10
timmartin Jun 2, 2022
410cb7e
Apply code review feedback
timmartin Jun 15, 2022
414353c
Add a test to illustrate the second-level metaclass issue
timmartin Jun 15, 2022
7dc9fc7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 15, 2022
efc75e7
Clean up the functional test and add an extra case
timmartin Jun 15, 2022
5d6a493
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 15, 2022
b46cd09
Fix some code review comments
timmartin Jun 22, 2022
433f850
Remove the second-level metaclass test case
timmartin Jun 22, 2022
8ec0215
Use consistent location for NotFoundError
timmartin Jun 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ Release date: TBA

Closes #2409

* Don't report ``unsupported-binary-operation`` on Python <= 3.9 when using the ``|`` operator
with types, if one has a metaclass that overloads ``__or__`` or ``__ror__`` as appropriate.

Closes #4951

* The ``config`` attribute of ``BaseChecker`` has been deprecated. You can use ``checker.linter.config``
to access the global configuration object instead of a checker-specific object.

Expand Down
5 changes: 5 additions & 0 deletions doc/whatsnew/2.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ Other Changes

Relates to #6612

* Don't report ``unsupported-binary-operation`` on Python <= 3.9 when using the ``|`` operator
with types, if one has a metaclass that overloads ``__or__`` or ``__ror__`` as appropriate.

Closes #4951

* Fix bug where it writes a plain text error message to stdout, invalidating output formats.

Closes #6597
Expand Down
33 changes: 27 additions & 6 deletions pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -1900,13 +1900,34 @@ def _detect_unsupported_alternative_union_syntax(self, node: nodes.BinOp) -> Non
self._check_unsupported_alternative_union_syntax(node)

def _check_unsupported_alternative_union_syntax(self, node: nodes.BinOp) -> None:
"""Check if left or right node is of type `type`."""
"""Check if left or right node is of type `type`.

If either is, and doesn't
support an or operator via a metaclass, infer that this is a mistaken
attempt to use alternative union syntax when not supported.
"""
msg = "unsupported operand type(s) for |"
for n in (node.left, node.right):
n = astroid.helpers.object_type(n)
if isinstance(n, nodes.ClassDef) and is_classdef_type(n):
self.add_message("unsupported-binary-operation", args=msg, node=node)
break
left_obj = astroid.helpers.object_type(node.left)
right_obj = astroid.helpers.object_type(node.right)
left_is_type = False
right_is_type = False

if isinstance(left_obj, nodes.ClassDef) and is_classdef_type(left_obj):
try:
left_obj.getattr("__or__")
return
except astroid.NotFoundError:
left_is_type = True

if isinstance(right_obj, nodes.ClassDef) and is_classdef_type(right_obj):
try:
right_obj.getattr("__ror__")
return
except astroid.NotFoundError:
right_is_type = True

if left_is_type or right_is_type:
self.add_message("unsupported-binary-operation", args=msg, node=node)

# TODO: This check was disabled (by adding the leading underscore)
# due to false positives several years ago - can we re-enable it?
Expand Down
23 changes: 23 additions & 0 deletions tests/functional/a/alternative/alternative_union_syntax_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,26 @@ class CustomDataClass3:
@dataclasses.dataclass
class CustomDataClass4:
my_var: int | str # [unsupported-binary-operation]

# Not an error if the metaclass implements __or__

class ForwardMetaclass(type):
def __or__(cls, other):
return True

class ReverseMetaclass(type):
def __ror__(cls, other):
return True

class WithForward(metaclass=ForwardMetaclass):
pass

class WithReverse(metaclass=ReverseMetaclass):
pass

class DefaultMetaclass:
pass

class_list = [WithForward | DefaultMetaclass]
class_list_reversed_invalid = [WithReverse | DefaultMetaclass] # [unsupported-binary-operation]
class_list_reversed_valid = [DefaultMetaclass | WithReverse]
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ unsupported-binary-operation:76:12:76:21:CustomDataClass:unsupported operand typ
unsupported-binary-operation:80:12:80:21:CustomDataClass2:unsupported operand type(s) for |:UNDEFINED
unsupported-binary-operation:84:12:84:21:CustomDataClass3:unsupported operand type(s) for |:UNDEFINED
unsupported-binary-operation:89:12:89:21:CustomDataClass4:unsupported operand type(s) for |:UNDEFINED
unsupported-binary-operation:111:31:111:61::unsupported operand type(s) for |:UNDEFINED