Skip to content

Commit e3f34b8

Browse files
authored
[ruff] Mark autofix for RUF052 as always unsafe (#14824)
1 parent ab26d9c commit e3f34b8

3 files changed

+46
-31
lines changed

crates/ruff_linter/src/rules/ruff/rules/used_dummy_variable.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ use crate::{checkers::ast::Checker, renamer::Renamer};
1616
/// By default, "dummy variables" are any variables with names that start with leading
1717
/// underscores. However, this is customisable using the [`lint.dummy-variable-rgx`] setting).
1818
///
19-
/// Dunder variables are ignored by this rule, as are variables named `_`.
20-
///
2119
/// ## Why is this bad?
2220
/// Marking a variable with a leading underscore conveys that it is intentionally unused within the function or method.
2321
/// When these variables are later referenced in the code, it causes confusion and potential misunderstandings about
@@ -27,18 +25,25 @@ use crate::{checkers::ast::Checker, renamer::Renamer};
2725
/// Sometimes leading underscores are used to avoid variables shadowing other variables, Python builtins, or Python
2826
/// keywords. However, [PEP 8] recommends to use trailing underscores for this rather than leading underscores.
2927
///
28+
/// Dunder variables are ignored by this rule, as are variables named `_`.
29+
/// Only local variables in function scopes are flagged by the rule.
30+
///
3031
/// ## Example
3132
/// ```python
3233
/// def function():
3334
/// _variable = 3
34-
/// return _variable + 1
35+
/// # important: avoid shadowing the builtin `id()` function!
36+
/// _id = 4
37+
/// return _variable + _id
3538
/// ```
3639
///
3740
/// Use instead:
3841
/// ```python
3942
/// def function():
4043
/// variable = 3
41-
/// return variable + 1
44+
/// # important: avoid shadowing the builtin `id()` function!
45+
/// id_ = 4
46+
/// return variable + id_
4247
/// ```
4348
///
4449
/// ## Fix availability
@@ -47,6 +52,16 @@ use crate::{checkers::ast::Checker, renamer::Renamer};
4752
/// would not shadow any other known variables already accessible from the scope
4853
/// in which the variable is defined.
4954
///
55+
/// ## Fix safety
56+
/// This rule's fix is marked as unsafe.
57+
///
58+
/// For this rule's fix, Ruff renames the variable and fixes up all known references to
59+
/// it so they point to the renamed variable. However, some renamings also require other
60+
/// changes such as different arguments to constructor calls or alterations to comments.
61+
/// Ruff is aware of some of these cases: `_T = TypeVar("_T")` will be fixed to
62+
/// `T = TypeVar("T")` if the `_T` binding is flagged by this rule. However, in general,
63+
/// cases like these are hard to detect and hard to automatically fix.
64+
///
5065
/// ## Options
5166
/// - [`lint.dummy-variable-rgx`]
5267
///
@@ -146,7 +161,7 @@ pub(crate) fn used_dummy_variable(checker: &Checker, binding: &Binding) -> Optio
146161
if let Some(fix) = get_possible_fix(name, shadowed_kind, binding.scope, checker) {
147162
diagnostic.try_set_fix(|| {
148163
Renamer::rename(name, &fix, scope, semantic, checker.stylist())
149-
.map(|(edit, rest)| Fix::safe_edits(edit, rest))
164+
.map(|(edit, rest)| Fix::unsafe_edits(edit, rest))
150165
});
151166
}
152167
}

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF052_RUF052.py.snap

+13-13
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ RUF052.py:77:9: RUF052 [*] Local dummy variable `_var` is accessed
1111
|
1212
= help: Remove leading underscores
1313

14-
Safe fix
14+
Unsafe fix
1515
74 74 |
1616
75 75 | class Class_:
1717
76 76 | def fun(self):
@@ -32,7 +32,7 @@ RUF052.py:84:5: RUF052 [*] Local dummy variable `_list` is accessed
3232
|
3333
= help: Prefer using trailing underscores to avoid shadowing a built-in
3434

35-
Safe fix
35+
Unsafe fix
3636
81 81 | return _var
3737
82 82 |
3838
83 83 | def fun():
@@ -54,7 +54,7 @@ RUF052.py:91:5: RUF052 [*] Local dummy variable `_x` is accessed
5454
|
5555
= help: Prefer using trailing underscores to avoid shadowing a variable
5656

57-
Safe fix
57+
Unsafe fix
5858
88 88 |
5959
89 89 | def fun():
6060
90 90 | global x
@@ -77,7 +77,7 @@ RUF052.py:98:5: RUF052 [*] Local dummy variable `_x` is accessed
7777
|
7878
= help: Prefer using trailing underscores to avoid shadowing a variable
7979

80-
Safe fix
80+
Unsafe fix
8181
95 95 | x = "outer"
8282
96 96 | def bar():
8383
97 97 | nonlocal x
@@ -99,7 +99,7 @@ RUF052.py:105:5: RUF052 [*] Local dummy variable `_x` is accessed
9999
|
100100
= help: Prefer using trailing underscores to avoid shadowing a variable
101101

102-
Safe fix
102+
Unsafe fix
103103
102 102 |
104104
103 103 | def fun():
105105
104 104 | x = "local"
@@ -160,7 +160,7 @@ RUF052.py:138:5: RUF052 [*] Local dummy variable `_P` is accessed
160160
|
161161
= help: Remove leading underscores
162162

163-
Safe fix
163+
Unsafe fix
164164
135 135 | from enum import Enum
165165
136 136 | from collections import namedtuple
166166
137 137 |
@@ -186,7 +186,7 @@ RUF052.py:139:5: RUF052 [*] Local dummy variable `_T` is accessed
186186
|
187187
= help: Remove leading underscores
188188

189-
Safe fix
189+
Unsafe fix
190190
136 136 | from collections import namedtuple
191191
137 137 |
192192
138 138 | _P = ParamSpec("_P")
@@ -213,7 +213,7 @@ RUF052.py:140:5: RUF052 [*] Local dummy variable `_NT` is accessed
213213
|
214214
= help: Remove leading underscores
215215

216-
Safe fix
216+
Unsafe fix
217217
137 137 |
218218
138 138 | _P = ParamSpec("_P")
219219
139 139 | _T = TypeVar(name="_T", covariant=True, bound=int|str)
@@ -239,7 +239,7 @@ RUF052.py:141:5: RUF052 [*] Local dummy variable `_E` is accessed
239239
|
240240
= help: Remove leading underscores
241241

242-
Safe fix
242+
Unsafe fix
243243
138 138 | _P = ParamSpec("_P")
244244
139 139 | _T = TypeVar(name="_T", covariant=True, bound=int|str)
245245
140 140 | _NT = NamedTuple("_NT", [("foo", int)])
@@ -264,7 +264,7 @@ RUF052.py:142:5: RUF052 [*] Local dummy variable `_NT2` is accessed
264264
|
265265
= help: Remove leading underscores
266266

267-
Safe fix
267+
Unsafe fix
268268
139 139 | _T = TypeVar(name="_T", covariant=True, bound=int|str)
269269
140 140 | _NT = NamedTuple("_NT", [("foo", int)])
270270
141 141 | _E = Enum("_E", ["a", "b", "c"])
@@ -288,7 +288,7 @@ RUF052.py:143:5: RUF052 [*] Local dummy variable `_NT3` is accessed
288288
|
289289
= help: Remove leading underscores
290290

291-
Safe fix
291+
Unsafe fix
292292
140 140 | _NT = NamedTuple("_NT", [("foo", int)])
293293
141 141 | _E = Enum("_E", ["a", "b", "c"])
294294
142 142 | _NT2 = namedtuple("_NT2", ['x', 'y', 'z'])
@@ -310,7 +310,7 @@ RUF052.py:144:5: RUF052 [*] Local dummy variable `_DynamicClass` is accessed
310310
|
311311
= help: Remove leading underscores
312312

313-
Safe fix
313+
Unsafe fix
314314
141 141 | _E = Enum("_E", ["a", "b", "c"])
315315
142 142 | _NT2 = namedtuple("_NT2", ['x', 'y', 'z'])
316316
143 143 | _NT3 = namedtuple(typename="_NT3", field_names=['x', 'y', 'z'])
@@ -332,7 +332,7 @@ RUF052.py:145:5: RUF052 [*] Local dummy variable `_NotADynamicClass` is accessed
332332
|
333333
= help: Remove leading underscores
334334

335-
Safe fix
335+
Unsafe fix
336336
142 142 | _NT2 = namedtuple("_NT2", ['x', 'y', 'z'])
337337
143 143 | _NT3 = namedtuple(typename="_NT3", field_names=['x', 'y', 'z'])
338338
144 144 | _DynamicClass = type("_DynamicClass", (), {})

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__custom_dummy_var_regexp_preset__RUF052_RUF052.py_1.snap

+13-13
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ RUF052.py:77:9: RUF052 [*] Local dummy variable `_var` is accessed
1111
|
1212
= help: Remove leading underscores
1313

14-
Safe fix
14+
Unsafe fix
1515
74 74 |
1616
75 75 | class Class_:
1717
76 76 | def fun(self):
@@ -32,7 +32,7 @@ RUF052.py:84:5: RUF052 [*] Local dummy variable `_list` is accessed
3232
|
3333
= help: Prefer using trailing underscores to avoid shadowing a built-in
3434

35-
Safe fix
35+
Unsafe fix
3636
81 81 | return _var
3737
82 82 |
3838
83 83 | def fun():
@@ -54,7 +54,7 @@ RUF052.py:91:5: RUF052 [*] Local dummy variable `_x` is accessed
5454
|
5555
= help: Prefer using trailing underscores to avoid shadowing a variable
5656

57-
Safe fix
57+
Unsafe fix
5858
88 88 |
5959
89 89 | def fun():
6060
90 90 | global x
@@ -77,7 +77,7 @@ RUF052.py:98:5: RUF052 [*] Local dummy variable `_x` is accessed
7777
|
7878
= help: Prefer using trailing underscores to avoid shadowing a variable
7979

80-
Safe fix
80+
Unsafe fix
8181
95 95 | x = "outer"
8282
96 96 | def bar():
8383
97 97 | nonlocal x
@@ -99,7 +99,7 @@ RUF052.py:105:5: RUF052 [*] Local dummy variable `_x` is accessed
9999
|
100100
= help: Prefer using trailing underscores to avoid shadowing a variable
101101

102-
Safe fix
102+
Unsafe fix
103103
102 102 |
104104
103 103 | def fun():
105105
104 104 | x = "local"
@@ -160,7 +160,7 @@ RUF052.py:138:5: RUF052 [*] Local dummy variable `_P` is accessed
160160
|
161161
= help: Remove leading underscores
162162

163-
Safe fix
163+
Unsafe fix
164164
135 135 | from enum import Enum
165165
136 136 | from collections import namedtuple
166166
137 137 |
@@ -186,7 +186,7 @@ RUF052.py:139:5: RUF052 [*] Local dummy variable `_T` is accessed
186186
|
187187
= help: Remove leading underscores
188188

189-
Safe fix
189+
Unsafe fix
190190
136 136 | from collections import namedtuple
191191
137 137 |
192192
138 138 | _P = ParamSpec("_P")
@@ -213,7 +213,7 @@ RUF052.py:140:5: RUF052 [*] Local dummy variable `_NT` is accessed
213213
|
214214
= help: Remove leading underscores
215215

216-
Safe fix
216+
Unsafe fix
217217
137 137 |
218218
138 138 | _P = ParamSpec("_P")
219219
139 139 | _T = TypeVar(name="_T", covariant=True, bound=int|str)
@@ -239,7 +239,7 @@ RUF052.py:141:5: RUF052 [*] Local dummy variable `_E` is accessed
239239
|
240240
= help: Remove leading underscores
241241

242-
Safe fix
242+
Unsafe fix
243243
138 138 | _P = ParamSpec("_P")
244244
139 139 | _T = TypeVar(name="_T", covariant=True, bound=int|str)
245245
140 140 | _NT = NamedTuple("_NT", [("foo", int)])
@@ -264,7 +264,7 @@ RUF052.py:142:5: RUF052 [*] Local dummy variable `_NT2` is accessed
264264
|
265265
= help: Remove leading underscores
266266

267-
Safe fix
267+
Unsafe fix
268268
139 139 | _T = TypeVar(name="_T", covariant=True, bound=int|str)
269269
140 140 | _NT = NamedTuple("_NT", [("foo", int)])
270270
141 141 | _E = Enum("_E", ["a", "b", "c"])
@@ -288,7 +288,7 @@ RUF052.py:143:5: RUF052 [*] Local dummy variable `_NT3` is accessed
288288
|
289289
= help: Remove leading underscores
290290

291-
Safe fix
291+
Unsafe fix
292292
140 140 | _NT = NamedTuple("_NT", [("foo", int)])
293293
141 141 | _E = Enum("_E", ["a", "b", "c"])
294294
142 142 | _NT2 = namedtuple("_NT2", ['x', 'y', 'z'])
@@ -310,7 +310,7 @@ RUF052.py:144:5: RUF052 [*] Local dummy variable `_DynamicClass` is accessed
310310
|
311311
= help: Remove leading underscores
312312

313-
Safe fix
313+
Unsafe fix
314314
141 141 | _E = Enum("_E", ["a", "b", "c"])
315315
142 142 | _NT2 = namedtuple("_NT2", ['x', 'y', 'z'])
316316
143 143 | _NT3 = namedtuple(typename="_NT3", field_names=['x', 'y', 'z'])
@@ -332,7 +332,7 @@ RUF052.py:145:5: RUF052 [*] Local dummy variable `_NotADynamicClass` is accessed
332332
|
333333
= help: Remove leading underscores
334334

335-
Safe fix
335+
Unsafe fix
336336
142 142 | _NT2 = namedtuple("_NT2", ['x', 'y', 'z'])
337337
143 143 | _NT3 = namedtuple(typename="_NT3", field_names=['x', 'y', 'z'])
338338
144 144 | _DynamicClass = type("_DynamicClass", (), {})

0 commit comments

Comments
 (0)