rspec/rules/S935/python/rule.adoc
Anton Haubner 714ee0bb94
Merge S6658 into S935 (#2761)
This merges S6658 into S935, see also this discussion on slack:
https://sonarsource.slack.com/archives/CFUS31LRE/p1690534750237959

This is the previous PR for merging S6658 which this PR is based on:
https://github.com/SonarSource/rspec/pull/2450

---------

Original S6658 rule authored-by: Maksim Grebeniuk <maksim.grebeniuk@sonarsource.com>
2023-08-02 16:55:20 +02:00

92 lines
3.2 KiB
Plaintext

This rule raises an issue when a special method returns an object of an unexpected type.
== Why is this an issue?
Python allows developers to customize how code is interpreted by defining special methods (also called magic methods). For example, it is possible to define the objects own truthiness or falsiness by iverriding ``++__bool__++`` method. It is invoked when the built-in ``++bool()++`` function is called on an object. The ``++bool()++`` function returns ``++True++`` or ``++False++`` based on the truth value of the object.
The Python interpreter will call these methods when performing the operation they're associated with. Each special method expects a specific return type. Calls to a special method will throw a ``++TypeError++`` if its return type is incorrect.
An issue will be raised when one of the following methods doesn't return the indicated type:
* ``++__bool__++`` method should return bool
* ``++__index__++`` method should return integer
* ``++__repr__++`` method should return string
* ``++__str__++`` method should return string
* ``++__bytes__++`` method should return bytes
* ``++__hash__++`` method should return integer
* ``++__format__++`` method should return string
* ``++__getnewargs__++`` method should return tuple
* ``++__getnewargs_ex__++`` method should return something which is of the form tuple(tuple, dict)
== How to fix it
Make sure to return a value of the same type as defined in the Python documentation for each special method.
=== Code examples
==== Noncompliant code example
[source,python,diff-id=1,diff-type=noncompliant]
----
class MyClass:
def __bool__(self):
return 0 # Noncompliant: Return value of type bool here.
obj1 = MyClass()
print(bool(obj1)) # TypeError: __bool__ should return bool, returned int
----
==== Compliant solution
[source,python,diff-id=1,diff-type=compliant]
----
class MyClass:
def __bool__(self):
return False
obj1 = MyClass()
print(bool(obj1))
----
== Resources
=== Documentation
* Python Data Model Documentation - https://docs.python.org/3/reference/datamodel.html#special-method-names[Special method names]
* Python Object Serialization Documentation - https://docs.python.org/3/library/pickle.html#pickling-class-instances[Pickling Class Instances]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
==== if there is a return statement
* Return a value of type XXX here.
* Return a value of type XXX here. A tuple of two elements was expected but found tuple with YYY element(s).
==== if there is no return statement
* Return a value of type XXX in this method. Consider explicitly raising a `TypeError` if this class is not meant to support this method.
* Return a value of type XXX in this method. The method can not be a coroutine and have the `async` keyword.
* Return a value of type XXX in this method. The method can not be a generator and contain `yield` expressions.
=== Highlighting
==== if there is return statement
Primary: the returned expressions, or the return keyword if no expressions are returned
Secondary: method name
==== if there is no return statement at all
Primary: method name
'''
== Comments And Links
(visible only on this page)
endif::env-github,rspecator-view[]