mirror of https://github.com/astral-sh/ruff
fix(F822): add option to enable F822 in __init__.py files (#11370)
## Summary This PR aims to close #10095 by adding an option `init-allow-undef-export` to the `pyflakes` settings. This option is currently set to `true` such that behavior is kept identical. But setting this option to `false` will lead to `F822` warnings to be shown in all files, **including** `__init__.py` files. As I've mentioned on #10095, I think `init-allow-undef-export=false` would be the more user-friendly default option, as it creates fewer surprises. @charliermarsh what do you think about making that the default? With this option in place, it's a single line fix for people that rely on the old behavior. And thinking longer term, for future major releases, one could probably consider deprecating the option and eventually having people just `noqa` these warnings if they are not wanted. ## Test Plan I've added a `test_init_f822_enabled` test which repeats the test that is done in the `init` test but this time with `init-allow-undef-export=false` and the snap file correctly shows that ruff will then trigger the otherwise suppressed F822 warning. closes #10095
This commit is contained in:
parent
921bc15542
commit
e35deee583
|
|
@ -2301,7 +2301,9 @@ impl<'a> Checker<'a> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.enabled(Rule::UndefinedExport) {
|
if self.enabled(Rule::UndefinedExport) {
|
||||||
if !self.path.ends_with("__init__.py") {
|
if self.settings.preview.is_enabled()
|
||||||
|
|| !self.path.ends_with("__init__.py")
|
||||||
|
{
|
||||||
self.diagnostics.push(
|
self.diagnostics.push(
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
pyflakes::rules::UndefinedExport {
|
pyflakes::rules::UndefinedExport {
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,7 @@ mod tests {
|
||||||
#[test_case(Rule::UnusedImport, Path::new("F401_27__all_mistyped/__init__.py"))]
|
#[test_case(Rule::UnusedImport, Path::new("F401_27__all_mistyped/__init__.py"))]
|
||||||
#[test_case(Rule::UnusedImport, Path::new("F401_28__all_multiple/__init__.py"))]
|
#[test_case(Rule::UnusedImport, Path::new("F401_28__all_multiple/__init__.py"))]
|
||||||
#[test_case(Rule::UnusedImport, Path::new("F401_29__all_conditional/__init__.py"))]
|
#[test_case(Rule::UnusedImport, Path::new("F401_29__all_conditional/__init__.py"))]
|
||||||
|
#[test_case(Rule::UndefinedExport, Path::new("__init__.py"))]
|
||||||
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!(
|
let snapshot = format!(
|
||||||
"preview__{}_{}",
|
"preview__{}_{}",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,11 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
/// Including an undefined name in `__all__` is likely to raise `NameError` at
|
/// Including an undefined name in `__all__` is likely to raise `NameError` at
|
||||||
/// runtime, when the module is imported.
|
/// runtime, when the module is imported.
|
||||||
///
|
///
|
||||||
|
/// In [preview], this rule will flag undefined names in `__init__.py` file,
|
||||||
|
/// even if those names implicitly refer to other modules in the package. Users
|
||||||
|
/// that rely on implicit exports should disable this rule in `__init__.py`
|
||||||
|
/// files via [`lint.per-file-ignores`].
|
||||||
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// from foo import bar
|
/// from foo import bar
|
||||||
|
|
@ -31,6 +36,8 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
///
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: `__all__`](https://docs.python.org/3/tutorial/modules.html#importing-from-a-package)
|
/// - [Python documentation: `__all__`](https://docs.python.org/3/tutorial/modules.html#importing-from-a-package)
|
||||||
|
///
|
||||||
|
/// [preview]: https://docs.astral.sh/ruff/preview/
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct UndefinedExport {
|
pub struct UndefinedExport {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
||||||
|
---
|
||||||
|
__init__.py:5:12: F822 Undefined name `a` in `__all__`
|
||||||
|
|
|
||||||
|
3 | print(__path__)
|
||||||
|
4 |
|
||||||
|
5 | __all__ = ["a", "b", "c"]
|
||||||
|
| ^^^ F822
|
||||||
|
|
|
||||||
|
|
||||||
|
__init__.py:5:17: F822 Undefined name `b` in `__all__`
|
||||||
|
|
|
||||||
|
3 | print(__path__)
|
||||||
|
4 |
|
||||||
|
5 | __all__ = ["a", "b", "c"]
|
||||||
|
| ^^^ F822
|
||||||
|
|
|
||||||
|
|
||||||
|
__init__.py:5:22: F822 Undefined name `c` in `__all__`
|
||||||
|
|
|
||||||
|
3 | print(__path__)
|
||||||
|
4 |
|
||||||
|
5 | __all__ = ["a", "b", "c"]
|
||||||
|
| ^^^ F822
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue