![github-actions[bot]](/assets/img/avatar_default.png)
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>
84 lines
2.5 KiB
Plaintext
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[]
|