mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
'Revert "F821: Fix false negatives in .py files when from __future__ import annotations
is active (#10362)"' (#10513)
This commit is contained in:
parent
9b3c732538
commit
c62184d057
6 changed files with 50 additions and 41 deletions
|
@ -33,16 +33,3 @@ class MyClass:
|
||||||
baz: MyClass
|
baz: MyClass
|
||||||
eggs = baz # Still invalid even when `__future__.annotations` are enabled
|
eggs = baz # Still invalid even when `__future__.annotations` are enabled
|
||||||
eggs = "baz" # always okay
|
eggs = "baz" # always okay
|
||||||
|
|
||||||
# Forward references:
|
|
||||||
MaybeDStr: TypeAlias = Optional[DStr] # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
MaybeDStr2: TypeAlias = Optional["DStr"] # always okay
|
|
||||||
DStr: TypeAlias = Union[D, str] # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
DStr2: TypeAlias = Union["D", str] # always okay
|
|
||||||
|
|
||||||
class D: ...
|
|
||||||
|
|
||||||
# More circular references
|
|
||||||
class Leaf: ...
|
|
||||||
class Tree(list[Tree | Leaf]): ... # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
class Tree2(list["Tree | Leaf"]): ... # always okay
|
|
||||||
|
|
23
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_29.py
vendored
Normal file
23
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_29.py
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
"""Regression test for #10451.
|
||||||
|
|
||||||
|
Annotations in a class are allowed to be forward references
|
||||||
|
if `from __future__ import annotations` is active,
|
||||||
|
even if they're in a class included in
|
||||||
|
`lint.flake8-type-checking.runtime-evaluated-base-classes`.
|
||||||
|
|
||||||
|
They're not allowed to refer to symbols that cannot be *resolved*
|
||||||
|
at runtime, however.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from sqlalchemy.orm import DeclarativeBase, Mapped
|
||||||
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
some_mapping: Mapped[list[Bar]] | None = None # Should not trigger F821 (resolveable forward reference)
|
||||||
|
simplified: list[Bar] | None = None # Should not trigger F821 (resolveable forward reference)
|
||||||
|
|
||||||
|
|
||||||
|
class Bar:
|
||||||
|
pass
|
|
@ -937,7 +937,6 @@ impl<'a> Visitor<'a> for Checker<'a> {
|
||||||
&& !self.semantic.in_deferred_type_definition()
|
&& !self.semantic.in_deferred_type_definition()
|
||||||
&& self.semantic.in_type_definition()
|
&& self.semantic.in_type_definition()
|
||||||
&& self.semantic.future_annotations()
|
&& self.semantic.future_annotations()
|
||||||
&& (self.semantic.in_typing_only_annotation() || self.source_type.is_stub())
|
|
||||||
{
|
{
|
||||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr {
|
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr {
|
||||||
self.visit.string_type_definitions.push((
|
self.visit.string_type_definitions.push((
|
||||||
|
|
|
@ -180,6 +180,29 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(Rule::UndefinedName, Path::new("F821_29.py"))]
|
||||||
|
fn rules_with_flake8_type_checking_settings_enabled(
|
||||||
|
rule_code: Rule,
|
||||||
|
path: &Path,
|
||||||
|
) -> Result<()> {
|
||||||
|
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("pyflakes").join(path).as_path(),
|
||||||
|
&LinterSettings {
|
||||||
|
flake8_type_checking: crate::rules::flake8_type_checking::settings::Settings {
|
||||||
|
runtime_required_base_classes: vec![
|
||||||
|
"pydantic.BaseModel".to_string(),
|
||||||
|
"sqlalchemy.orm.DeclarativeBase".to_string(),
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..LinterSettings::for_rule(rule_code)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
assert_messages!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))]
|
#[test_case(Rule::UnusedVariable, Path::new("F841_4.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!(
|
||||||
|
|
|
@ -17,30 +17,3 @@ F821_27.py:34:8: F821 Undefined name `baz`
|
||||||
| ^^^ F821
|
| ^^^ F821
|
||||||
35 | eggs = "baz" # always okay
|
35 | eggs = "baz" # always okay
|
||||||
|
|
|
|
||||||
|
|
||||||
F821_27.py:38:33: F821 Undefined name `DStr`
|
|
||||||
|
|
|
||||||
37 | # Forward references:
|
|
||||||
38 | MaybeDStr: TypeAlias = Optional[DStr] # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
| ^^^^ F821
|
|
||||||
39 | MaybeDStr2: TypeAlias = Optional["DStr"] # always okay
|
|
||||||
40 | DStr: TypeAlias = Union[D, str] # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
|
|
|
||||||
|
|
||||||
F821_27.py:40:25: F821 Undefined name `D`
|
|
||||||
|
|
|
||||||
38 | MaybeDStr: TypeAlias = Optional[DStr] # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
39 | MaybeDStr2: TypeAlias = Optional["DStr"] # always okay
|
|
||||||
40 | DStr: TypeAlias = Union[D, str] # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
| ^ F821
|
|
||||||
41 | DStr2: TypeAlias = Union["D", str] # always okay
|
|
||||||
|
|
|
||||||
|
|
||||||
F821_27.py:47:17: F821 Undefined name `Tree`
|
|
||||||
|
|
|
||||||
45 | # More circular references
|
|
||||||
46 | class Leaf: ...
|
|
||||||
47 | class Tree(list[Tree | Leaf]): ... # Still invalid even when `__future__.annotations` are enabled
|
|
||||||
| ^^^^ F821
|
|
||||||
48 | class Tree2(list["Tree | Leaf"]): ... # always okay
|
|
||||||
|
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
||||||
|
---
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue