org.sonar.l10n.py.rules.python.S5712.html Maven / Gradle / Ivy
This rule raises an issue when a special method raises a NotImplementedError
instead of returning NotImplemented
.
Why is this an issue?
In Python, special methods corresponding to numeric operators and rich comparison operators should return NotImplemented
when the
operation is not supported.
For example A + B
is equivalent to calling A.__add__(B)
. If this binary operation is not supported by class A,
A.__add__(B)
should return NotImplemented
. The interpreter will then try the reverse operation, i.e.
B.__radd__(A)
. If these special methods were to raise NotImplementedError
, the callers would not catch the exception and the
reverse operation would not be called.
Below is the list of special methods this rule applies to:
-
__lt__(self, other)
-
__le__(self, other)
-
__eq__(self, other)
-
__ne__(self, other)
-
__gt__(self, other)
-
__ge__(self, other)
-
__add__(self, other)
-
__sub__(self, other)
-
__mul__(self, other)
-
__matmul__(self, other)
-
__truediv__(self, other)
-
__floordiv__(self, other)
-
__mod__(self, other)
-
__divmod__(self, other)
-
__pow__(self, other[, modulo])
-
__lshift__(self, other)
-
__rshift__(self, other)
-
__and__(self, other)
-
__xor__(self, other)
-
__or__(self, other)
-
__radd__(self, other)
-
__rsub__(self, other)
-
__rmul__(self, other)
-
__rmatmul__(self, other)
-
__rtruediv__(self, other)
-
__rfloordiv__(self, other)
-
__rmod__(self, other)
-
__rdivmod__(self, other)
-
__rpow__(self, other[, modulo])
-
__rlshift__(self, other)
-
__rrshift__(self, other)
-
__rand__(self, other)
-
__rxor__(self, other)
-
__ror__(self, other)
-
__iadd__(self, other)
-
__isub__(self, other)
-
__imul__(self, other)
-
__imatmul__(self, other)
-
__itruediv__(self, other)
-
__ifloordiv__(self, other)
-
__imod__(self, other)
-
__ipow__(self, other[, modulo])
-
__ilshift__(self, other)
-
__irshift__(self, other)
-
__iand__(self, other)
-
__ixor__(self, other)
-
__ior__(self, other)
-
__length_hint__(self)
How to fix it
Make sure special methods return NotImplemented
instead of raising a NotImplementedError
.
Code examples
Noncompliant code example
class MyClass:
def __add__(self, other):
raise NotImplementedError() # Noncompliant: the exception will be propagated
def __radd__(self, other):
raise NotImplementedError() # Noncompliant: the exception will be propagated
class MyOtherClass:
def __add__(self, other):
return 42
def __radd__(self, other):
return 42
MyClass() + MyOtherClass() # This will raise NotImplementedError
Compliant solution
class MyClass:
def __add__(self, other):
return NotImplemented
def __radd__(self, other):
return NotImplemented
class MyOtherClass:
def __add__(self, other):
return 42
def __radd__(self, other):
return 42
MyClass() + MyOtherClass() # This returns 42
Pitfalls
The __length_hint__
special method also requires to return a NotImplemented
. Its behavior differs from the other methods,
because when it returns NotImplemented
, a default value will be returned instead. See PEP
424 for more information.
Resources
Documentation
- Python documentation - Built-in Constants - NotImplemented
- Python documentation - Implementing the
arithmetic operations
Standards
- PEP 424 - A method exposing
__length_hint__