rspec/rules/S5607/python/rule.adoc

90 lines
2.6 KiB
Plaintext
Raw Normal View History

2023-07-03 16:40:19 +02:00
This rule raises an issue when an operator is used on incompatible types.
2023-07-03 16:40:19 +02:00
== Why is this an issue?
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
:link-with-uscores1: https://docs.python.org/3/reference/datamodel.html?#emulating-numeric-types
:link-with-uscores2: https://docs.python.org/3/reference/datamodel.html?#object.__lt__
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
For a specific operator, two types are considered incompatible if no built-in operations between those types exist and none of the operands has implemented the operator's corresponding special methods.
Performing such an operation on incompatible types will raise a `TypeError`.
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
Calling an operator in Python is equivalent to calling a special method (except for the identity operator `is`).
Python provides a set of built-in operations. For example, to add two integers: `1 + 2`, calling the built-in operator `+` is equivalent to calling the special method ``++__add__++`` on the type `int`.
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
Python allows developers to define how an operator will behave with a custom class by implementing the corresponding special method.
When defining such methods for symmetrical binary operators, developers need to define two methods so that the order of operands doesn't matter, ex: ``++__add__++`` and ``++__radd__++``.
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
For a complete list of operators and their methods see the Python documentation: {link-with-uscores1}[arithmetic and bitwise operators], {link-with-uscores2}[comparison operators].
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
== How to fix it
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
Implementing the special methods for a specific operator will fix the issue.
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
=== Code examples
2023-07-03 16:40:19 +02:00
==== Noncompliant code example
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,python]
2021-04-28 16:49:39 +02:00
----
class Empty:
pass
class Add:
def __add__(self, other):
return 42
2023-07-03 16:40:19 +02:00
Empty() + 1 # Noncompliant: no __add__ method is defined on the Empty class
2021-04-28 16:49:39 +02:00
Add() + 1
2023-07-03 16:40:19 +02:00
1 + Add() # Noncompliant: no __radd__ method is defined on the Add class
2021-04-28 16:49:39 +02:00
Add() + Empty()
2023-07-03 16:40:19 +02:00
Empty() + Add() # Noncompliant: no __radd__ method is defined on the Add class
2021-04-28 16:49:39 +02:00
----
2023-07-03 16:40:19 +02:00
==== Compliant solution
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,python]
2021-04-28 16:49:39 +02:00
----
class Empty:
pass
class Add:
def __add__(self, other):
return 42
def __radd__(self, other):
return 42
Add() + 1
1 + Add()
Add() + Empty()
Empty() + Add()
----
== Resources
2021-04-28 16:49:39 +02:00
2023-07-03 16:40:19 +02:00
=== Documentation
* {link-with-uscores2}[Rich comparison methods]
* {link-with-uscores1}[Emulating numeric types]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
* Fix this invalid XXX operation between incompatible types.
* Fix this invalid XXX operation on a type which doesn't support it.
=== Highlighting
Primary location: the operator
Secondary locations: the operand(s)
endif::env-github,rspecator-view[]