Skip to content
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

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

Merged
merged 5 commits into from
Sep 4, 2024

Conversation

iamlucasvieira
Copy link
Contributor

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

Copy link
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
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
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.

@@ -963,6 +963,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(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
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
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.

@@ -1404,6 +1404,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::IfExpInsteadOfOrOperator) {
refurb::rules::if_exp_instead_of_or_operator(checker, if_exp);
}
if checker.enabled(Rule::RedundantTernary) {
Copy link
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
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
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
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
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
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
Member

@AlexWaygood
Copy link
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
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.

@iamlucasvieira
Copy link
Contributor Author

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
@iamlucasvieira
Copy link
Contributor Author

  • 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
Member

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

Copy link
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
20 checks passed
@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