From d164e0dbe443000a1cd7b7af16f1ad329de2487c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 30 Jul 2024 16:27:43 +0100 Subject: [PATCH] Consider more stdlib decorators to be property-like --- .../test/fixtures/flake8_return/RET501.py | 22 ++++++++++++++++ .../pylint/property_with_parameters.py | 19 ++++++++++++++ ...__PLR0206_property_with_parameters.py.snap | 25 +++++++++++++++++++ .../src/analyze/visibility.rs | 5 +++- 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_return/RET501.py b/crates/ruff_linter/resources/test/fixtures/flake8_return/RET501.py index 972b686ac9cbd..70346bef98686 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_return/RET501.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_return/RET501.py @@ -27,3 +27,25 @@ class BaseCache2: def prop(self) -> None: print("Property not found") return None + + +import abc +import enum +import types + + +class Baz: + @abc.abstractproperty + def prop2(self) -> None: + print("Override me") + return None + + @types.DynamicClassAttribute + def prop3(self) -> None: + print("Gotta make this a multiline function for it to be a meaningful test") + return None + + @enum.property + def prop4(self) -> None: + print("I've run out of things to say") + return None diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/property_with_parameters.py b/crates/ruff_linter/resources/test/fixtures/pylint/property_with_parameters.py index 210f02981ff35..4b6a076e6e81b 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/property_with_parameters.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/property_with_parameters.py @@ -47,3 +47,22 @@ class Cached: @cached_property def cached_prop(self, value): # [property-with-parameters] ... + + +import abc +import enum +import types + + +class Baz: + @abc.abstractproperty + def prop2(self, param) -> None: # [property-with-parameters] + return None + + @types.DynamicClassAttribute + def prop3(self, param) -> None: # [property-with-parameters] + return None + + @enum.property + def prop4(self, param) -> None: # [property-with-parameters] + return None diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0206_property_with_parameters.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0206_property_with_parameters.py.snap index cf968be9da783..ada975adc5a78 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0206_property_with_parameters.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0206_property_with_parameters.py.snap @@ -51,3 +51,28 @@ property_with_parameters.py:48:9: PLR0206 Cannot have defined parameters for pro | ^^^^^^^^^^^ PLR0206 49 | ... | + +property_with_parameters.py:59:9: PLR0206 Cannot have defined parameters for properties + | +57 | class Baz: +58 | @abc.abstractproperty +59 | def prop2(self, param) -> None: # [property-with-parameters] + | ^^^^^ PLR0206 +60 | return None + | + +property_with_parameters.py:63:9: PLR0206 Cannot have defined parameters for properties + | +62 | @types.DynamicClassAttribute +63 | def prop3(self, param) -> None: # [property-with-parameters] + | ^^^^^ PLR0206 +64 | return None + | + +property_with_parameters.py:67:9: PLR0206 Cannot have defined parameters for properties + | +66 | @enum.property +67 | def prop4(self, param) -> None: # [property-with-parameters] + | ^^^^^ PLR0206 +68 | return None + | diff --git a/crates/ruff_python_semantic/src/analyze/visibility.rs b/crates/ruff_python_semantic/src/analyze/visibility.rs index 1910af249a84e..e3f77fcfc1ff3 100644 --- a/crates/ruff_python_semantic/src/analyze/visibility.rs +++ b/crates/ruff_python_semantic/src/analyze/visibility.rs @@ -74,7 +74,10 @@ pub fn is_property( .is_some_and(|qualified_name| { matches!( qualified_name.segments(), - ["" | "builtins", "property"] | ["functools", "cached_property"] + ["" | "builtins" | "enum", "property"] + | ["functools", "cached_property"] + | ["abc", "abstractproperty"] + | ["types", "DynamicClassAttribute"] ) || extra_properties .iter() .any(|extra_property| extra_property.segments() == qualified_name.segments())