[syntax-errors]: future-feature-not-defined (F407) (#20554)

<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

This PR implements
https://docs.astral.sh/ruff/rules/future-feature-not-defined/ (F407) as
a semantic syntax error.

## Test Plan

<!-- How was it tested? -->

I have written inline tests as directed in #17412

---------

Signed-off-by: 11happy <soni5happy@gmail.com>
This commit is contained in:
Bhuminjay Soni 2025-09-25 23:22:24 +05:30 committed by GitHub
parent 6b7a9dc2f2
commit cfc64d1707
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 246 additions and 45 deletions

View file

@ -0,0 +1,146 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/invalid_future_feature.py
---
## AST
```
Module(
ModModule {
node_index: NodeIndex(None),
range: 0..151,
body: [
ImportFrom(
StmtImportFrom {
node_index: NodeIndex(None),
range: 0..38,
module: Some(
Identifier {
id: Name("__future__"),
range: 5..15,
node_index: NodeIndex(None),
},
),
names: [
Alias {
range: 23..38,
node_index: NodeIndex(None),
name: Identifier {
id: Name("invalid_feature"),
range: 23..38,
node_index: NodeIndex(None),
},
asname: None,
},
],
level: 0,
},
),
ImportFrom(
StmtImportFrom {
node_index: NodeIndex(None),
range: 39..90,
module: Some(
Identifier {
id: Name("__future__"),
range: 44..54,
node_index: NodeIndex(None),
},
),
names: [
Alias {
range: 62..73,
node_index: NodeIndex(None),
name: Identifier {
id: Name("annotations"),
range: 62..73,
node_index: NodeIndex(None),
},
asname: None,
},
Alias {
range: 75..90,
node_index: NodeIndex(None),
name: Identifier {
id: Name("invalid_feature"),
range: 75..90,
node_index: NodeIndex(None),
},
asname: None,
},
],
level: 0,
},
),
ImportFrom(
StmtImportFrom {
node_index: NodeIndex(None),
range: 91..150,
module: Some(
Identifier {
id: Name("__future__"),
range: 96..106,
node_index: NodeIndex(None),
},
),
names: [
Alias {
range: 114..131,
node_index: NodeIndex(None),
name: Identifier {
id: Name("invalid_feature_1"),
range: 114..131,
node_index: NodeIndex(None),
},
asname: None,
},
Alias {
range: 133..150,
node_index: NodeIndex(None),
name: Identifier {
id: Name("invalid_feature_2"),
range: 133..150,
node_index: NodeIndex(None),
},
asname: None,
},
],
level: 0,
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | from __future__ import invalid_feature
| ^^^^^^^^^^^^^^^ Syntax Error: Future feature `invalid_feature` is not defined
2 | from __future__ import annotations, invalid_feature
3 | from __future__ import invalid_feature_1, invalid_feature_2
|
|
1 | from __future__ import invalid_feature
2 | from __future__ import annotations, invalid_feature
| ^^^^^^^^^^^^^^^ Syntax Error: Future feature `invalid_feature` is not defined
3 | from __future__ import invalid_feature_1, invalid_feature_2
|
|
1 | from __future__ import invalid_feature
2 | from __future__ import annotations, invalid_feature
3 | from __future__ import invalid_feature_1, invalid_feature_2
| ^^^^^^^^^^^^^^^^^ Syntax Error: Future feature `invalid_feature_1` is not defined
|
|
1 | from __future__ import invalid_feature
2 | from __future__ import annotations, invalid_feature
3 | from __future__ import invalid_feature_1, invalid_feature_2
| ^^^^^^^^^^^^^^^^^ Syntax Error: Future feature `invalid_feature_2` is not defined
|

View file

@ -0,0 +1,42 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/valid_future_feature.py
---
## AST
```
Module(
ModModule {
node_index: NodeIndex(None),
range: 0..35,
body: [
ImportFrom(
StmtImportFrom {
node_index: NodeIndex(None),
range: 0..34,
module: Some(
Identifier {
id: Name("__future__"),
range: 5..15,
node_index: NodeIndex(None),
},
),
names: [
Alias {
range: 23..34,
node_index: NodeIndex(None),
name: Identifier {
id: Name("annotations"),
range: 23..34,
node_index: NodeIndex(None),
},
asname: None,
},
],
level: 0,
},
),
],
},
)
```