mirror of https://github.com/astral-sh/ruff
[`flake8-use-pathlib`] Skip single dots for `invalid-pathlib-with-suffix` (`PTH210`) on versions >= 3.14 (#19331)
Skips [invalid-pathlib-with-suffix (PTH210)](https://docs.astral.sh/ruff/rules/invalid-pathlib-with-suffix/#invalid-pathlib-with-suffix-pth210) for `.with_suffix(".")` on Python versions 3.14 and greater, as per [the docs](https://docs.python.org/3.14/library/pathlib.html#pathlib.PurePath.with_suffix). Progress towards #15506
This commit is contained in:
parent
464144f1c6
commit
82391b5675
|
|
@ -0,0 +1,26 @@
|
||||||
|
from pathlib import (
|
||||||
|
Path,
|
||||||
|
PosixPath,
|
||||||
|
PurePath,
|
||||||
|
PurePosixPath,
|
||||||
|
PureWindowsPath,
|
||||||
|
WindowsPath,
|
||||||
|
)
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
|
path = Path()
|
||||||
|
posix_path: pathlib.PosixPath = PosixPath()
|
||||||
|
pure_path: PurePath = PurePath()
|
||||||
|
pure_posix_path = pathlib.PurePosixPath()
|
||||||
|
pure_windows_path: PureWindowsPath = pathlib.PureWindowsPath()
|
||||||
|
windows_path: pathlib.WindowsPath = pathlib.WindowsPath()
|
||||||
|
|
||||||
|
|
||||||
|
### No Errors
|
||||||
|
path.with_suffix(".")
|
||||||
|
posix_path.with_suffix(".")
|
||||||
|
pure_path.with_suffix(".")
|
||||||
|
pure_posix_path.with_suffix(".")
|
||||||
|
pure_windows_path.with_suffix(".")
|
||||||
|
windows_path.with_suffix(".")
|
||||||
|
|
@ -8,6 +8,7 @@ mod tests {
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use ruff_python_ast::PythonVersion;
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use crate::assert_diagnostics;
|
use crate::assert_diagnostics;
|
||||||
|
|
@ -143,4 +144,22 @@ mod tests {
|
||||||
assert_diagnostics!(snapshot, diagnostics);
|
assert_diagnostics!(snapshot, diagnostics);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(Rule::InvalidPathlibWithSuffix, Path::new("PTH210_2.py"))]
|
||||||
|
fn pathlib_with_suffix_py314(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
|
let snapshot = format!(
|
||||||
|
"py314__{}_{}",
|
||||||
|
rule_code.noqa_code(),
|
||||||
|
path.to_string_lossy()
|
||||||
|
);
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("flake8_use_pathlib").join(path).as_path(),
|
||||||
|
&settings::LinterSettings {
|
||||||
|
unresolved_target_version: PythonVersion::PY314.into(),
|
||||||
|
..settings::LinterSettings::for_rule(rule_code)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
assert_diagnostics!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::{Edit, Fix, FixAvailability, Violation};
|
use crate::{Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::{self as ast, StringFlags};
|
use ruff_python_ast::{self as ast, PythonVersion, StringFlags};
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_python_semantic::analyze::typing;
|
use ruff_python_semantic::analyze::typing;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
@ -9,12 +9,13 @@ use ruff_text_size::Ranged;
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `pathlib.Path.with_suffix()` calls where
|
/// Checks for `pathlib.Path.with_suffix()` calls where
|
||||||
/// the given suffix does not have a leading dot
|
/// the given suffix does not have a leading dot
|
||||||
/// or the given suffix is a single dot `"."`.
|
/// or the given suffix is a single dot `"."` and the
|
||||||
|
/// Python version is less than 3.14.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// `Path.with_suffix()` will raise an error at runtime
|
/// `Path.with_suffix()` will raise an error at runtime
|
||||||
/// if the given suffix is not prefixed with a dot
|
/// if the given suffix is not prefixed with a dot
|
||||||
/// or it is a single dot `"."`.
|
/// or, in versions prior to Python 3.14, if it is a single dot `"."`.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
|
|
@ -57,9 +58,6 @@ use ruff_text_size::Ranged;
|
||||||
/// No fix is offered if the suffix `"."` is given, since the intent is unclear.
|
/// No fix is offered if the suffix `"."` is given, since the intent is unclear.
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
pub(crate) struct InvalidPathlibWithSuffix {
|
pub(crate) struct InvalidPathlibWithSuffix {
|
||||||
// TODO: Since "." is a correct suffix in Python 3.14,
|
|
||||||
// we will need to update this rule and documentation
|
|
||||||
// once Ruff supports Python 3.14.
|
|
||||||
single_dot: bool,
|
single_dot: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,6 +114,13 @@ pub(crate) fn invalid_pathlib_with_suffix(checker: &Checker, call: &ast::ExprCal
|
||||||
};
|
};
|
||||||
|
|
||||||
let single_dot = string_value == ".";
|
let single_dot = string_value == ".";
|
||||||
|
|
||||||
|
// As of Python 3.14, a single dot is considered a valid suffix.
|
||||||
|
// https://docs.python.org/3.14/library/pathlib.html#pathlib.PurePath.with_suffix
|
||||||
|
if single_dot && checker.target_version() >= PythonVersion::PY314 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
checker.report_diagnostic(InvalidPathlibWithSuffix { single_dot }, call.range);
|
checker.report_diagnostic(InvalidPathlibWithSuffix { single_dot }, call.range);
|
||||||
if !single_dot {
|
if !single_dot {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_use_pathlib/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
Loading…
Reference in New Issue