From ce0800fccf7c7f712ff36d98140e7d9946329136 Mon Sep 17 00:00:00 2001 From: yunchi Date: Wed, 7 May 2025 11:34:34 -0700 Subject: [PATCH] [`pylint`] add fix safety section (`PLC2801`) (#17825) parent: #15584 fix was introduced at: #9587 reasoning: #9572 --- .../pylint/rules/unnecessary_dunder_call.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs index 28163c94fc..6da31dbd85 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs @@ -15,6 +15,34 @@ use ruff_python_ast::PythonVersion; /// Dunder names are not meant to be called explicitly and, in most cases, can /// be replaced with builtins or operators. /// +/// ## Fix safety +/// This fix is always unsafe. When replacing dunder method calls with operators +/// or builtins, the behavior can change in the following ways: +/// +/// 1. Types may implement only a subset of related dunder methods. Calling a +/// missing dunder method directly returns `NotImplemented`, but using the +/// equivalent operator raises a `TypeError`. +/// ```python +/// class C: pass +/// c = C() +/// c.__gt__(1) # before fix: NotImplemented +/// c > 1 # after fix: raises TypeError +/// ``` +/// 2. Instance-assigned dunder methods are ignored by operators and builtins. +/// ```python +/// class C: pass +/// c = C() +/// c.__bool__ = lambda: False +/// c.__bool__() # before fix: False +/// bool(c) # after fix: True +/// ``` +/// +/// 3. Even with built-in types, behavior can differ. +/// ```python +/// (1).__gt__(1.0) # before fix: NotImplemented +/// 1 > 1.0 # after fix: False +/// ``` +/// /// ## Example /// ```python /// three = (3.0).__str__()