Move `@functools.cache` rewrites to their own rule (#1938)

Closes #1934.
This commit is contained in:
Charlie Marsh 2023-01-17 15:12:40 -05:00 committed by GitHub
parent 70ea4b25e8
commit 072849a8a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 425 additions and 390 deletions

View File

@ -1,5 +1,14 @@
# Breaking Changes # Breaking Changes
## 0.0.225
### `@functools.cache` rewrites have been moved to a standalone rule (`UP033`) ([#1938](https://github.com/charliermarsh/ruff/pull/1938))
Previously, `UP011` handled both `@functools.lru_cache()`-to-`@functools.lru_cache` conversions,
_and_ `@functools.lru_cache(maxsize=None)`-to-`@functools.cache` conversions. The latter has been
moved out to its own rule (`UP033`). As such, some `# noqa: UP011` comments may need to be updated
to reflect the change in rule code.
## 0.0.222 ## 0.0.222
### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/charliermarsh/ruff/pull/1877)) ### `--max-complexity` has been removed from the CLI ([#1877](https://github.com/charliermarsh/ruff/pull/1877))

View File

@ -705,7 +705,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
| UP008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | 🛠 | | UP008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | 🛠 |
| UP009 | PEP3120UnnecessaryCodingComment | UTF-8 encoding declaration is unnecessary | 🛠 | | UP009 | PEP3120UnnecessaryCodingComment | UTF-8 encoding declaration is unnecessary | 🛠 |
| UP010 | UnnecessaryFutureImport | Unnecessary `__future__` import `...` for target Python version | 🛠 | | UP010 | UnnecessaryFutureImport | Unnecessary `__future__` import `...` for target Python version | 🛠 |
| UP011 | UnnecessaryLRUCacheParams | Unnecessary parameters to `functools.lru_cache` | 🛠 | | UP011 | LRUCacheWithoutParameters | Unnecessary parameters to `functools.lru_cache` | 🛠 |
| UP012 | UnnecessaryEncodeUTF8 | Unnecessary call to `encode` as UTF-8 | 🛠 | | UP012 | UnnecessaryEncodeUTF8 | Unnecessary call to `encode` as UTF-8 | 🛠 |
| UP013 | ConvertTypedDictFunctionalToClass | Convert `...` from `TypedDict` functional to class syntax | 🛠 | | UP013 | ConvertTypedDictFunctionalToClass | Convert `...` from `TypedDict` functional to class syntax | 🛠 |
| UP014 | ConvertNamedTupleFunctionalToClass | Convert `...` from `NamedTuple` functional to class syntax | 🛠 | | UP014 | ConvertNamedTupleFunctionalToClass | Convert `...` from `NamedTuple` functional to class syntax | 🛠 |
@ -726,6 +726,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
| UP029 | UnnecessaryBuiltinImport | Unnecessary builtin import: `...` | 🛠 | | UP029 | UnnecessaryBuiltinImport | Unnecessary builtin import: `...` | 🛠 |
| UP030 | FormatLiterals | Use implicit references for positional format fields | 🛠 | | UP030 | FormatLiterals | Use implicit references for positional format fields | 🛠 |
| UP032 | FString | Use f-string instead of `format` call | 🛠 | | UP032 | FString | Use f-string instead of `format` call | 🛠 |
| UP033 | FunctoolsCache | Use `@functools.cache` instead of `@functools.lru_cache(maxsize=None)` | 🛠 |
### pep8-naming (N) ### pep8-naming (N)

View File

@ -0,0 +1,67 @@
import functools
from functools import lru_cache
@functools.lru_cache()
def fixme():
pass
@lru_cache()
def fixme():
pass
@other_decorator
@functools.lru_cache()
def fixme():
pass
@functools.lru_cache()
@other_decorator
def fixme():
pass
@functools.lru_cache(maxsize=None)
def ok():
pass
@lru_cache(maxsize=None)
def ok():
pass
@functools.lru_cache(maxsize=64)
def ok():
pass
@lru_cache(maxsize=64)
def ok():
pass
def user_func():
pass
@lru_cache(user_func)
def ok():
pass
@lru_cache(user_func, maxsize=None)
def ok():
pass
def lru_cache(maxsize=None):
pass
@lru_cache(maxsize=None)
def ok():
pass

View File

@ -1,103 +0,0 @@
import functools
from functools import lru_cache
@lru_cache()
def fixme1():
pass
@other_deco_after
@functools.lru_cache()
def fixme2():
pass
@lru_cache(maxsize=None)
def fixme3():
pass
@functools.lru_cache(maxsize=None)
@other_deco_before
def fixme4():
pass
@lru_cache( # A
) # B
def fixme5():
pass
@lru_cache(
# A
) # B
def fixme6():
pass
@functools.lru_cache(
# A
maxsize = None) # B
def fixme7():
pass
@functools.lru_cache(
# A1
maxsize = None
# A2
) # B
def fixme8():
pass
@functools.lru_cache(
# A1
maxsize =
None
# A2
)
def fixme9():
pass
@functools.lru_cache(
# A1
maxsize =
None
# A2
)
def fixme10():
pass
@lru_cache
def correct1():
pass
@functools.lru_cache
def correct2():
pass
@functoools.lru_cache(maxsize=64)
def correct3():
pass
def user_func():
pass
@lru_cache(user_func)
def correct4():
pass
@lru_cache(user_func, maxsize=None)
def correct5():
pass

View File

@ -1,15 +0,0 @@
import functools
def lru_cache(maxsize=None):
pass
@lru_cache()
def dont_fixme():
pass
@lru_cache(maxsize=None)
def dont_fixme():
pass

View File

@ -0,0 +1,67 @@
import functools
from functools import lru_cache
@functools.lru_cache(maxsize=None)
def fixme():
pass
@lru_cache(maxsize=None)
def fixme():
pass
@other_decorator
@functools.lru_cache(maxsize=None)
def fixme():
pass
@functools.lru_cache(maxsize=None)
@other_decorator
def fixme():
pass
@functools.lru_cache()
def ok():
pass
@lru_cache()
def ok():
pass
@functools.lru_cache(maxsize=64)
def ok():
pass
@lru_cache(maxsize=64)
def ok():
pass
def user_func():
pass
@lru_cache(user_func)
def ok():
pass
@lru_cache(user_func, maxsize=None)
def ok():
pass
def lru_cache(maxsize=None):
pass
@lru_cache(maxsize=None)
def ok():
pass

View File

@ -1688,6 +1688,7 @@
"UP03", "UP03",
"UP030", "UP030",
"UP032", "UP032",
"UP033",
"W", "W",
"W2", "W2",
"W29", "W29",

View File

@ -499,7 +499,12 @@ where
if self.settings.rules.enabled(&RuleCode::UP011) if self.settings.rules.enabled(&RuleCode::UP011)
&& self.settings.target_version >= PythonVersion::Py38 && self.settings.target_version >= PythonVersion::Py38
{ {
pyupgrade::rules::unnecessary_lru_cache_params(self, decorator_list); pyupgrade::rules::lru_cache_without_parameters(self, decorator_list);
}
if self.settings.rules.enabled(&RuleCode::UP033)
&& self.settings.target_version >= PythonVersion::Py39
{
pyupgrade::rules::functools_cache(self, decorator_list);
} }
if self.settings.rules.enabled(&RuleCode::B018) { if self.settings.rules.enabled(&RuleCode::B018) {

View File

@ -232,7 +232,7 @@ ruff_macros::define_rule_mapping!(
UP008 => violations::SuperCallWithParameters, UP008 => violations::SuperCallWithParameters,
UP009 => violations::PEP3120UnnecessaryCodingComment, UP009 => violations::PEP3120UnnecessaryCodingComment,
UP010 => violations::UnnecessaryFutureImport, UP010 => violations::UnnecessaryFutureImport,
UP011 => violations::UnnecessaryLRUCacheParams, UP011 => violations::LRUCacheWithoutParameters,
UP012 => violations::UnnecessaryEncodeUTF8, UP012 => violations::UnnecessaryEncodeUTF8,
UP013 => violations::ConvertTypedDictFunctionalToClass, UP013 => violations::ConvertTypedDictFunctionalToClass,
UP014 => violations::ConvertNamedTupleFunctionalToClass, UP014 => violations::ConvertNamedTupleFunctionalToClass,
@ -253,6 +253,7 @@ ruff_macros::define_rule_mapping!(
UP029 => violations::UnnecessaryBuiltinImport, UP029 => violations::UnnecessaryBuiltinImport,
UP030 => violations::FormatLiterals, UP030 => violations::FormatLiterals,
UP032 => violations::FString, UP032 => violations::FString,
UP033 => violations::FunctoolsCache,
// pydocstyle // pydocstyle
D100 => violations::PublicModule, D100 => violations::PublicModule,
D101 => violations::PublicClass, D101 => violations::PublicClass,

View File

@ -30,8 +30,7 @@ mod tests {
#[test_case(RuleCode::UP009, Path::new("UP009_3.py"); "UP009_3")] #[test_case(RuleCode::UP009, Path::new("UP009_3.py"); "UP009_3")]
#[test_case(RuleCode::UP009, Path::new("UP009_4.py"); "UP009_4")] #[test_case(RuleCode::UP009, Path::new("UP009_4.py"); "UP009_4")]
#[test_case(RuleCode::UP010, Path::new("UP010.py"); "UP010")] #[test_case(RuleCode::UP010, Path::new("UP010.py"); "UP010")]
#[test_case(RuleCode::UP011, Path::new("UP011_0.py"); "UP011_0")] #[test_case(RuleCode::UP011, Path::new("UP011.py"); "UP011")]
#[test_case(RuleCode::UP011, Path::new("UP011_1.py"); "UP011_1")]
#[test_case(RuleCode::UP012, Path::new("UP012.py"); "UP012")] #[test_case(RuleCode::UP012, Path::new("UP012.py"); "UP012")]
#[test_case(RuleCode::UP013, Path::new("UP013.py"); "UP013")] #[test_case(RuleCode::UP013, Path::new("UP013.py"); "UP013")]
#[test_case(RuleCode::UP014, Path::new("UP014.py"); "UP014")] #[test_case(RuleCode::UP014, Path::new("UP014.py"); "UP014")]
@ -55,6 +54,7 @@ mod tests {
#[test_case(RuleCode::UP030, Path::new("UP030_0.py"); "UP030_0")] #[test_case(RuleCode::UP030, Path::new("UP030_0.py"); "UP030_0")]
#[test_case(RuleCode::UP030, Path::new("UP030_1.py"); "UP030_1")] #[test_case(RuleCode::UP030, Path::new("UP030_1.py"); "UP030_1")]
#[test_case(RuleCode::UP032, Path::new("UP032.py"); "UP032")] #[test_case(RuleCode::UP032, Path::new("UP032.py"); "UP032")]
#[test_case(RuleCode::UP033, Path::new("UP033.py"); "UP033")]
fn rules(rule_code: RuleCode, path: &Path) -> Result<()> { fn rules(rule_code: RuleCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy()); let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
let diagnostics = test_path( let diagnostics = test_path(

View File

@ -0,0 +1,63 @@
use rustpython_ast::{Constant, ExprKind, KeywordData};
use rustpython_parser::ast::Expr;
use crate::ast::helpers::{create_expr, unparse_expr};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::fix::Fix;
use crate::registry::{Diagnostic, RuleCode};
use crate::violations;
/// UP033
pub fn functools_cache(checker: &mut Checker, decorator_list: &[Expr]) {
for expr in decorator_list.iter() {
let ExprKind::Call {
func,
args,
keywords,
} = &expr.node else {
continue;
};
// Look for, e.g., `import functools; @functools.lru_cache(maxsize=None)`.
if args.is_empty()
&& keywords.len() == 1
&& checker
.resolve_call_path(func)
.map_or(false, |call_path| call_path == ["functools", "lru_cache"])
{
let KeywordData { arg, value } = &keywords[0].node;
if arg.as_ref().map_or(false, |arg| arg == "maxsize")
&& matches!(
value.node,
ExprKind::Constant {
value: Constant::None,
kind: None,
}
)
{
let mut diagnostic = Diagnostic::new(
violations::FunctoolsCache,
Range::new(func.end_location.unwrap(), expr.end_location.unwrap()),
);
if checker.patch(&RuleCode::UP033) {
if let ExprKind::Attribute { value, ctx, .. } = &func.node {
diagnostic.amend(Fix::replacement(
unparse_expr(
&create_expr(ExprKind::Attribute {
value: value.clone(),
attr: "cache".to_string(),
ctx: ctx.clone(),
}),
checker.stylist,
),
expr.location,
expr.end_location.unwrap(),
));
}
}
checker.diagnostics.push(diagnostic);
}
}
}
}

View File

@ -0,0 +1,43 @@
use rustpython_ast::ExprKind;
use rustpython_parser::ast::Expr;
use crate::ast::helpers::unparse_expr;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::fix::Fix;
use crate::registry::{Diagnostic, RuleCode};
use crate::violations;
/// UP011
pub fn lru_cache_without_parameters(checker: &mut Checker, decorator_list: &[Expr]) {
for expr in decorator_list.iter() {
let ExprKind::Call {
func,
args,
keywords,
} = &expr.node else {
continue;
};
// Look for, e.g., `import functools; @functools.lru_cache()`.
if args.is_empty()
&& keywords.is_empty()
&& checker
.resolve_call_path(func)
.map_or(false, |call_path| call_path == ["functools", "lru_cache"])
{
let mut diagnostic = Diagnostic::new(
violations::LRUCacheWithoutParameters,
Range::new(func.end_location.unwrap(), expr.end_location.unwrap()),
);
if checker.patch(&RuleCode::UP011) {
diagnostic.amend(Fix::replacement(
unparse_expr(func, checker.stylist),
expr.location,
expr.end_location.unwrap(),
));
}
checker.diagnostics.push(diagnostic);
}
}
}

View File

@ -4,6 +4,8 @@ pub(crate) use datetime_utc_alias::datetime_utc_alias;
pub(crate) use deprecated_unittest_alias::deprecated_unittest_alias; pub(crate) use deprecated_unittest_alias::deprecated_unittest_alias;
pub(crate) use f_strings::f_strings; pub(crate) use f_strings::f_strings;
pub(crate) use format_literals::format_literals; pub(crate) use format_literals::format_literals;
pub(crate) use functools_cache::functools_cache;
pub(crate) use lru_cache_without_parameters::lru_cache_without_parameters;
pub(crate) use native_literals::native_literals; pub(crate) use native_literals::native_literals;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
pub(crate) use open_alias::open_alias; pub(crate) use open_alias::open_alias;
@ -25,7 +27,6 @@ pub(crate) use typing_text_str_alias::typing_text_str_alias;
pub(crate) use unnecessary_builtin_import::unnecessary_builtin_import; pub(crate) use unnecessary_builtin_import::unnecessary_builtin_import;
pub(crate) use unnecessary_encode_utf8::unnecessary_encode_utf8; pub(crate) use unnecessary_encode_utf8::unnecessary_encode_utf8;
pub(crate) use unnecessary_future_import::unnecessary_future_import; pub(crate) use unnecessary_future_import::unnecessary_future_import;
pub(crate) use unnecessary_lru_cache_params::unnecessary_lru_cache_params;
pub(crate) use unpack_list_comprehension::unpack_list_comprehension; pub(crate) use unpack_list_comprehension::unpack_list_comprehension;
pub(crate) use use_pep585_annotation::use_pep585_annotation; pub(crate) use use_pep585_annotation::use_pep585_annotation;
pub(crate) use use_pep604_annotation::use_pep604_annotation; pub(crate) use use_pep604_annotation::use_pep604_annotation;
@ -44,6 +45,8 @@ mod datetime_utc_alias;
mod deprecated_unittest_alias; mod deprecated_unittest_alias;
mod f_strings; mod f_strings;
mod format_literals; mod format_literals;
mod functools_cache;
mod lru_cache_without_parameters;
mod native_literals; mod native_literals;
mod open_alias; mod open_alias;
mod os_error_alias; mod os_error_alias;
@ -61,7 +64,6 @@ mod typing_text_str_alias;
mod unnecessary_builtin_import; mod unnecessary_builtin_import;
mod unnecessary_encode_utf8; mod unnecessary_encode_utf8;
mod unnecessary_future_import; mod unnecessary_future_import;
mod unnecessary_lru_cache_params;
mod unpack_list_comprehension; mod unpack_list_comprehension;
mod use_pep585_annotation; mod use_pep585_annotation;
mod use_pep604_annotation; mod use_pep604_annotation;

View File

@ -1,88 +0,0 @@
use rustpython_ast::{Constant, ExprKind, KeywordData};
use rustpython_parser::ast::Expr;
use crate::ast::helpers::{create_expr, unparse_expr};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::fix::Fix;
use crate::registry::{Diagnostic, RuleCode};
use crate::settings::types::PythonVersion;
use crate::violations;
/// UP011
pub fn unnecessary_lru_cache_params(checker: &mut Checker, decorator_list: &[Expr]) {
for expr in decorator_list.iter() {
let ExprKind::Call {
func,
args,
keywords,
} = &expr.node else {
continue;
};
// Look for, e.g., `import functools; @functools.lru_cache`.
if !(args.is_empty()
&& checker
.resolve_call_path(func)
.map_or(false, |call_path| call_path == ["functools", "lru_cache"]))
{
continue;
}
// Ex) `functools.lru_cache()`
if keywords.is_empty() {
let mut diagnostic = Diagnostic::new(
violations::UnnecessaryLRUCacheParams,
Range::new(func.end_location.unwrap(), expr.end_location.unwrap()),
);
if checker.patch(&RuleCode::UP011) {
diagnostic.amend(Fix::replacement(
unparse_expr(func, checker.stylist),
expr.location,
expr.end_location.unwrap(),
));
}
checker.diagnostics.push(diagnostic);
}
// Ex) `functools.lru_cache(maxsize=None)`
if !(checker.settings.target_version >= PythonVersion::Py39 && keywords.len() == 1) {
continue;
}
let KeywordData { arg, value } = &keywords[0].node;
if !(arg.as_ref().map_or(false, |arg| arg == "maxsize")
&& matches!(
value.node,
ExprKind::Constant {
value: Constant::None,
kind: None,
}
))
{
continue;
}
let mut diagnostic = Diagnostic::new(
violations::UnnecessaryLRUCacheParams,
Range::new(func.end_location.unwrap(), expr.end_location.unwrap()),
);
if checker.patch(&RuleCode::UP011) {
if let ExprKind::Attribute { value, ctx, .. } = &func.node {
diagnostic.amend(Fix::replacement(
unparse_expr(
&create_expr(ExprKind::Attribute {
value: value.clone(),
attr: "cache".to_string(),
ctx: ctx.clone(),
}),
checker.stylist,
),
expr.location,
expr.end_location.unwrap(),
));
}
}
checker.diagnostics.push(diagnostic);
}
}

View File

@ -0,0 +1,73 @@
---
source: src/rules/pyupgrade/mod.rs
expression: diagnostics
---
- kind:
LRUCacheWithoutParameters: ~
location:
row: 5
column: 20
end_location:
row: 5
column: 22
fix:
content: functools.lru_cache
location:
row: 5
column: 1
end_location:
row: 5
column: 22
parent: ~
- kind:
LRUCacheWithoutParameters: ~
location:
row: 10
column: 10
end_location:
row: 10
column: 12
fix:
content: lru_cache
location:
row: 10
column: 1
end_location:
row: 10
column: 12
parent: ~
- kind:
LRUCacheWithoutParameters: ~
location:
row: 16
column: 20
end_location:
row: 16
column: 22
fix:
content: functools.lru_cache
location:
row: 16
column: 1
end_location:
row: 16
column: 22
parent: ~
- kind:
LRUCacheWithoutParameters: ~
location:
row: 21
column: 20
end_location:
row: 21
column: 22
fix:
content: functools.lru_cache
location:
row: 21
column: 1
end_location:
row: 21
column: 22
parent: ~

View File

@ -1,168 +0,0 @@
---
source: src/rules/pyupgrade/mod.rs
expression: diagnostics
---
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 5
column: 10
end_location:
row: 5
column: 12
fix:
content: lru_cache
location:
row: 5
column: 1
end_location:
row: 5
column: 12
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 11
column: 20
end_location:
row: 11
column: 22
fix:
content: functools.lru_cache
location:
row: 11
column: 1
end_location:
row: 11
column: 22
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 16
column: 10
end_location:
row: 16
column: 24
fix: ~
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 21
column: 20
end_location:
row: 21
column: 34
fix:
content: functools.cache
location:
row: 21
column: 1
end_location:
row: 21
column: 34
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 27
column: 10
end_location:
row: 28
column: 1
fix:
content: lru_cache
location:
row: 27
column: 1
end_location:
row: 28
column: 1
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 33
column: 10
end_location:
row: 35
column: 1
fix:
content: lru_cache
location:
row: 33
column: 1
end_location:
row: 35
column: 1
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 40
column: 20
end_location:
row: 42
column: 19
fix:
content: functools.cache
location:
row: 40
column: 1
end_location:
row: 42
column: 19
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 47
column: 20
end_location:
row: 51
column: 1
fix:
content: functools.cache
location:
row: 47
column: 1
end_location:
row: 51
column: 1
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 56
column: 20
end_location:
row: 62
column: 1
fix:
content: functools.cache
location:
row: 56
column: 1
end_location:
row: 62
column: 1
parent: ~
- kind:
UnnecessaryLRUCacheParams: ~
location:
row: 67
column: 20
end_location:
row: 72
column: 1
fix:
content: functools.cache
location:
row: 67
column: 1
end_location:
row: 72
column: 1
parent: ~

View File

@ -1,6 +0,0 @@
---
source: src/rules/pyupgrade/mod.rs
expression: diagnostics
---
[]

View File

@ -0,0 +1,66 @@
---
source: src/rules/pyupgrade/mod.rs
expression: diagnostics
---
- kind:
FunctoolsCache: ~
location:
row: 5
column: 20
end_location:
row: 5
column: 34
fix:
content: functools.cache
location:
row: 5
column: 1
end_location:
row: 5
column: 34
parent: ~
- kind:
FunctoolsCache: ~
location:
row: 10
column: 10
end_location:
row: 10
column: 24
fix: ~
parent: ~
- kind:
FunctoolsCache: ~
location:
row: 16
column: 20
end_location:
row: 16
column: 34
fix:
content: functools.cache
location:
row: 16
column: 1
end_location:
row: 16
column: 34
parent: ~
- kind:
FunctoolsCache: ~
location:
row: 21
column: 20
end_location:
row: 21
column: 34
fix:
content: functools.cache
location:
row: 21
column: 1
end_location:
row: 21
column: 34
parent: ~

View File

@ -3396,9 +3396,9 @@ impl AlwaysAutofixableViolation for UnnecessaryFutureImport {
} }
define_violation!( define_violation!(
pub struct UnnecessaryLRUCacheParams; pub struct LRUCacheWithoutParameters;
); );
impl AlwaysAutofixableViolation for UnnecessaryLRUCacheParams { impl AlwaysAutofixableViolation for LRUCacheWithoutParameters {
fn message(&self) -> String { fn message(&self) -> String {
"Unnecessary parameters to `functools.lru_cache`".to_string() "Unnecessary parameters to `functools.lru_cache`".to_string()
} }
@ -3408,7 +3408,7 @@ impl AlwaysAutofixableViolation for UnnecessaryLRUCacheParams {
} }
fn placeholder() -> Self { fn placeholder() -> Self {
UnnecessaryLRUCacheParams LRUCacheWithoutParameters
} }
} }
@ -3814,6 +3814,23 @@ impl AlwaysAutofixableViolation for FString {
} }
} }
define_violation!(
pub struct FunctoolsCache;
);
impl AlwaysAutofixableViolation for FunctoolsCache {
fn message(&self) -> String {
"Use `@functools.cache` instead of `@functools.lru_cache(maxsize=None)`".to_string()
}
fn autofix_title(&self) -> String {
"Rewrite with `@functools.cache".to_string()
}
fn placeholder() -> Self {
FunctoolsCache
}
}
// pydocstyle // pydocstyle
define_violation!( define_violation!(