[flake8-bugbear] Mark autofix for B004 as unsafe if the hasattr call expr contains comments (#18755)

This commit is contained in:
Victor Hugo Gomes 2025-06-19 07:46:53 -03:00 committed by GitHub
parent 4c8d612120
commit f7a741a99e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 2 deletions

View file

@ -29,3 +29,13 @@ def this_is_fine():
o = object()
if callable(o):
print("Ooh, this is actually callable.")
# https://github.com/astral-sh/ruff/issues/18741
# The autofix for this is unsafe due to the comments.
hasattr(
# comment 1
obj, # comment 2
# comment 3
"__call__", # comment 4
# comment 5
)

View file

@ -1,3 +1,4 @@
use ruff_diagnostics::Applicability;
use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_python_ast::{self as ast, Expr};
use ruff_text_size::Ranged;
@ -26,6 +27,21 @@ use crate::{Edit, Fix, FixAvailability, Violation};
/// callable(obj)
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as unsafe if there's comments in the `hasattr` call
/// expression, as comments may be removed.
///
/// For example, the fix would be marked as unsafe in the following case:
/// ```python
/// hasattr(
/// # comment 1
/// obj, # comment 2
/// # comment 3
/// "__call__", # comment 4
/// # comment 5
/// )
/// ```
///
/// ## References
/// - [Python documentation: `callable`](https://docs.python.org/3/library/functions.html#callable)
/// - [Python documentation: `hasattr`](https://docs.python.org/3/library/functions.html#hasattr)
@ -84,7 +100,15 @@ pub(crate) fn unreliable_callable_check(
format!("{binding}({})", checker.locator().slice(obj)),
expr.range(),
);
Ok(Fix::safe_edits(binding_edit, import_edit))
Ok(Fix::applicable_edits(
binding_edit,
import_edit,
if checker.comment_ranges().intersects(expr.range()) {
Applicability::Unsafe
} else {
Applicability::Safe
},
))
});
}
}

View file

@ -86,3 +86,31 @@ B004.py:24:8: B004 [*] Using `hasattr(x, "__call__")` to test if x is callable i
25 26 | print("STILL a bug!")
26 27 |
27 28 |
B004.py:35:1: B004 [*] Using `hasattr(x, "__call__")` to test if x is callable is unreliable. Use `callable(x)` for consistent results.
|
33 | # https://github.com/astral-sh/ruff/issues/18741
34 | # The autofix for this is unsafe due to the comments.
35 | / hasattr(
36 | | # comment 1
37 | | obj, # comment 2
38 | | # comment 3
39 | | "__call__", # comment 4
40 | | # comment 5
41 | | )
| |_^ B004
|
= help: Replace with `callable()`
Unsafe fix
32 32 |
33 33 | # https://github.com/astral-sh/ruff/issues/18741
34 34 | # The autofix for this is unsafe due to the comments.
35 |-hasattr(
36 |- # comment 1
37 |- obj, # comment 2
38 |- # comment 3
39 |- "__call__", # comment 4
40 |- # comment 5
41 |-)
35 |+callable(obj)