Skip to content

[ruff] implement useless if-else (RUF034)#13218

Merged
MichaReiser merged 5 commits intoastral-sh:mainfrom
lucasctl:redundant-ternary-rule
Sep 4, 2024
Merged

[ruff] implement useless if-else (RUF034)#13218
MichaReiser merged 5 commits intoastral-sh:mainfrom
lucasctl:redundant-ternary-rule

Conversation

@lucasctl
Copy link
Copy Markdown
Contributor

@lucasctl lucasctl commented Sep 2, 2024

Summary

Adds a new rule, RUF102, to check for redundant ternary operators. Message shows when both the true and false branches return the same value, as discussed in #12516

Test Plan

cargo test

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Sep 2, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+2 -0 violations, +0 -0 fixes in 2 projects; 52 projects unchanged)

apache/superset (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ superset/utils/decorators.py:158:9: RUF034 Useless if-else condition

pandas-dev/pandas (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ pandas/tests/io/formats/style/test_style.py:923:26: RUF034 Useless if-else condition

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
RUF034 2 2 0 0 0

@RubenVanEldik
Copy link
Copy Markdown
Contributor

Hi Lucas,

I am new to Ruff an am just reading PRs to get a better understanding of how everything works. I was wondering, how did you decide to name it RUF102. Is there any logic behind the RUF0XX, RUF1XX sets?

Copy link
Copy Markdown
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This overall looks great to me but we should change the rule code and its name.

I have some concerns with the scope of the rule. I know it has previously been accepted but I only just now looked closer into it.

  • There's some overlap with SIM108 that simplifies if expressions
  • The scope of the rule is very narrow. Should it also apply to if-statements?

@AlexWaygood what are your thoughts on the rule?

It would be great if the rule also provided a fix that removes the if expression with the true or false body.

(Ruff, "033") => (RuleGroup::Preview, rules::ruff::rules::PostInitDefault),
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
(Ruff, "102") => (RuleGroup::Preview, rules::ruff::rules::RedundantTernary),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 1XX ruff rules are reserved for noqa specific rules. Let's change the code to 034.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RubenVanEldik I think this answers it 😄. This is also my first time contributing here.

if checker.enabled(Rule::IfExpInsteadOfOrOperator) {
refurb::rules::if_exp_instead_of_or_operator(checker, if_exp);
}
if checker.enabled(Rule::RedundantTernary) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I quickly checked other "ternary" specific rules and all of them use the term if-expr instead. We also use the term Useless when referring to useless code.

How about: useless-if-expr?

Copy link
Copy Markdown
Member

@AlexWaygood AlexWaygood Sep 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useless-if-expr sounds good to me. I agree that that's more approachable language than ternary

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, but if we also cover if blocks maybe we will need a different name. For example: useless-if-logic

Copy link
Copy Markdown
Member

@AlexWaygood AlexWaygood Sep 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, good point. Maybe useless-if-else? Or useless-if-condition?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I likeuseless-if-else

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like useless-if-else. It provides room for expanding the rule in the future.

@MichaReiser MichaReiser added rule Implementing or modifying a lint rule preview Related to preview mode features labels Sep 3, 2024
@MichaReiser
Copy link
Copy Markdown
Member

@AlexWaygood
Copy link
Copy Markdown
Member

AlexWaygood commented Sep 3, 2024

The ecosystem check shows an interesting false positive:

apache/superset@548d543/superset/utils/decorators.py#L158

@MichaReiser is that a false positive? The snippet in question is:

sorted_args = tuple(
    x if hasattr(x, "__repr__") else x for x in [*args, *sorted(kwargs.items())]
)

It seems like each element in the iterable there will be collected whether or not it has a __repr__ method, so I think it can just be simplified to

sorted_args = tuple(x for x in [*args, *sorted(kwargs.items())])

or even just

sorted_args = (*args, *sorted(kwargs.items()))

What they probably wanted to do was

sorted_args = tuple(
    repr(x) if hasattr(x, "__repr__") else x for x in [*args, *sorted(kwargs.items())]
)

But even that doesn't make much sense, because all objects in Python have a __repr__ attribute:

>>> hasattr(object, "__repr__")
True

@AlexWaygood
Copy link
Copy Markdown
Member

There's some overlap with SIM108 that simplifies if expressions

I support this being a separate rule to SIM108. SIM108 is quite opinionated IMO: I think it's questionable whether rewriting an if/else block as a ternary expression is always easier to read in Python, or always more idiomatic. This rule, on the other hand, seems like it's pointing out something that you'd almost always want to avoid. A useless ternary expression is almost certainly a straight-up mistake that you didn't mean to write 😄

The scope of the rule is very narrow. Should it also apply to if-statements?

Also applying it to if/else statements sounds reasonable to me.

@lucasctl
Copy link
Copy Markdown
Contributor Author

lucasctl commented Sep 3, 2024

It would be great if the rule also provided a fix that removes the if expression with the true or false body.

I don't think a fix would fit this rule because users probably end up in this situation when they mistype one of the ternary ends. Instead of just removing the ternary, they probably need to correct one of the sides.

@AlexWaygood AlexWaygood changed the title [ruff] implement redundant ternary rule (RUF102) [ruff] implement redundant ternary rule (RUF034) Sep 3, 2024
@lucasctl
Copy link
Copy Markdown
Contributor Author

lucasctl commented Sep 3, 2024

  • The scope of the rule is very narrow. Should it also apply to if-statements?

I wonder if rule SIM114 address that

@MichaReiser
Copy link
Copy Markdown
Member

SIM114 only seems to flag if-elif but not if-else. https://play.ruff.rs/ae79ec83-f045-4262-bcfb-dc8a08a19460

Copy link
Copy Markdown
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I think we could merge this now and expand it to if/else statements as a followup. @MichaReiser what do you think?

@MichaReiser MichaReiser changed the title [ruff] implement redundant ternary rule (RUF034) [ruff] implement useless if-else (RUF034) Sep 4, 2024
@MichaReiser MichaReiser merged commit e37bde4 into astral-sh:main Sep 4, 2024
@MichaReiser MichaReiser mentioned this pull request Oct 24, 2024
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Related to preview mode features rule Implementing or modifying a lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants