New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[behavior-change] RUF010 delete unnecessary str()
#4958
Comments
@charliermarsh I can take this up unless you've already started working on it :) |
It’s ok, I’ve already started on it :) |
@charliermarsh @smackesey I believe this is wrong, and thus #4971 should be reverted. See below: class Test:
def __str__(self) -> str:
return "str"
def __format__(self, __format_spec: str) -> str:
return "format"
print(f"{Test()} {str(Test())} {Test()!s} {Test()!s:6} {Test():6}")
# gives: format str str str format so, i.e. even the stdlib's StrEnum will not work correctly after such an auto "fix" |
(Taking a look.) |
Can you include an example to illustrate the behavior you're describing with |
ah, sorry, my bad. I was using my "polyfill" in 3.10 which apparently doesn't match 3.11 stdlib exactly. Anyways, the Here is another example with enums in 3.11: from enum import StrEnum, Enum
class Test(StrEnum):
VALUE = "value"
class NonStrEnum(str, Enum):
VALUE = "value"
def __str__(self) -> str:
return str(self.value)
def __format__(self, format_spec: str) -> str:
return repr(self)
print(f"{Test.VALUE} {Test.VALUE!s}") # prints "value value"
print(f"{NonStrEnum.VALUE} {NonStrEnum.VALUE!s}") # prints "<NonStrEnum.VALUE: 'value'> value" |
All good. Just to be totally clear, I'm not trying to "disprove" the claim here, I think you're right that these aren't equivalent (it looks like f-strings by default are calling |
sure, no problem. Sorry for confusion with StrEnum, it just happened to be something I was (re)implementing in one of my commercial projects in 3.10 that is impacted. Can't think of an easy way to estimate the impact here, probably not a lot of custom format functions out there. But my gut tells me that introducing silent non-100%-compatible changes is not what users of Ruff expect. Since Ruff (at least originally) was supposed to lint, not "optimize" code, at least I expect it to retain everything (just like black), without any possible side-effects. Since Ruff is so fast and I bet 80%+ just have auto-fix for most of the rules, most won't even notice such a small "benign" change, which may hit at some point if custom formatting is applied... but ultimately it's your call. I personally would have to make a mental notice to either wait for a release that reverts this or remember to disable auto-fix for this rule... |
A couple quick comments (a little tight on time but want to keep this convo going, sorry for brevity):
|
no worries, that’s actually a lot of great details, appreciate you taking the time.
|
Nice catch @mishamsk, I wasn't even aware |
@smackesey thanks! |
IIUC, these two expressions are exactly equivalent:
The
str
is superfluous in (1). But instead of RUF010 removing thestr
call, instead it autofixes tof"{x!s}"
-- but the!s
here is still superfluous-- the only time it makes sense to use!s
is if there is an additional format specifier, e.g.f"{x!s:20}"
(in this casestr
is applied before the format specifier, whereas without!s
it is applied after the format specifier).So IMO RUF010 should remove
str()
unless there is a format specifier, in which case it converts to!s
.The text was updated successfully, but these errors were encountered: