mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 11:59:35 +00:00
[pyflakes
] Improve error message for UndefinedName
when a builtin was added in a newer version than specified in Ruff config (F821
) (#13293)
This commit is contained in:
parent
b7cef6c999
commit
1d5bd89987
5 changed files with 223 additions and 165 deletions
|
@ -1,5 +1,6 @@
|
|||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_semantic::Exceptions;
|
||||
use ruff_python_stdlib::builtins::version_builtin_was_added;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
|
@ -35,9 +36,12 @@ pub(crate) fn unresolved_references(checker: &mut Checker) {
|
|||
}
|
||||
}
|
||||
|
||||
let symbol_name = reference.name(checker.locator);
|
||||
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::UndefinedName {
|
||||
name: reference.name(checker.locator).to_string(),
|
||||
name: symbol_name.to_string(),
|
||||
minor_version_builtin_added: version_builtin_was_added(symbol_name),
|
||||
},
|
||||
reference.range(),
|
||||
));
|
||||
|
|
|
@ -208,6 +208,18 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f821_with_builtin_added_on_new_py_version_but_old_target_version_specified() {
|
||||
let diagnostics = test_snippet(
|
||||
"PythonFinalizationError",
|
||||
&LinterSettings {
|
||||
target_version: crate::settings::types::PythonVersion::Py312,
|
||||
..LinterSettings::for_rule(Rule::UndefinedName)
|
||||
},
|
||||
);
|
||||
assert_messages!(diagnostics);
|
||||
}
|
||||
|
||||
#[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))]
|
||||
#[test_case(Rule::UnusedImport, Path::new("__init__.py"))]
|
||||
#[test_case(Rule::UnusedImport, Path::new("F401_24/__init__.py"))]
|
||||
|
|
|
@ -19,17 +19,35 @@ use ruff_macros::{derive_message_formats, violation};
|
|||
/// return n * 2
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - [`target-version`]: Can be used to configure which symbols Ruff will understand
|
||||
/// as being available in the `builtins` namespace.
|
||||
///
|
||||
/// ## References
|
||||
/// - [Python documentation: Naming and binding](https://docs.python.org/3/reference/executionmodel.html#naming-and-binding)
|
||||
#[violation]
|
||||
pub struct UndefinedName {
|
||||
pub(crate) name: String,
|
||||
pub(crate) minor_version_builtin_added: Option<u8>,
|
||||
}
|
||||
|
||||
impl Violation for UndefinedName {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UndefinedName { name } = self;
|
||||
let UndefinedName {
|
||||
name,
|
||||
minor_version_builtin_added,
|
||||
} = self;
|
||||
let tip = minor_version_builtin_added.map(|version_added| {
|
||||
format!(
|
||||
r#"Consider specifying `requires-python = ">= 3.{version_added}"` or `tool.ruff.target-version = "py3{version_added}"` in your `pyproject.toml` file."#
|
||||
)
|
||||
});
|
||||
|
||||
if let Some(tip) = tip {
|
||||
format!("Undefined name `{name}`. {tip}")
|
||||
} else {
|
||||
format!("Undefined name `{name}`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
||||
---
|
||||
<filename>:1:1: F821 Undefined name `PythonFinalizationError`. Consider specifying `requires-python = ">= 3.13"` or `tool.ruff.target-version = "py313"` in your `pyproject.toml` file.
|
||||
|
|
||||
1 | PythonFinalizationError
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ F821
|
||||
|
|
|
@ -23,11 +23,7 @@ pub const MAGIC_GLOBALS: &[&str] = &[
|
|||
"__file__",
|
||||
];
|
||||
|
||||
/// Return the list of builtins for the given Python minor version.
|
||||
///
|
||||
/// Intended to be kept in sync with [`is_python_builtin`].
|
||||
pub fn python_builtins(minor_version: u8, is_notebook: bool) -> Vec<&'static str> {
|
||||
let mut builtins = vec![
|
||||
static ALWAYS_AVAILABLE_BUILTINS: &[&str] = &[
|
||||
"ArithmeticError",
|
||||
"AssertionError",
|
||||
"AttributeError",
|
||||
|
@ -180,24 +176,28 @@ pub fn python_builtins(minor_version: u8, is_notebook: bool) -> Vec<&'static str
|
|||
"type",
|
||||
"vars",
|
||||
"zip",
|
||||
];
|
||||
];
|
||||
static PY310_PLUS_BUILTINS: &[&str] = &["EncodingWarning", "aiter", "anext"];
|
||||
static PY311_PLUS_BUILTINS: &[&str] = &["BaseExceptionGroup", "ExceptionGroup"];
|
||||
static PY313_PLUS_BUILTINS: &[&str] = &["PythonFinalizationError"];
|
||||
|
||||
/// Return the list of builtins for the given Python minor version.
|
||||
///
|
||||
/// Intended to be kept in sync with [`is_python_builtin`].
|
||||
pub fn python_builtins(minor_version: u8, is_notebook: bool) -> Vec<&'static str> {
|
||||
let mut builtins = ALWAYS_AVAILABLE_BUILTINS.to_vec();
|
||||
if minor_version >= 10 {
|
||||
builtins.extend(&["EncodingWarning", "aiter", "anext"]);
|
||||
builtins.extend(PY310_PLUS_BUILTINS);
|
||||
}
|
||||
|
||||
if minor_version >= 11 {
|
||||
builtins.extend(&["BaseExceptionGroup", "ExceptionGroup"]);
|
||||
builtins.extend(PY311_PLUS_BUILTINS);
|
||||
}
|
||||
|
||||
if minor_version >= 13 {
|
||||
builtins.push("PythonFinalizationError");
|
||||
builtins.extend(PY313_PLUS_BUILTINS);
|
||||
}
|
||||
|
||||
if is_notebook {
|
||||
builtins.extend(IPYTHON_BUILTINS);
|
||||
}
|
||||
|
||||
builtins
|
||||
}
|
||||
|
||||
|
@ -370,6 +370,22 @@ pub fn is_python_builtin(name: &str, minor_version: u8, is_notebook: bool) -> bo
|
|||
)
|
||||
}
|
||||
|
||||
/// Return `Some(version)`, where `version` corresponds to the Python minor version
|
||||
/// in which the builtin was added
|
||||
pub fn version_builtin_was_added(name: &str) -> Option<u8> {
|
||||
if PY310_PLUS_BUILTINS.contains(&name) {
|
||||
Some(10)
|
||||
} else if PY311_PLUS_BUILTINS.contains(&name) {
|
||||
Some(11)
|
||||
} else if PY313_PLUS_BUILTINS.contains(&name) {
|
||||
Some(13)
|
||||
} else if ALWAYS_AVAILABLE_BUILTINS.contains(&name) {
|
||||
Some(0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the given name is that of a Python builtin iterator.
|
||||
pub fn is_iterator(name: &str) -> bool {
|
||||
matches!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue