diff --git a/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs b/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs index 9dbcd2be9f..28ecb6b514 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs @@ -20,53 +20,69 @@ use crate::rules::ruff::rules::helpers::{ /// changed in one instance, as those changes will unexpectedly affect all /// other instances. /// -/// When mutable values are intended, they should be annotated with -/// `typing.ClassVar`. When mutability is not required, values should be -/// immutable types, like `tuple` or `frozenset`. +/// Generally speaking, you probably want to avoid having mutable default +/// values in the class body at all; instead, these variables should usually +/// be initialized in `__init__`. However, other possible fixes for the issue +/// can include: +/// - Explicitly annotating the variable with [`typing.ClassVar`][ClassVar] to +/// indicate that it is intended to be shared across all instances. +/// - Using an immutable data type (e.g. a tuple instead of a list) +/// for the default value. /// -/// For mutable variables, prefer to initialize them in `__init__`. -/// -/// ## Examples -/// -/// Using `ClassVar` and imutable types: +/// ## Example /// /// ```python /// class A: -/// mutable_default: list[int] = [] -/// immutable_default: list[int] = [] +/// variable_1: list[int] = [] +/// variable_2: set[int] = set() +/// variable_3: dict[str, int] = {} /// ``` /// /// Use instead: /// /// ```python +/// class A: +/// def __init__(self) -> None: +/// self.variable_1: list[int] = [] +/// self.variable_2: set[int] = set() +/// self.variable_3: dict[str, int] = {} +/// ``` +/// +/// Or: +/// +/// ```python /// from typing import ClassVar /// /// /// class A: -/// mutable_default: ClassVar[list[int]] = [] -/// immutable_default: tuple[int, ...] = () +/// variable_1: ClassVar[list[int]] = [] +/// variable_2: ClassVar[set[int]] = set() +/// variable_3: ClassVar[dict[str, int]] = {} /// ``` /// -/// Using instance variables instead of class variables: +/// Or: /// /// ```python /// class A: -/// instance_dict: dict[str, str] = {"key": "value"} +/// variable_1: list[int] | None = None +/// variable_2: set[int] | None = None +/// variable_3: dict[str, int] | None = None /// ``` /// -/// Use instead: +/// Or: /// /// ```python -/// class A: -/// instance_dict: ClassVar[dict[str, str]] +/// from collections.abc import Sequence, Mapping, Set as AbstractSet +/// from types import MappingProxyType /// -/// def __init__(self) -> None: -/// self.instance_dict: dict[str, str] = {"key": "value"} +/// +/// class A: +/// variable_1: Sequence[int] = () +/// variable_2: AbstractSet[int] = frozenset() +/// variable_3: Mapping[str, int] = MappingProxyType({}) /// ``` /// -/// In cases where memory efficiency is a priority, `MappingProxyType` -/// can be used to create immutable dictionaries that are shared between -/// instances. +/// [ClassVar]: https://docs.python.org/3/library/typing.html#typing.ClassVar #[derive(ViolationMetadata)] pub(crate) struct MutableClassDefault;