github-actions[bot] c70acb68e9
Create rule S6792: Generic classes should be defined using the type parameter syntax (#3197)
You can preview this rule
[here](https://sonarsource.github.io/rspec/#/rspec/S6792/python)
(updated a few minutes after each push).

## Review

A dedicated reviewer checked the rule description successfully for:

- [ ] logical errors and incorrect information
- [ ] information gaps and missing content
- [ ] text style and tone
- [ ] PR summary and labels follow [the
guidelines](https://github.com/SonarSource/rspec/#to-modify-an-existing-rule)

---------

Co-authored-by: guillaume-dequenne-sonarsource <guillaume-dequenne-sonarsource@users.noreply.github.com>
Co-authored-by: Guillaume Dequenne <guillaume.dequenne@sonarsource.com>
2023-11-01 11:42:29 +01:00

84 lines
2.5 KiB
Plaintext

This rule raises an issue when a generic class is defined through explicit inheritance of `typing.Generic` instead of using the type parameter syntax.
== Why is this an issue?
Through https://peps.python.org/pep-0695/[PEP 695], Python 3.12 introduces the type parameter syntax to allow for a more compact and explicit way to define generic classes and functions.
Prior to Python 3.12, defining a generic class would be done through the following syntax:
[source,python]
----
from typing import Generic, TypeVar
_T_co = TypeVar("_T_co", covariant=True, bound=str)
class ClassA(Generic[_T_co]):
def method1(self) -> _T_co:
...
----
Since Python 3.12, it can be done with the following syntax:
[source,python]
----
class ClassA[T: str]:
def method1(self) -> T:
...
----
Using the former syntax requires importing `TypeVar` and `Generic` symbols from the `typing` module. It also requires the explicit definition of a type variable in the global scope, with a redundant name provided in quotes (`T = TypeVar("T")`). This makes the definition of generic classes verbose and confusing.
It is therefore recommended to use the type parameter syntax when working with Python 3.12 and later.
=== Exceptions
This rule will only raise an issue when the Python version of the analyzed project is set to 3.12 or higher.
== How to fix it
To fix this issue, make sure to use the type parameter syntax whenever defining a generic class.
=== Code examples
==== Noncompliant code example
[source,python,diff-id=1,diff-type=noncompliant]
----
from typing import Generic, TypeVar
_T_co = TypeVar("_T_co", covariant=True, bound=str)
class ClassA(Generic[_T_co]): # Noncompliant: Explicit definition of a TypeVar and inheritance from typing.Generic is verbose
def method1(self) -> _T_co:
...
----
==== Compliant solution
[source,python,diff-id=1,diff-type=compliant]
----
class ClassA[T: str]: # Compliant: Concise syntax for type parameter is used
def method1(self) -> T:
...
----
== Resources
=== Documentation
* Python Documentation - https://docs.python.org/3.12/reference/compound_stmts.html#generic-classes[Generic classes]
* Python 3.12 Release Notes - https://docs.python.org/3.12/whatsnew/3.12.html#pep-695-type-parameter-syntax[PEP 695: Type Parameter Syntax]
* PEP 695 - https://peps.python.org/pep-0695/[Type Parameter Syntax]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
Use the type parameter syntax to declare this generic class.
'''
endif::env-github,rspecator-view[]