In Python, special methods corresponding to numeric operators, rich comparison operators and the ``++__length_hint__++`` method should return ``++NotImplemented++`` when the operation is not supported. These methods should not raise ``++NotImplementedError++`` as callers don't expect it and won't catch this exception.


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)++``. This enables adding new operations by changing only one class instead of two.


This rule raises an issue when one of the following methods raises ``++NotImplementedError++`` instead of returning ``++NotImplemented++``:

* ++__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)

== Noncompliant Code Example

----
class MyClass:
    def __add__(self, other):
        raise NotImplementedError()  # Noncompliant
    def __radd__(self, other):
        raise NotImplementedError()  # Noncompliant

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
----

== See

* Python documentation - https://docs.python.org/3/library/constants.html#NotImplemented[Built-in Constants - NotImplemented]
* Python documentation - https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations[Implementing the arithmetic operations]
