astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.

Home Page:https://docs.astral.sh/ruff

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FURB110 may break code

martinlehoux opened this issue · comments

  • Keywords: FURB110
  • Command: ruff --preview --select FURB110 --fix
  • Ruff version: 0.4.3

FURB110 autofix (with preview) changed code

place_id = (
    location_place_id
    if location_place_id
    else City.objects.get(pk=city_id).gmaps_place_id
    if city_id
    else None
)    

into

place_id = location_place_id or City.objects.get(pk=city_id).gmaps_place_id if city_id else None

With inputs location_place_id = "abc" and city_id = None, the code previously returned "abc" but now returns None

Could you provide a minimal code snippet to try?

I'm able to reproduce it using the following example.

❯ bat test.py
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: test.py
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ location_place_id = "abc"
   2   │ city_id = None
   3   │ place_id = (
   4   │     location_place_id
   5   │     if location_place_id
   6   │     else "ghi"
   7   │     if city_id
   8   │     else None
   9   │ )
  10   │
  11   │ print(place_id)
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
❯ python test.py
abc

After running ruff --fix.

❯ ruff check test.py --preview --select FURB110 --fix
Found 1 error (1 fixed, 0 remaining).
❯ bat test.py
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: test.py
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ location_place_id = "abc"
   2   │ city_id = None
   3   │ place_id = (
   4   │     location_place_id or "ghi"
   5   │     if city_id
   6   │     else None
   7   │ )
   8   │
   9   │ print(place_id)
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
❯ python test.py
None

The correct fix here should wrap the second or statement in parentheses.

❯ bat test.py
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: test.py
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ location_place_id = "abc"
   2   │ city_id = None
   3   │ place_id = location_place_id or ("ghi" if city_id else None)
   4   │ print(place_id)
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
❯ python test.py
abc

Thanks @blueraft , and yes that is exactly the fix I did ;)

Probably a precedence issue.

I think the edit content should be generated using the Generator to account for precedence as it currently uses raw string:

Edit::range_replacement(
format!(
"{} or {}",
checker.locator().slice(left),
checker.locator().slice(right),
),
if_expr.range(),
),

Raw strings are better right now IMO since they preserve more of the verbatim content. I think I'd rather augment the fix to parenthesize if needed.