mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
Allow more immutable funcs for RUF009 (#4660)
This commit is contained in:
parent
12e45498e8
commit
ccca11839a
7 changed files with 155 additions and 173 deletions
|
@ -1,6 +1,7 @@
|
|||
import collections
|
||||
import datetime as dt
|
||||
from decimal import Decimal
|
||||
from fractions import Fraction
|
||||
import logging
|
||||
import operator
|
||||
from pathlib import Path
|
||||
|
@ -158,12 +159,37 @@ def float_infinity_literal(value=float("1e999")):
|
|||
pass
|
||||
|
||||
|
||||
# But don't allow standard floats
|
||||
def float_int_is_wrong(value=float(3)):
|
||||
# Allow standard floats
|
||||
def float_int_okay(value=float(3)):
|
||||
pass
|
||||
|
||||
|
||||
def float_str_not_inf_or_nan_is_wrong(value=float("3.14")):
|
||||
def float_str_not_inf_or_nan_okay(value=float("3.14")):
|
||||
pass
|
||||
|
||||
|
||||
# Allow immutable str() value
|
||||
def str_okay(value=str("foo")):
|
||||
pass
|
||||
|
||||
|
||||
# Allow immutable bool() value
|
||||
def bool_okay(value=bool("bar")):
|
||||
pass
|
||||
|
||||
|
||||
# Allow immutable int() value
|
||||
def int_okay(value=int("12")):
|
||||
pass
|
||||
|
||||
|
||||
# Allow immutable complex() value
|
||||
def complex_okay(value=complex(1,2)):
|
||||
pass
|
||||
|
||||
|
||||
# Allow immutable Fraction() value
|
||||
def fraction_okay(value=Fraction(1,2)):
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ import datetime
|
|||
import re
|
||||
import typing
|
||||
from dataclasses import dataclass, field
|
||||
from fractions import Fraction
|
||||
from pathlib import Path
|
||||
from typing import ClassVar, NamedTuple
|
||||
|
||||
|
||||
def default_function() -> list[int]:
|
||||
return []
|
||||
|
||||
|
@ -25,7 +25,12 @@ class A:
|
|||
fine_timedelta: datetime.timedelta = datetime.timedelta(hours=7)
|
||||
fine_tuple: tuple[int] = tuple([1])
|
||||
fine_regex: re.Pattern = re.compile(r".*")
|
||||
|
||||
fine_float: float = float('-inf')
|
||||
fine_int: int = int(12)
|
||||
fine_complex: complex = complex(1, 2)
|
||||
fine_str: str = str("foo")
|
||||
fine_bool: bool = bool("foo")
|
||||
fine_fraction: Fraction = Fraction(1,2)
|
||||
|
||||
DEFAULT_IMMUTABLETYPE_FOR_ALL_DATACLASSES = ImmutableType(40)
|
||||
DEFAULT_A_FOR_ALL_DATACLASSES = A([1, 2, 3])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Arguments, Constant, Expr, Ranged};
|
||||
use rustpython_parser::ast::{self, Arguments, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
|
@ -94,10 +94,9 @@ where
|
|||
{
|
||||
fn visit_expr(&mut self, expr: &'b Expr) {
|
||||
match expr {
|
||||
Expr::Call(ast::ExprCall { func, args, .. }) => {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => {
|
||||
if !is_mutable_func(self.model, func)
|
||||
&& !is_immutable_func(self.model, func, &self.extend_immutable_calls)
|
||||
&& !is_nan_or_infinity(func, args)
|
||||
{
|
||||
self.diagnostics.push((
|
||||
FunctionCallInDefaultArgument {
|
||||
|
@ -115,29 +114,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = expr else {
|
||||
return false;
|
||||
};
|
||||
if id != "float" {
|
||||
return false;
|
||||
}
|
||||
let Some(arg) = args.first() else {
|
||||
return false;
|
||||
};
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} )= arg else {
|
||||
return false;
|
||||
};
|
||||
let lowercased = value.to_lowercase();
|
||||
matches!(
|
||||
lowercased.as_str(),
|
||||
"nan" | "+nan" | "-nan" | "inf" | "+inf" | "-inf" | "infinity" | "+infinity" | "-infinity"
|
||||
)
|
||||
}
|
||||
|
||||
/// B008
|
||||
pub(crate) fn function_call_argument_default(checker: &mut Checker, arguments: &Arguments) {
|
||||
// Map immutable calls to (module, member) format.
|
||||
|
|
|
@ -1,113 +1,113 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
---
|
||||
B006_B008.py:62:25: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:63:25: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
62 | def this_is_wrong(value=[1, 2, 3]):
|
||||
63 | def this_is_wrong(value=[1, 2, 3]):
|
||||
| ^^^^^^^^^ B006
|
||||
63 | ...
|
||||
64 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:66:30: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:67:30: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
66 | def this_is_also_wrong(value={}):
|
||||
67 | def this_is_also_wrong(value={}):
|
||||
| ^^ B006
|
||||
67 | ...
|
||||
68 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:70:20: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:71:20: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
70 | def and_this(value=set()):
|
||||
71 | def and_this(value=set()):
|
||||
| ^^^^^ B006
|
||||
71 | ...
|
||||
72 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:74:20: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:75:20: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
74 | def this_too(value=collections.OrderedDict()):
|
||||
75 | def this_too(value=collections.OrderedDict()):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
|
||||
75 | ...
|
||||
76 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:78:32: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:79:32: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
78 | async def async_this_too(value=collections.defaultdict()):
|
||||
79 | async def async_this_too(value=collections.defaultdict()):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
|
||||
79 | ...
|
||||
80 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:82:26: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:83:26: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
82 | def dont_forget_me(value=collections.deque()):
|
||||
83 | def dont_forget_me(value=collections.deque()):
|
||||
| ^^^^^^^^^^^^^^^^^^^ B006
|
||||
83 | ...
|
||||
84 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:87:46: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:88:46: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
87 | # N.B. we're also flagging the function call in the comprehension
|
||||
88 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
|
||||
88 | # N.B. we're also flagging the function call in the comprehension
|
||||
89 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ B006
|
||||
89 | pass
|
||||
90 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:91:46: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:92:46: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
91 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
|
||||
92 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ B006
|
||||
92 | pass
|
||||
93 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:95:45: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:96:45: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
95 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
|
||||
96 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ B006
|
||||
96 | pass
|
||||
97 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:99:33: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:100:33: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
99 | def kwonlyargs_mutable(*, value=[]):
|
||||
100 | def kwonlyargs_mutable(*, value=[]):
|
||||
| ^^ B006
|
||||
100 | ...
|
||||
101 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:192:20: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:218:20: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
192 | # B006 and B008
|
||||
193 | # We should handle arbitrary nesting of these B008.
|
||||
194 | def nested_combo(a=[float(3), dt.datetime.now()]):
|
||||
218 | # B006 and B008
|
||||
219 | # We should handle arbitrary nesting of these B008.
|
||||
220 | def nested_combo(a=[float(3), dt.datetime.now()]):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B006
|
||||
195 | pass
|
||||
221 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:225:27: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:251:27: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
225 | def mutable_annotations(
|
||||
226 | a: list[int] | None = [],
|
||||
251 | def mutable_annotations(
|
||||
252 | a: list[int] | None = [],
|
||||
| ^^ B006
|
||||
227 | b: Optional[Dict[int, int]] = {},
|
||||
228 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
253 | b: Optional[Dict[int, int]] = {},
|
||||
254 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
|
|
||||
|
||||
B006_B008.py:226:35: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:252:35: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
226 | def mutable_annotations(
|
||||
227 | a: list[int] | None = [],
|
||||
228 | b: Optional[Dict[int, int]] = {},
|
||||
252 | def mutable_annotations(
|
||||
253 | a: list[int] | None = [],
|
||||
254 | b: Optional[Dict[int, int]] = {},
|
||||
| ^^ B006
|
||||
229 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
230 | ):
|
||||
255 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
256 | ):
|
||||
|
|
||||
|
||||
B006_B008.py:227:62: B006 Do not use mutable data structures for argument defaults
|
||||
B006_B008.py:253:62: B006 Do not use mutable data structures for argument defaults
|
||||
|
|
||||
227 | a: list[int] | None = [],
|
||||
228 | b: Optional[Dict[int, int]] = {},
|
||||
229 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
253 | a: list[int] | None = [],
|
||||
254 | b: Optional[Dict[int, int]] = {},
|
||||
255 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
| ^^^^^ B006
|
||||
230 | ):
|
||||
231 | pass
|
||||
256 | ):
|
||||
257 | pass
|
||||
|
|
||||
|
||||
|
||||
|
|
|
@ -1,114 +1,83 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
---
|
||||
B006_B008.py:87:61: B008 Do not perform function call `range` in argument defaults
|
||||
B006_B008.py:88:61: B008 Do not perform function call `range` in argument defaults
|
||||
|
|
||||
87 | # N.B. we're also flagging the function call in the comprehension
|
||||
88 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
|
||||
88 | # N.B. we're also flagging the function call in the comprehension
|
||||
89 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
|
||||
| ^^^^^^^^ B008
|
||||
89 | pass
|
||||
90 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:91:64: B008 Do not perform function call `range` in argument defaults
|
||||
B006_B008.py:92:64: B008 Do not perform function call `range` in argument defaults
|
||||
|
|
||||
91 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
|
||||
92 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
|
||||
| ^^^^^^^^ B008
|
||||
92 | pass
|
||||
93 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:95:60: B008 Do not perform function call `range` in argument defaults
|
||||
B006_B008.py:96:60: B008 Do not perform function call `range` in argument defaults
|
||||
|
|
||||
95 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
|
||||
96 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
|
||||
| ^^^^^^^^ B008
|
||||
96 | pass
|
||||
97 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:111:39: B008 Do not perform function call `time.time` in argument defaults
|
||||
B006_B008.py:112:39: B008 Do not perform function call `time.time` in argument defaults
|
||||
|
|
||||
111 | # B008
|
||||
112 | # Flag function calls as default args (including if they are part of a sub-expression)
|
||||
113 | def in_fact_all_calls_are_wrong(value=time.time()):
|
||||
112 | # B008
|
||||
113 | # Flag function calls as default args (including if they are part of a sub-expression)
|
||||
114 | def in_fact_all_calls_are_wrong(value=time.time()):
|
||||
| ^^^^^^^^^^^ B008
|
||||
114 | ...
|
||||
115 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:115:12: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
||||
B006_B008.py:116:12: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
||||
|
|
||||
115 | def f(when=dt.datetime.now() + dt.timedelta(days=7)):
|
||||
116 | def f(when=dt.datetime.now() + dt.timedelta(days=7)):
|
||||
| ^^^^^^^^^^^^^^^^^ B008
|
||||
116 | pass
|
||||
117 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:119:30: B008 Do not perform function call in argument defaults
|
||||
B006_B008.py:120:30: B008 Do not perform function call in argument defaults
|
||||
|
|
||||
119 | def can_even_catch_lambdas(a=(lambda x: x)()):
|
||||
120 | def can_even_catch_lambdas(a=(lambda x: x)()):
|
||||
| ^^^^^^^^^^^^^^^ B008
|
||||
120 | ...
|
||||
121 | ...
|
||||
|
|
||||
|
||||
B006_B008.py:157:34: B008 Do not perform function call `float` in argument defaults
|
||||
B006_B008.py:218:31: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
||||
|
|
||||
157 | def float_infinity_literal(value=float("1e999")):
|
||||
| ^^^^^^^^^^^^^^ B008
|
||||
158 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:162:30: B008 Do not perform function call `float` in argument defaults
|
||||
|
|
||||
162 | # But don't allow standard floats
|
||||
163 | def float_int_is_wrong(value=float(3)):
|
||||
| ^^^^^^^^ B008
|
||||
164 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:166:45: B008 Do not perform function call `float` in argument defaults
|
||||
|
|
||||
166 | def float_str_not_inf_or_nan_is_wrong(value=float("3.14")):
|
||||
| ^^^^^^^^^^^^^ B008
|
||||
167 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:192:21: B008 Do not perform function call `float` in argument defaults
|
||||
|
|
||||
192 | # B006 and B008
|
||||
193 | # We should handle arbitrary nesting of these B008.
|
||||
194 | def nested_combo(a=[float(3), dt.datetime.now()]):
|
||||
| ^^^^^^^^ B008
|
||||
195 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:192:31: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
||||
|
|
||||
192 | # B006 and B008
|
||||
193 | # We should handle arbitrary nesting of these B008.
|
||||
194 | def nested_combo(a=[float(3), dt.datetime.now()]):
|
||||
218 | # B006 and B008
|
||||
219 | # We should handle arbitrary nesting of these B008.
|
||||
220 | def nested_combo(a=[float(3), dt.datetime.now()]):
|
||||
| ^^^^^^^^^^^^^^^^^ B008
|
||||
195 | pass
|
||||
221 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:198:22: B008 Do not perform function call `map` in argument defaults
|
||||
B006_B008.py:224:22: B008 Do not perform function call `map` in argument defaults
|
||||
|
|
||||
198 | # Don't flag nested B006 since we can't guarantee that
|
||||
199 | # it isn't made mutable by the outer operation.
|
||||
200 | def no_nested_b006(a=map(lambda s: s.upper(), ["a", "b", "c"])):
|
||||
224 | # Don't flag nested B006 since we can't guarantee that
|
||||
225 | # it isn't made mutable by the outer operation.
|
||||
226 | def no_nested_b006(a=map(lambda s: s.upper(), ["a", "b", "c"])):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B008
|
||||
201 | pass
|
||||
227 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:203:19: B008 Do not perform function call `random.randint` in argument defaults
|
||||
B006_B008.py:229:19: B008 Do not perform function call `random.randint` in argument defaults
|
||||
|
|
||||
203 | # B008-ception.
|
||||
204 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
|
||||
229 | # B008-ception.
|
||||
230 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B008
|
||||
205 | pass
|
||||
231 | pass
|
||||
|
|
||||
|
||||
B006_B008.py:203:37: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
||||
B006_B008.py:229:37: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
||||
|
|
||||
203 | # B008-ception.
|
||||
204 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
|
||||
229 | # B008-ception.
|
||||
230 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
|
||||
| ^^^^^^^^^^^^^^^^^ B008
|
||||
205 | pass
|
||||
231 | pass
|
||||
|
|
||||
|
||||
|
||||
|
|
|
@ -11,34 +11,34 @@ RUF009.py:19:41: RUF009 Do not perform function call `default_function` in datac
|
|||
23 | another_class_var: ClassVar[list[int]] = default_function()
|
||||
|
|
||||
|
||||
RUF009.py:36:41: RUF009 Do not perform function call `default_function` in dataclass defaults
|
||||
RUF009.py:41:41: RUF009 Do not perform function call `default_function` in dataclass defaults
|
||||
|
|
||||
36 | @dataclass
|
||||
37 | class B:
|
||||
38 | hidden_mutable_default: list[int] = default_function()
|
||||
41 | @dataclass
|
||||
42 | class B:
|
||||
43 | hidden_mutable_default: list[int] = default_function()
|
||||
| ^^^^^^^^^^^^^^^^^^ RUF009
|
||||
39 | another_dataclass: A = A()
|
||||
40 | not_optimal: ImmutableType = ImmutableType(20)
|
||||
44 | another_dataclass: A = A()
|
||||
45 | not_optimal: ImmutableType = ImmutableType(20)
|
||||
|
|
||||
|
||||
RUF009.py:37:28: RUF009 Do not perform function call `A` in dataclass defaults
|
||||
RUF009.py:42:28: RUF009 Do not perform function call `A` in dataclass defaults
|
||||
|
|
||||
37 | class B:
|
||||
38 | hidden_mutable_default: list[int] = default_function()
|
||||
39 | another_dataclass: A = A()
|
||||
42 | class B:
|
||||
43 | hidden_mutable_default: list[int] = default_function()
|
||||
44 | another_dataclass: A = A()
|
||||
| ^^^ RUF009
|
||||
40 | not_optimal: ImmutableType = ImmutableType(20)
|
||||
41 | good_variant: ImmutableType = DEFAULT_IMMUTABLETYPE_FOR_ALL_DATACLASSES
|
||||
45 | not_optimal: ImmutableType = ImmutableType(20)
|
||||
46 | good_variant: ImmutableType = DEFAULT_IMMUTABLETYPE_FOR_ALL_DATACLASSES
|
||||
|
|
||||
|
||||
RUF009.py:38:34: RUF009 Do not perform function call `ImmutableType` in dataclass defaults
|
||||
RUF009.py:43:34: RUF009 Do not perform function call `ImmutableType` in dataclass defaults
|
||||
|
|
||||
38 | hidden_mutable_default: list[int] = default_function()
|
||||
39 | another_dataclass: A = A()
|
||||
40 | not_optimal: ImmutableType = ImmutableType(20)
|
||||
43 | hidden_mutable_default: list[int] = default_function()
|
||||
44 | another_dataclass: A = A()
|
||||
45 | not_optimal: ImmutableType = ImmutableType(20)
|
||||
| ^^^^^^^^^^^^^^^^^ RUF009
|
||||
41 | good_variant: ImmutableType = DEFAULT_IMMUTABLETYPE_FOR_ALL_DATACLASSES
|
||||
42 | okay_variant: A = DEFAULT_A_FOR_ALL_DATACLASSES
|
||||
46 | good_variant: ImmutableType = DEFAULT_IMMUTABLETYPE_FOR_ALL_DATACLASSES
|
||||
47 | okay_variant: A = DEFAULT_A_FOR_ALL_DATACLASSES
|
||||
|
|
||||
|
||||
|
||||
|
|
|
@ -201,12 +201,18 @@ pub fn is_immutable_annotation(model: &SemanticModel, expr: &Expr) -> bool {
|
|||
}
|
||||
|
||||
const IMMUTABLE_FUNCS: &[&[&str]] = &[
|
||||
&["", "tuple"],
|
||||
&["", "bool"],
|
||||
&["", "complex"],
|
||||
&["", "float"],
|
||||
&["", "frozenset"],
|
||||
&["", "int"],
|
||||
&["", "str"],
|
||||
&["", "tuple"],
|
||||
&["datetime", "date"],
|
||||
&["datetime", "datetime"],
|
||||
&["datetime", "timedelta"],
|
||||
&["decimal", "Decimal"],
|
||||
&["fractions", "Fraction"],
|
||||
&["operator", "attrgetter"],
|
||||
&["operator", "itemgetter"],
|
||||
&["operator", "methodcaller"],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue