From 0a8cad255059fc29822e815364495597908bbcca Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 27 Sep 2023 00:36:55 -0400 Subject: [PATCH] Allow named expressions in `__all__` assignments (#7673) ## Summary This PR adds support for named expressions when analyzing `__all__` assignments, as per https://github.com/astral-sh/ruff/issues/7672. It also loosens the enforcement around assignments like: `__all__ = list(some_other_expression)`. We shouldn't flag these as invalid, even though we can't analyze the members, since we _know_ they evaluate to a `list`. Closes https://github.com/astral-sh/ruff/issues/7672. ## Test Plan `cargo test` --- .../fixtures/pylint/invalid_all_format.py | 6 +++++ ..._tests__PLE0605_invalid_all_format.py.snap | 22 ++++++++++++++++++- crates/ruff_python_ast/src/all.rs | 12 ++++++---- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/invalid_all_format.py b/crates/ruff_linter/resources/test/fixtures/pylint/invalid_all_format.py index fc7a3f8e15..f3b0eb1de1 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/invalid_all_format.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/invalid_all_format.py @@ -20,6 +20,8 @@ __all__ = foo.bar # [invalid-all-format] __all__ = foo["bar"] # [invalid-all-format] +__all__ = (foo := bar) # [invalid-all-format] + __all__ = ["Hello"] __all__ = ("Hello",) @@ -41,3 +43,7 @@ __all__ = __all__ + ["Hello"] __all__ = __all__ + multiprocessing.__all__ __all__ = list[str](["Hello", "world"]) + +__all__ = list[str](foo()) + +__all__ = (foo := ["Hello", "world"]) diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0605_invalid_all_format.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0605_invalid_all_format.py.snap index 9e96d3cb8f..1768e87240 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0605_invalid_all_format.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0605_invalid_all_format.py.snap @@ -106,7 +106,27 @@ invalid_all_format.py:21:1: PLE0605 Invalid format for `__all__`, must be `tuple 21 | __all__ = foo["bar"] # [invalid-all-format] | ^^^^^^^ PLE0605 22 | -23 | __all__ = ["Hello"] +23 | __all__ = (foo := bar) # [invalid-all-format] + | + +invalid_all_format.py:23:1: PLE0605 Invalid format for `__all__`, must be `tuple` or `list` + | +21 | __all__ = foo["bar"] # [invalid-all-format] +22 | +23 | __all__ = (foo := bar) # [invalid-all-format] + | ^^^^^^^ PLE0605 +24 | +25 | __all__ = ["Hello"] + | + +invalid_all_format.py:23:12: PLE0605 Invalid format for `__all__`, must be `tuple` or `list` + | +21 | __all__ = foo["bar"] # [invalid-all-format] +22 | +23 | __all__ = (foo := bar) # [invalid-all-format] + | ^^^ PLE0605 +24 | +25 | __all__ = ["Hello"] | diff --git a/crates/ruff_python_ast/src/all.rs b/crates/ruff_python_ast/src/all.rs index 3f738984b5..bd0bd66d04 100644 --- a/crates/ruff_python_ast/src/all.rs +++ b/crates/ruff_python_ast/src/all.rs @@ -81,17 +81,21 @@ where | Expr::Tuple(ast::ExprTuple { elts, .. }) => { return (Some(elts), DunderAllFlags::empty()); } - Expr::ListComp(_) | Expr::SetComp(_) | Expr::GeneratorExp(_) => { - // Allow comprehensions, even though we can't statically analyze - // them. + _ => { + // We can't analyze other expressions, but they must be + // valid, since the `list` or `tuple` call will ultimately + // evaluate to a list or tuple. return (None, DunderAllFlags::empty()); } - _ => {} } } } } } + Expr::NamedExpr(ast::ExprNamedExpr { value, .. }) => { + // Allow, e.g., `__all__ += (value := ["A", "B"])`. + return extract_elts(value, is_builtin); + } _ => {} } (None, DunderAllFlags::INVALID_FORMAT)