From 04e7cecab3ee51df32f9f9d01652b04d7395db0c Mon Sep 17 00:00:00 2001 From: Dan Parizher <105245560+danparizher@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:27:31 -0500 Subject: [PATCH] [`flake8-simplify`] Fix SIM222 false positive for `tuple(generator) or None` (`SIM222`) (#21187) Co-authored-by: Micha Reiser --- .../test/fixtures/flake8_simplify/SIM222.py | 12 ++++++++++++ ...__flake8_simplify__tests__SIM222_SIM222.py.snap | 8 ++++++++ crates/ruff_python_ast/src/helpers.rs | 14 ++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM222.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM222.py index e1e299c98e..71fc606386 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM222.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM222.py @@ -204,3 +204,15 @@ x = 1 print(f"{x=}" or "bar") # SIM222 (lambda: 1) or True # SIM222 (i for i in range(1)) or "bar" # SIM222 + +# https://github.com/astral-sh/ruff/issues/21136 +def get_items(): + return tuple(item for item in Item.objects.all()) or None # OK + + +def get_items_list(): + return tuple([item for item in items]) or None # OK + + +def get_items_set(): + return tuple({item for item in items}) or None # OK diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM222_SIM222.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM222_SIM222.py.snap index f6c8bba110..0e65033b21 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM222_SIM222.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM222_SIM222.py.snap @@ -1101,6 +1101,7 @@ help: Replace with `f"{x=}"` 204 + print(f"{x=}") # SIM222 205 | (lambda: 1) or True # SIM222 206 | (i for i in range(1)) or "bar" # SIM222 +207 | note: This is an unsafe fix and may change runtime behavior SIM222 [*] Use `lambda: 1` instead of `lambda: 1 or ...` @@ -1119,6 +1120,8 @@ help: Replace with `lambda: 1` - (lambda: 1) or True # SIM222 205 + lambda: 1 # SIM222 206 | (i for i in range(1)) or "bar" # SIM222 +207 | +208 | # https://github.com/astral-sh/ruff/issues/21136 note: This is an unsafe fix and may change runtime behavior SIM222 [*] Use `(i for i in range(1))` instead of `(i for i in range(1)) or ...` @@ -1128,6 +1131,8 @@ SIM222 [*] Use `(i for i in range(1))` instead of `(i for i in range(1)) or ...` 205 | (lambda: 1) or True # SIM222 206 | (i for i in range(1)) or "bar" # SIM222 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +207 | +208 | # https://github.com/astral-sh/ruff/issues/21136 | help: Replace with `(i for i in range(1))` 203 | x = 1 @@ -1135,4 +1140,7 @@ help: Replace with `(i for i in range(1))` 205 | (lambda: 1) or True # SIM222 - (i for i in range(1)) or "bar" # SIM222 206 + (i for i in range(1)) # SIM222 +207 | +208 | # https://github.com/astral-sh/ruff/issues/21136 +209 | def get_items(): note: This is an unsafe fix and may change runtime behavior diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 9d5159a829..66ad66d9b1 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -1318,9 +1318,19 @@ impl Truthiness { if arguments.is_empty() { // Ex) `list()` Self::Falsey - } else if arguments.args.len() == 1 && arguments.keywords.is_empty() { + } else if let [argument] = &*arguments.args + && arguments.keywords.is_empty() + { // Ex) `list([1, 2, 3])` - Self::from_expr(&arguments.args[0], is_builtin) + // For tuple(generator), we can't determine statically if the result will + // be empty or not, so return Unknown. The generator itself is truthy, but + // tuple(empty_generator) is falsy. ListComp and SetComp are handled by + // recursing into Self::from_expr below, which returns Unknown for them. + if argument.is_generator_expr() { + Self::Unknown + } else { + Self::from_expr(argument, is_builtin) + } } else { Self::Unknown }