mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
[ruff
] Classes with mixed type variable style (RUF053
) (#15841)
This commit is contained in:
parent
ba2f0e998d
commit
84ceddcbd9
11 changed files with 900 additions and 32 deletions
109
crates/ruff_linter/resources/test/fixtures/ruff/RUF053.py
vendored
Normal file
109
crates/ruff_linter/resources/test/fixtures/ruff/RUF053.py
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
from typing import Generic, ParamSpec, TypeVar, TypeVarTuple, Unpack
|
||||
|
||||
|
||||
_A = TypeVar('_A')
|
||||
_B = TypeVar('_B', bound=int)
|
||||
_C = TypeVar('_C', str, bytes)
|
||||
_D = TypeVar('_D', default=int)
|
||||
_E = TypeVar('_E', bound=int, default=int)
|
||||
_F = TypeVar('_F', str, bytes, default=str)
|
||||
_G = TypeVar('_G', str, a := int)
|
||||
|
||||
_As = TypeVarTuple('_As')
|
||||
_Bs = TypeVarTuple('_Bs', bound=tuple[int, str])
|
||||
_Cs = TypeVarTuple('_Cs', default=tuple[int, str])
|
||||
|
||||
_P1 = ParamSpec('_P1')
|
||||
_P2 = ParamSpec('_P2', bound=[bytes, bool])
|
||||
_P3 = ParamSpec('_P3', default=[int, str])
|
||||
|
||||
|
||||
### Errors
|
||||
|
||||
class C[T](Generic[_A]): ...
|
||||
class C[T](Generic[_B], str): ...
|
||||
class C[T](int, Generic[_C]): ...
|
||||
class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
|
||||
class C[*Ts](Generic[*_As]): ...
|
||||
class C[*Ts](Generic[Unpack[_As]]): ...
|
||||
class C[*Ts](Generic[Unpack[_Bs]], tuple[*Bs]): ...
|
||||
class C[*Ts](Callable[[*_Cs], tuple[*Ts]], Generic[_Cs]): ... # TODO: Type parameter defaults
|
||||
|
||||
|
||||
class C[**P](Generic[_P1]): ...
|
||||
class C[**P](Generic[_P2]): ...
|
||||
class C[**P](Generic[_P3]): ... # TODO: Type parameter defaults
|
||||
|
||||
|
||||
class C[T](Generic[T, _A]): ...
|
||||
|
||||
|
||||
# See `is_existing_param_of_same_class`.
|
||||
# `expr_name_to_type_var` doesn't handle named expressions,
|
||||
# only simple assignments, so there is no fix.
|
||||
class C[T: (_Z := TypeVar('_Z'))](Generic[_Z]): ...
|
||||
|
||||
|
||||
class C(Generic[_B]):
|
||||
class D[T](Generic[_B, T]): ...
|
||||
|
||||
|
||||
class C[T]:
|
||||
class D[U](Generic[T, U]): ...
|
||||
|
||||
|
||||
# In a single run, only the first is reported.
|
||||
# Others will be reported/fixed in following iterations.
|
||||
class C[T](Generic[_C], Generic[_D]): ...
|
||||
class C[T, _C: (str, bytes)](Generic[_D]): ... # TODO: Type parameter defaults
|
||||
|
||||
|
||||
class C[
|
||||
T # Comment
|
||||
](Generic[_E]): ... # TODO: Type parameter defaults
|
||||
|
||||
|
||||
class C[T](Generic[Generic[_F]]): ...
|
||||
class C[T](Generic[Unpack[_A]]): ...
|
||||
class C[T](Generic[Unpack[_P1]]): ...
|
||||
class C[T](Generic[Unpack[Unpack[_P2]]]): ...
|
||||
class C[T](Generic[Unpack[*_As]]): ...
|
||||
class C[T](Generic[Unpack[_As, _Bs]]): ...
|
||||
|
||||
|
||||
class C[T](Generic[_A, _A]): ...
|
||||
class C[T](Generic[_A, Unpack[_As]]): ...
|
||||
class C[T](Generic[*_As, _A]): ...
|
||||
|
||||
|
||||
from somewhere import APublicTypeVar
|
||||
class C[T](Generic[APublicTypeVar]): ...
|
||||
class C[T](Generic[APublicTypeVar, _A]): ...
|
||||
|
||||
|
||||
# `_G` has two constraints: `str` and `a := int`.
|
||||
# The latter cannot be used as a PEP 695 constraint,
|
||||
# as named expressions are forbidden within type parameter lists.
|
||||
# See also the `_Z` example above.
|
||||
class C[T](Generic[_G]): ... # Should be moved down below eventually
|
||||
|
||||
|
||||
# Single-element constraints should not be converted to a bound.
|
||||
class C[T: (str,)](Generic[_A]): ...
|
||||
class C[T: [a]](Generic[_A]): ...
|
||||
|
||||
|
||||
# Existing bounds should not be deparenthesized.
|
||||
# class C[T: (_Y := int)](Generic[_A]): ... # TODO: Uncomment this
|
||||
# class C[T: (*a,)](Generic[_A]): ... # TODO: Uncomment this
|
||||
|
||||
|
||||
### No errors
|
||||
|
||||
class C(Generic[_A]): ...
|
||||
class C[_A]: ...
|
||||
class C[_A](list[_A]): ...
|
||||
class C[_A](list[Generic[_A]]): ...
|
|
@ -554,6 +554,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::NonPEP695GenericClass) {
|
||||
pyupgrade::rules::non_pep695_generic_class(checker, class_def);
|
||||
}
|
||||
if checker.enabled(Rule::ClassWithMixedTypeVars) {
|
||||
ruff::rules::class_with_mixed_type_vars(checker, class_def);
|
||||
}
|
||||
}
|
||||
Stmt::Import(ast::StmtImport { names, range: _ }) => {
|
||||
if checker.enabled(Rule::MultipleImportsOnOneLine) {
|
||||
|
|
|
@ -1005,6 +1005,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
(Ruff, "049") => (RuleGroup::Preview, rules::ruff::rules::DataclassEnum),
|
||||
(Ruff, "051") => (RuleGroup::Preview, rules::ruff::rules::IfKeyInDictDel),
|
||||
(Ruff, "052") => (RuleGroup::Preview, rules::ruff::rules::UsedDummyVariable),
|
||||
(Ruff, "053") => (RuleGroup::Preview, rules::ruff::rules::ClassWithMixedTypeVars),
|
||||
(Ruff, "055") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRegularExpression),
|
||||
(Ruff, "056") => (RuleGroup::Preview, rules::ruff::rules::FalsyDictGetFallback),
|
||||
(Ruff, "057") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRound),
|
||||
|
|
|
@ -57,7 +57,7 @@ mod native_literals;
|
|||
mod open_alias;
|
||||
mod os_error_alias;
|
||||
mod outdated_version_block;
|
||||
mod pep695;
|
||||
pub(crate) mod pep695;
|
||||
mod printf_string_formatting;
|
||||
mod quoted_annotation;
|
||||
mod redundant_open_modes;
|
||||
|
|
|
@ -9,7 +9,7 @@ use ruff_python_ast::{
|
|||
self as ast,
|
||||
name::Name,
|
||||
visitor::{self, Visitor},
|
||||
Expr, ExprCall, ExprName, ExprSubscript, Identifier, Stmt, StmtAssign, TypeParam,
|
||||
Arguments, Expr, ExprCall, ExprName, ExprSubscript, Identifier, Stmt, StmtAssign, TypeParam,
|
||||
TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple,
|
||||
};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
|
@ -28,7 +28,7 @@ mod non_pep695_type_alias;
|
|||
mod private_type_parameter;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TypeVarRestriction<'a> {
|
||||
pub(crate) enum TypeVarRestriction<'a> {
|
||||
/// A type variable with a bound, e.g., `TypeVar("T", bound=int)`.
|
||||
Bound(&'a Expr),
|
||||
/// A type variable with constraints, e.g., `TypeVar("T", int, str)`.
|
||||
|
@ -39,25 +39,25 @@ enum TypeVarRestriction<'a> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum TypeParamKind {
|
||||
pub(crate) enum TypeParamKind {
|
||||
TypeVar,
|
||||
TypeVarTuple,
|
||||
ParamSpec,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TypeVar<'a> {
|
||||
name: &'a str,
|
||||
restriction: Option<TypeVarRestriction<'a>>,
|
||||
kind: TypeParamKind,
|
||||
default: Option<&'a Expr>,
|
||||
pub(crate) struct TypeVar<'a> {
|
||||
pub(crate) name: &'a str,
|
||||
pub(crate) restriction: Option<TypeVarRestriction<'a>>,
|
||||
pub(crate) kind: TypeParamKind,
|
||||
pub(crate) default: Option<&'a Expr>,
|
||||
}
|
||||
|
||||
/// Wrapper for formatting a sequence of [`TypeVar`]s for use as a generic type parameter (e.g. `[T,
|
||||
/// *Ts, **P]`). See [`DisplayTypeVar`] for further details.
|
||||
struct DisplayTypeVars<'a> {
|
||||
type_vars: &'a [TypeVar<'a>],
|
||||
source: &'a str,
|
||||
pub(crate) struct DisplayTypeVars<'a> {
|
||||
pub(crate) type_vars: &'a [TypeVar<'a>],
|
||||
pub(crate) source: &'a str,
|
||||
}
|
||||
|
||||
impl Display for DisplayTypeVars<'_> {
|
||||
|
@ -81,7 +81,7 @@ impl Display for DisplayTypeVars<'_> {
|
|||
|
||||
/// Used for displaying `type_var`. `source` is the whole file, which will be sliced to recover the
|
||||
/// `TypeVarRestriction` values for generic bounds and constraints.
|
||||
struct DisplayTypeVar<'a> {
|
||||
pub(crate) struct DisplayTypeVar<'a> {
|
||||
type_var: &'a TypeVar<'a>,
|
||||
source: &'a str,
|
||||
}
|
||||
|
@ -192,6 +192,34 @@ impl<'a> From<&'a TypeVar<'a>> for TypeParam {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a TypeParam> for TypeVar<'a> {
|
||||
fn from(param: &'a TypeParam) -> Self {
|
||||
let (kind, restriction) = match param {
|
||||
TypeParam::TypeVarTuple(_) => (TypeParamKind::TypeVarTuple, None),
|
||||
TypeParam::ParamSpec(_) => (TypeParamKind::ParamSpec, None),
|
||||
|
||||
TypeParam::TypeVar(param) => {
|
||||
let restriction = match param.bound.as_deref() {
|
||||
None => None,
|
||||
Some(Expr::Tuple(constraints)) => Some(TypeVarRestriction::Constraint(
|
||||
constraints.elts.iter().collect::<Vec<_>>(),
|
||||
)),
|
||||
Some(bound) => Some(TypeVarRestriction::Bound(bound)),
|
||||
};
|
||||
|
||||
(TypeParamKind::TypeVar, restriction)
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
name: param.name(),
|
||||
kind,
|
||||
restriction,
|
||||
default: param.default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeVarReferenceVisitor<'a> {
|
||||
vars: Vec<TypeVar<'a>>,
|
||||
semantic: &'a SemanticModel<'a>,
|
||||
|
@ -242,7 +270,7 @@ impl<'a> Visitor<'a> for TypeVarReferenceVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn expr_name_to_type_var<'a>(
|
||||
pub(crate) fn expr_name_to_type_var<'a>(
|
||||
semantic: &'a SemanticModel,
|
||||
name: &'a ExprName,
|
||||
) -> Option<TypeVar<'a>> {
|
||||
|
@ -349,3 +377,18 @@ fn check_type_vars(vars: Vec<TypeVar<'_>>) -> Option<Vec<TypeVar<'_>>> {
|
|||
== vars.len())
|
||||
.then_some(vars)
|
||||
}
|
||||
|
||||
/// Search `class_bases` for a `typing.Generic` base class. Returns the `Generic` expression (if
|
||||
/// any), along with its index in the class's bases tuple.
|
||||
pub(crate) fn find_generic<'a>(
|
||||
class_bases: &'a Arguments,
|
||||
semantic: &SemanticModel,
|
||||
) -> Option<(usize, &'a ExprSubscript)> {
|
||||
class_bases.args.iter().enumerate().find_map(|(idx, expr)| {
|
||||
expr.as_subscript_expr().and_then(|sub_expr| {
|
||||
semantic
|
||||
.match_typing_expr(&sub_expr.value, "Generic")
|
||||
.then_some((idx, sub_expr))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::visitor::Visitor;
|
||||
use ruff_python_ast::{Arguments, ExprSubscript, StmtClassDef};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_python_ast::{ExprSubscript, StmtClassDef};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::edits::{remove_argument, Parentheses};
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
use super::{check_type_vars, in_nested_context, DisplayTypeVars, TypeVarReferenceVisitor};
|
||||
use super::{
|
||||
check_type_vars, find_generic, in_nested_context, DisplayTypeVars, TypeVarReferenceVisitor,
|
||||
};
|
||||
|
||||
/// ## What it does
|
||||
///
|
||||
|
@ -211,18 +212,3 @@ pub(crate) fn non_pep695_generic_class(checker: &mut Checker, class_def: &StmtCl
|
|||
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// Search `class_bases` for a `typing.Generic` base class. Returns the `Generic` expression (if
|
||||
/// any), along with its index in the class's bases tuple.
|
||||
fn find_generic<'a>(
|
||||
class_bases: &'a Arguments,
|
||||
semantic: &SemanticModel,
|
||||
) -> Option<(usize, &'a ExprSubscript)> {
|
||||
class_bases.args.iter().enumerate().find_map(|(idx, expr)| {
|
||||
expr.as_subscript_expr().and_then(|sub_expr| {
|
||||
semantic
|
||||
.match_typing_expr(&sub_expr.value, "Generic")
|
||||
.then_some((idx, sub_expr))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -435,6 +435,7 @@ mod tests {
|
|||
#[test_case(Rule::DataclassEnum, Path::new("RUF049.py"))]
|
||||
#[test_case(Rule::StarmapZip, Path::new("RUF058_0.py"))]
|
||||
#[test_case(Rule::StarmapZip, Path::new("RUF058_1.py"))]
|
||||
#[test_case(Rule::ClassWithMixedTypeVars, Path::new("RUF053.py"))]
|
||||
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!(
|
||||
"preview__{}_{}",
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
use rustc_hash::FxHashSet;
|
||||
use std::iter;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::{
|
||||
Arguments, Expr, ExprStarred, ExprSubscript, ExprTuple, StmtClassDef, TypeParams,
|
||||
};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::edits::{remove_argument, Parentheses};
|
||||
use crate::rules::pyupgrade::rules::pep695::{
|
||||
expr_name_to_type_var, find_generic, DisplayTypeVars, TypeParamKind, TypeVar,
|
||||
};
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for classes that have [PEP 695] [type parameter lists]
|
||||
/// while also inheriting from `typing.Generic` or `typing_extensions.Generic`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Such classes cause errors at runtime:
|
||||
///
|
||||
/// ```python
|
||||
/// from typing import Generic, TypeVar
|
||||
///
|
||||
/// U = TypeVar("U")
|
||||
///
|
||||
/// # TypeError: Cannot inherit from Generic[...] multiple times.
|
||||
/// class C[T](Generic[U]): ...
|
||||
/// ```
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```python
|
||||
/// from typing import Generic, ParamSpec, TypeVar, TypeVarTuple
|
||||
///
|
||||
/// U = TypeVar("U")
|
||||
/// P = ParamSpec("P")
|
||||
/// Ts = TypeVarTuple("Ts")
|
||||
///
|
||||
///
|
||||
/// class C[T](Generic[U, P, *Ts]): ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
///
|
||||
/// ```python
|
||||
/// class C[T, U, **P, *Ts]: ...
|
||||
/// ```
|
||||
///
|
||||
/// ## Fix safety
|
||||
/// As the fix changes runtime behaviour, it is always marked as unsafe.
|
||||
/// Additionally, comments within the fix range will not be preserved.
|
||||
///
|
||||
/// ## References
|
||||
/// - [Python documentation: User-defined generic types](https://docs.python.org/3/library/typing.html#user-defined-generic-types)
|
||||
/// - [Python documentation: type parameter lists](https://docs.python.org/3/reference/compound_stmts.html#type-params)
|
||||
/// - [PEP 695 - Type Parameter Syntax](https://peps.python.org/pep-0695/)
|
||||
///
|
||||
/// [PEP 695]: https://peps.python.org/pep-0695/
|
||||
/// [type parameter lists]: https://docs.python.org/3/reference/compound_stmts.html#type-params
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct ClassWithMixedTypeVars;
|
||||
|
||||
impl Violation for ClassWithMixedTypeVars {
|
||||
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
"Class with type parameter list inherits from `Generic`".to_string()
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> Option<String> {
|
||||
Some("Remove `Generic` base class".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// RUF053
|
||||
pub(crate) fn class_with_mixed_type_vars(checker: &mut Checker, class_def: &StmtClassDef) {
|
||||
if checker.settings.target_version < PythonVersion::Py312 {
|
||||
return;
|
||||
}
|
||||
|
||||
let StmtClassDef {
|
||||
type_params,
|
||||
arguments,
|
||||
..
|
||||
} = class_def;
|
||||
|
||||
let Some(type_params) = type_params else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(arguments) = arguments else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some((generic_base, old_style_type_vars)) =
|
||||
typing_generic_base_and_arguments(arguments, checker.semantic())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut diagnostic = Diagnostic::new(ClassWithMixedTypeVars, generic_base.range);
|
||||
|
||||
diagnostic.try_set_optional_fix(|| {
|
||||
convert_type_vars(
|
||||
generic_base,
|
||||
old_style_type_vars,
|
||||
type_params,
|
||||
arguments,
|
||||
checker,
|
||||
)
|
||||
});
|
||||
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
fn typing_generic_base_and_arguments<'a>(
|
||||
class_arguments: &'a Arguments,
|
||||
semantic: &SemanticModel,
|
||||
) -> Option<(&'a ExprSubscript, &'a Expr)> {
|
||||
let (_, base @ ExprSubscript { slice, .. }) = find_generic(class_arguments, semantic)?;
|
||||
|
||||
Some((base, slice.as_ref()))
|
||||
}
|
||||
|
||||
fn convert_type_vars(
|
||||
generic_base: &ExprSubscript,
|
||||
old_style_type_vars: &Expr,
|
||||
type_params: &TypeParams,
|
||||
class_arguments: &Arguments,
|
||||
checker: &Checker,
|
||||
) -> anyhow::Result<Option<Fix>> {
|
||||
let mut type_vars: Vec<_> = type_params.type_params.iter().map(TypeVar::from).collect();
|
||||
|
||||
let semantic = checker.semantic();
|
||||
let converted_type_vars = match old_style_type_vars {
|
||||
Expr::Tuple(ExprTuple { elts, .. }) => {
|
||||
generic_arguments_to_type_vars(elts.iter(), type_params, semantic)
|
||||
}
|
||||
expr @ (Expr::Subscript(_) | Expr::Name(_)) => {
|
||||
generic_arguments_to_type_vars(iter::once(expr), type_params, semantic)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let Some(converted_type_vars) = converted_type_vars else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
type_vars.extend(converted_type_vars);
|
||||
|
||||
let source = checker.source();
|
||||
let new_type_params = DisplayTypeVars {
|
||||
type_vars: &type_vars,
|
||||
source,
|
||||
};
|
||||
|
||||
let remove_generic_base =
|
||||
remove_argument(generic_base, class_arguments, Parentheses::Remove, source)?;
|
||||
let replace_type_params =
|
||||
Edit::range_replacement(new_type_params.to_string(), type_params.range);
|
||||
|
||||
Ok(Some(Fix::unsafe_edits(
|
||||
remove_generic_base,
|
||||
[replace_type_params],
|
||||
)))
|
||||
}
|
||||
|
||||
/// Returns the type variables `exprs` represent.
|
||||
///
|
||||
/// If at least one of them cannot be converted to [`TypeVar`],
|
||||
/// `None` is returned.
|
||||
fn generic_arguments_to_type_vars<'a>(
|
||||
exprs: impl Iterator<Item = &'a Expr>,
|
||||
existing_type_params: &TypeParams,
|
||||
semantic: &'a SemanticModel,
|
||||
) -> Option<Vec<TypeVar<'a>>> {
|
||||
let mut type_vars = vec![];
|
||||
let mut encountered: FxHashSet<&str> = existing_type_params
|
||||
.iter()
|
||||
.map(|tp| tp.name().as_str())
|
||||
.collect();
|
||||
|
||||
for expr in exprs {
|
||||
let (name, unpacked) = match expr {
|
||||
Expr::Name(name) => (name, false),
|
||||
Expr::Starred(ExprStarred { value, .. }) => (value.as_name_expr()?, true),
|
||||
|
||||
Expr::Subscript(ExprSubscript { value, slice, .. }) => {
|
||||
if !semantic.match_typing_expr(value, "Unpack") {
|
||||
return None;
|
||||
}
|
||||
|
||||
(slice.as_name_expr()?, true)
|
||||
}
|
||||
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if !encountered.insert(name.id.as_str()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let type_var = expr_name_to_type_var(semantic, name)?;
|
||||
|
||||
if !type_var_is_valid(&type_var, unpacked) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// TODO: Type parameter defaults
|
||||
if type_var.default.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
type_vars.push(type_var);
|
||||
}
|
||||
|
||||
Some(type_vars)
|
||||
}
|
||||
|
||||
/// Returns true in the following cases:
|
||||
///
|
||||
/// * If `type_var` is a `TypeVar`:
|
||||
/// * It must not be unpacked
|
||||
/// * If `type_var` is a `TypeVarTuple`:
|
||||
/// * It must be unpacked
|
||||
/// * It must not have any restrictions
|
||||
/// * If `type_var` is a `ParamSpec`:
|
||||
/// * It must not be unpacked
|
||||
/// * It must not have any restrictions
|
||||
fn type_var_is_valid(type_var: &TypeVar, unpacked: bool) -> bool {
|
||||
let is_type_var_tuple = matches!(&type_var.kind, TypeParamKind::TypeVarTuple);
|
||||
|
||||
if is_type_var_tuple && !unpacked || !is_type_var_tuple && unpacked {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !matches!(&type_var.kind, TypeParamKind::TypeVar) && type_var.restriction.is_some() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
|
@ -2,6 +2,7 @@ pub(crate) use ambiguous_unicode_character::*;
|
|||
pub(crate) use assert_with_print_message::*;
|
||||
pub(crate) use assignment_in_assert::*;
|
||||
pub(crate) use asyncio_dangling_task::*;
|
||||
pub(crate) use class_with_mixed_type_vars::*;
|
||||
pub(crate) use collection_literal_concatenation::*;
|
||||
pub(crate) use dataclass_enum::*;
|
||||
pub(crate) use decimal_from_float_literal::*;
|
||||
|
@ -55,6 +56,7 @@ mod ambiguous_unicode_character;
|
|||
mod assert_with_print_message;
|
||||
mod assignment_in_assert;
|
||||
mod asyncio_dangling_task;
|
||||
mod class_with_mixed_type_vars;
|
||||
mod collection_literal_concatenation;
|
||||
mod confusables;
|
||||
mod dataclass_enum;
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||
---
|
||||
RUF053.py:23:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
21 | ### Errors
|
||||
22 |
|
||||
23 | class C[T](Generic[_A]): ...
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
24 | class C[T](Generic[_B], str): ...
|
||||
25 | class C[T](int, Generic[_C]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
20 20 |
|
||||
21 21 | ### Errors
|
||||
22 22 |
|
||||
23 |-class C[T](Generic[_A]): ...
|
||||
23 |+class C[T, _A]: ...
|
||||
24 24 | class C[T](Generic[_B], str): ...
|
||||
25 25 | class C[T](int, Generic[_C]): ...
|
||||
26 26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
|
||||
RUF053.py:24:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
23 | class C[T](Generic[_A]): ...
|
||||
24 | class C[T](Generic[_B], str): ...
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
25 | class C[T](int, Generic[_C]): ...
|
||||
26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
21 21 | ### Errors
|
||||
22 22 |
|
||||
23 23 | class C[T](Generic[_A]): ...
|
||||
24 |-class C[T](Generic[_B], str): ...
|
||||
24 |+class C[T, _B: int](str): ...
|
||||
25 25 | class C[T](int, Generic[_C]): ...
|
||||
26 26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
27 27 | class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
|
||||
RUF053.py:25:17: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
23 | class C[T](Generic[_A]): ...
|
||||
24 | class C[T](Generic[_B], str): ...
|
||||
25 | class C[T](int, Generic[_C]): ...
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
27 | class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
22 22 |
|
||||
23 23 | class C[T](Generic[_A]): ...
|
||||
24 24 | class C[T](Generic[_B], str): ...
|
||||
25 |-class C[T](int, Generic[_C]): ...
|
||||
25 |+class C[T, _C: (str, bytes)](int): ...
|
||||
26 26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
27 27 | class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
28 28 | class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
|
||||
RUF053.py:26:19: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
24 | class C[T](Generic[_B], str): ...
|
||||
25 | class C[T](int, Generic[_C]): ...
|
||||
26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
27 | class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
28 | class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:27:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
25 | class C[T](int, Generic[_C]): ...
|
||||
26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
27 | class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
28 | class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:28:22: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
26 | class C[T](bytes, Generic[_D], bool): ... # TODO: Type parameter defaults
|
||||
27 | class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
28 | class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
29 |
|
||||
30 | class C[*Ts](Generic[*_As]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:30:14: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
28 | class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
29 |
|
||||
30 | class C[*Ts](Generic[*_As]): ...
|
||||
| ^^^^^^^^^^^^^ RUF053
|
||||
31 | class C[*Ts](Generic[Unpack[_As]]): ...
|
||||
32 | class C[*Ts](Generic[Unpack[_Bs]], tuple[*Bs]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
27 27 | class C[T](Generic[_E], list[_E]): ... # TODO: Type parameter defaults
|
||||
28 28 | class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
29 29 |
|
||||
30 |-class C[*Ts](Generic[*_As]): ...
|
||||
30 |+class C[*Ts, *_As]: ...
|
||||
31 31 | class C[*Ts](Generic[Unpack[_As]]): ...
|
||||
32 32 | class C[*Ts](Generic[Unpack[_Bs]], tuple[*Bs]): ...
|
||||
33 33 | class C[*Ts](Callable[[*_Cs], tuple[*Ts]], Generic[_Cs]): ... # TODO: Type parameter defaults
|
||||
|
||||
RUF053.py:31:14: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
30 | class C[*Ts](Generic[*_As]): ...
|
||||
31 | class C[*Ts](Generic[Unpack[_As]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
32 | class C[*Ts](Generic[Unpack[_Bs]], tuple[*Bs]): ...
|
||||
33 | class C[*Ts](Callable[[*_Cs], tuple[*Ts]], Generic[_Cs]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
28 28 | class C[T](list[_F], Generic[_F]): ... # TODO: Type parameter defaults
|
||||
29 29 |
|
||||
30 30 | class C[*Ts](Generic[*_As]): ...
|
||||
31 |-class C[*Ts](Generic[Unpack[_As]]): ...
|
||||
31 |+class C[*Ts, *_As]: ...
|
||||
32 32 | class C[*Ts](Generic[Unpack[_Bs]], tuple[*Bs]): ...
|
||||
33 33 | class C[*Ts](Callable[[*_Cs], tuple[*Ts]], Generic[_Cs]): ... # TODO: Type parameter defaults
|
||||
34 34 |
|
||||
|
||||
RUF053.py:32:14: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
30 | class C[*Ts](Generic[*_As]): ...
|
||||
31 | class C[*Ts](Generic[Unpack[_As]]): ...
|
||||
32 | class C[*Ts](Generic[Unpack[_Bs]], tuple[*Bs]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
33 | class C[*Ts](Callable[[*_Cs], tuple[*Ts]], Generic[_Cs]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:33:44: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
31 | class C[*Ts](Generic[Unpack[_As]]): ...
|
||||
32 | class C[*Ts](Generic[Unpack[_Bs]], tuple[*Bs]): ...
|
||||
33 | class C[*Ts](Callable[[*_Cs], tuple[*Ts]], Generic[_Cs]): ... # TODO: Type parameter defaults
|
||||
| ^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:36:14: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
36 | class C[**P](Generic[_P1]): ...
|
||||
| ^^^^^^^^^^^^ RUF053
|
||||
37 | class C[**P](Generic[_P2]): ...
|
||||
38 | class C[**P](Generic[_P3]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
33 33 | class C[*Ts](Callable[[*_Cs], tuple[*Ts]], Generic[_Cs]): ... # TODO: Type parameter defaults
|
||||
34 34 |
|
||||
35 35 |
|
||||
36 |-class C[**P](Generic[_P1]): ...
|
||||
36 |+class C[**P, **_P1]: ...
|
||||
37 37 | class C[**P](Generic[_P2]): ...
|
||||
38 38 | class C[**P](Generic[_P3]): ... # TODO: Type parameter defaults
|
||||
39 39 |
|
||||
|
||||
RUF053.py:37:14: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
36 | class C[**P](Generic[_P1]): ...
|
||||
37 | class C[**P](Generic[_P2]): ...
|
||||
| ^^^^^^^^^^^^ RUF053
|
||||
38 | class C[**P](Generic[_P3]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:38:14: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
36 | class C[**P](Generic[_P1]): ...
|
||||
37 | class C[**P](Generic[_P2]): ...
|
||||
38 | class C[**P](Generic[_P3]): ... # TODO: Type parameter defaults
|
||||
| ^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:41:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
41 | class C[T](Generic[T, _A]): ...
|
||||
| ^^^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
38 38 | class C[**P](Generic[_P3]): ... # TODO: Type parameter defaults
|
||||
39 39 |
|
||||
40 40 |
|
||||
41 |-class C[T](Generic[T, _A]): ...
|
||||
41 |+class C[T, _A]: ...
|
||||
42 42 |
|
||||
43 43 |
|
||||
44 44 | # See `is_existing_param_of_same_class`.
|
||||
|
||||
RUF053.py:47:35: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
45 | # `expr_name_to_type_var` doesn't handle named expressions,
|
||||
46 | # only simple assignments, so there is no fix.
|
||||
47 | class C[T: (_Z := TypeVar('_Z'))](Generic[_Z]): ...
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:51:16: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
50 | class C(Generic[_B]):
|
||||
51 | class D[T](Generic[_B, T]): ...
|
||||
| ^^^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
48 48 |
|
||||
49 49 |
|
||||
50 50 | class C(Generic[_B]):
|
||||
51 |- class D[T](Generic[_B, T]): ...
|
||||
51 |+ class D[T, _B: int]: ...
|
||||
52 52 |
|
||||
53 53 |
|
||||
54 54 | class C[T]:
|
||||
|
||||
RUF053.py:55:16: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
54 | class C[T]:
|
||||
55 | class D[U](Generic[T, U]): ...
|
||||
| ^^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:60:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
58 | # In a single run, only the first is reported.
|
||||
59 | # Others will be reported/fixed in following iterations.
|
||||
60 | class C[T](Generic[_C], Generic[_D]): ...
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
61 | class C[T, _C: (str, bytes)](Generic[_D]): ... # TODO: Type parameter defaults
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
57 57 |
|
||||
58 58 | # In a single run, only the first is reported.
|
||||
59 59 | # Others will be reported/fixed in following iterations.
|
||||
60 |-class C[T](Generic[_C], Generic[_D]): ...
|
||||
60 |+class C[T, _C: (str, bytes)](Generic[_D]): ...
|
||||
61 61 | class C[T, _C: (str, bytes)](Generic[_D]): ... # TODO: Type parameter defaults
|
||||
62 62 |
|
||||
63 63 |
|
||||
|
||||
RUF053.py:61:30: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
59 | # Others will be reported/fixed in following iterations.
|
||||
60 | class C[T](Generic[_C], Generic[_D]): ...
|
||||
61 | class C[T, _C: (str, bytes)](Generic[_D]): ... # TODO: Type parameter defaults
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:66:3: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
64 | class C[
|
||||
65 | T # Comment
|
||||
66 | ](Generic[_E]): ... # TODO: Type parameter defaults
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:69:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
69 | class C[T](Generic[Generic[_F]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
70 | class C[T](Generic[Unpack[_A]]): ...
|
||||
71 | class C[T](Generic[Unpack[_P1]]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:70:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
69 | class C[T](Generic[Generic[_F]]): ...
|
||||
70 | class C[T](Generic[Unpack[_A]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
71 | class C[T](Generic[Unpack[_P1]]): ...
|
||||
72 | class C[T](Generic[Unpack[Unpack[_P2]]]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:71:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
69 | class C[T](Generic[Generic[_F]]): ...
|
||||
70 | class C[T](Generic[Unpack[_A]]): ...
|
||||
71 | class C[T](Generic[Unpack[_P1]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
72 | class C[T](Generic[Unpack[Unpack[_P2]]]): ...
|
||||
73 | class C[T](Generic[Unpack[*_As]]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:72:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
70 | class C[T](Generic[Unpack[_A]]): ...
|
||||
71 | class C[T](Generic[Unpack[_P1]]): ...
|
||||
72 | class C[T](Generic[Unpack[Unpack[_P2]]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
73 | class C[T](Generic[Unpack[*_As]]): ...
|
||||
74 | class C[T](Generic[Unpack[_As, _Bs]]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:73:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
71 | class C[T](Generic[Unpack[_P1]]): ...
|
||||
72 | class C[T](Generic[Unpack[Unpack[_P2]]]): ...
|
||||
73 | class C[T](Generic[Unpack[*_As]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
74 | class C[T](Generic[Unpack[_As, _Bs]]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:74:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
72 | class C[T](Generic[Unpack[Unpack[_P2]]]): ...
|
||||
73 | class C[T](Generic[Unpack[*_As]]): ...
|
||||
74 | class C[T](Generic[Unpack[_As, _Bs]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:77:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
77 | class C[T](Generic[_A, _A]): ...
|
||||
| ^^^^^^^^^^^^^^^ RUF053
|
||||
78 | class C[T](Generic[_A, Unpack[_As]]): ...
|
||||
79 | class C[T](Generic[*_As, _A]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
74 74 | class C[T](Generic[Unpack[_As, _Bs]]): ...
|
||||
75 75 |
|
||||
76 76 |
|
||||
77 |-class C[T](Generic[_A, _A]): ...
|
||||
77 |+class C[T, _A]: ...
|
||||
78 78 | class C[T](Generic[_A, Unpack[_As]]): ...
|
||||
79 79 | class C[T](Generic[*_As, _A]): ...
|
||||
80 80 |
|
||||
|
||||
RUF053.py:78:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
77 | class C[T](Generic[_A, _A]): ...
|
||||
78 | class C[T](Generic[_A, Unpack[_As]]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
79 | class C[T](Generic[*_As, _A]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
75 75 |
|
||||
76 76 |
|
||||
77 77 | class C[T](Generic[_A, _A]): ...
|
||||
78 |-class C[T](Generic[_A, Unpack[_As]]): ...
|
||||
78 |+class C[T, _A, *_As]: ...
|
||||
79 79 | class C[T](Generic[*_As, _A]): ...
|
||||
80 80 |
|
||||
81 81 |
|
||||
|
||||
RUF053.py:79:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
77 | class C[T](Generic[_A, _A]): ...
|
||||
78 | class C[T](Generic[_A, Unpack[_As]]): ...
|
||||
79 | class C[T](Generic[*_As, _A]): ...
|
||||
| ^^^^^^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
76 76 |
|
||||
77 77 | class C[T](Generic[_A, _A]): ...
|
||||
78 78 | class C[T](Generic[_A, Unpack[_As]]): ...
|
||||
79 |-class C[T](Generic[*_As, _A]): ...
|
||||
79 |+class C[T, *_As, _A]: ...
|
||||
80 80 |
|
||||
81 81 |
|
||||
82 82 | from somewhere import APublicTypeVar
|
||||
|
||||
RUF053.py:83:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
82 | from somewhere import APublicTypeVar
|
||||
83 | class C[T](Generic[APublicTypeVar]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
84 | class C[T](Generic[APublicTypeVar, _A]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:84:12: RUF053 Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
82 | from somewhere import APublicTypeVar
|
||||
83 | class C[T](Generic[APublicTypeVar]): ...
|
||||
84 | class C[T](Generic[APublicTypeVar, _A]): ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
RUF053.py:91:12: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
89 | # as named expressions are forbidden within type parameter lists.
|
||||
90 | # See also the `_Z` example above.
|
||||
91 | class C[T](Generic[_G]): ... # Should be moved down below eventually
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
88 88 | # The latter cannot be used as a PEP 695 constraint,
|
||||
89 89 | # as named expressions are forbidden within type parameter lists.
|
||||
90 90 | # See also the `_Z` example above.
|
||||
91 |-class C[T](Generic[_G]): ... # Should be moved down below eventually
|
||||
91 |+class C[T, _G: (str, a := int)]: ... # Should be moved down below eventually
|
||||
92 92 |
|
||||
93 93 |
|
||||
94 94 | # Single-element constraints should not be converted to a bound.
|
||||
|
||||
RUF053.py:95:20: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
94 | # Single-element constraints should not be converted to a bound.
|
||||
95 | class C[T: (str,)](Generic[_A]): ...
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
96 | class C[T: [a]](Generic[_A]): ...
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
92 92 |
|
||||
93 93 |
|
||||
94 94 | # Single-element constraints should not be converted to a bound.
|
||||
95 |-class C[T: (str,)](Generic[_A]): ...
|
||||
95 |+class C[T: (str), _A]: ...
|
||||
96 96 | class C[T: [a]](Generic[_A]): ...
|
||||
97 97 |
|
||||
98 98 |
|
||||
|
||||
RUF053.py:96:17: RUF053 [*] Class with type parameter list inherits from `Generic`
|
||||
|
|
||||
94 | # Single-element constraints should not be converted to a bound.
|
||||
95 | class C[T: (str,)](Generic[_A]): ...
|
||||
96 | class C[T: [a]](Generic[_A]): ...
|
||||
| ^^^^^^^^^^^ RUF053
|
||||
|
|
||||
= help: Remove `Generic` base class
|
||||
|
||||
ℹ Unsafe fix
|
||||
93 93 |
|
||||
94 94 | # Single-element constraints should not be converted to a bound.
|
||||
95 95 | class C[T: (str,)](Generic[_A]): ...
|
||||
96 |-class C[T: [a]](Generic[_A]): ...
|
||||
96 |+class C[T: [a], _A]: ...
|
||||
97 97 |
|
||||
98 98 |
|
||||
99 99 | # Existing bounds should not be deparenthesized.
|
Loading…
Add table
Add a link
Reference in a new issue