mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:18 +00:00
[flake8-use-pathlib
] PTH*
suppress diagnostic for all os.*
functions that have the dir_fd
parameter (#17968)
<!-- Thank you for contributing to Ruff! 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? - Does this pull request include references to any relevant issues? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> Fixes #17776. This PR also handles all other `PTH*` rules that don't support file descriptors. ## Test Plan <!-- How was it tested? --> Update existing tests.
This commit is contained in:
parent
c9031ce59f
commit
d7ef01401c
4 changed files with 166 additions and 29 deletions
|
@ -9,3 +9,7 @@ extensions_dir = "./extensions"
|
|||
glob.glob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp"))
|
||||
list(glob.iglob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp")))
|
||||
search("*.png")
|
||||
|
||||
# if `dir_fd` is set, suppress the diagnostic
|
||||
glob.glob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp"), dir_fd=1)
|
||||
list(glob.iglob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp"), dir_fd=1))
|
||||
|
|
|
@ -87,3 +87,20 @@ def bar(x: int):
|
|||
os.rename("src", "dst", src_dir_fd=3, dst_dir_fd=4)
|
||||
os.rename("src", "dst", src_dir_fd=3)
|
||||
os.rename("src", "dst", dst_dir_fd=4)
|
||||
|
||||
# if `dir_fd` is set, suppress the diagnostic
|
||||
os.readlink(p, dir_fd=1)
|
||||
os.stat(p, dir_fd=2)
|
||||
os.unlink(p, dir_fd=3)
|
||||
os.remove(p, dir_fd=4)
|
||||
os.rmdir(p, dir_fd=5)
|
||||
os.mkdir(p, dir_fd=6)
|
||||
os.chmod(p, dir_fd=7)
|
||||
# `chmod` can also receive a file descriptor in the first argument
|
||||
os.chmod(8)
|
||||
os.chmod(x)
|
||||
|
||||
# if `src_dir_fd` or `dst_dir_fd` are set, suppress the diagnostic
|
||||
os.replace("src", "dst", src_dir_fd=1, dst_dir_fd=2)
|
||||
os.replace("src", "dst", src_dir_fd=1)
|
||||
os.replace("src", "dst", dst_dir_fd=2)
|
||||
|
|
|
@ -26,41 +26,109 @@ pub(crate) fn replaceable_by_pathlib(checker: &Checker, call: &ExprCall) {
|
|||
// PTH100
|
||||
["os", "path", "abspath"] => OsPathAbspath.into(),
|
||||
// PTH101
|
||||
["os", "chmod"] => OsChmod.into(),
|
||||
["os", "chmod"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.chmod)
|
||||
// ```text
|
||||
// 0 1 2 3
|
||||
// os.chmod(path, mode, *, dir_fd=None, follow_symlinks=True)
|
||||
// ```
|
||||
if call
|
||||
.arguments
|
||||
.find_argument_value("path", 0)
|
||||
.is_some_and(|expr| is_file_descriptor(expr, checker.semantic()))
|
||||
|| is_argument_non_default(&call.arguments, "dir_fd", 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
OsChmod.into()
|
||||
}
|
||||
// PTH102
|
||||
["os", "makedirs"] => OsMakedirs.into(),
|
||||
// PTH103
|
||||
["os", "mkdir"] => OsMkdir.into(),
|
||||
["os", "mkdir"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.mkdir)
|
||||
// ```text
|
||||
// 0 1 2
|
||||
// os.mkdir(path, mode=0o777, *, dir_fd=None)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "dir_fd", 2) {
|
||||
return;
|
||||
}
|
||||
OsMkdir.into()
|
||||
}
|
||||
// PTH104
|
||||
["os", "rename"] => {
|
||||
// `src_dir_fd` and `dst_dir_fd` are not supported by pathlib, so check if they are
|
||||
// are set to non-default values.
|
||||
// set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.rename)
|
||||
// ```text
|
||||
// 0 1 2 3
|
||||
// os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
|
||||
// ```
|
||||
if call
|
||||
.arguments
|
||||
.find_argument_value("src_dir_fd", 2)
|
||||
.is_some_and(|expr| !expr.is_none_literal_expr())
|
||||
|| call
|
||||
.arguments
|
||||
.find_argument_value("dst_dir_fd", 3)
|
||||
.is_some_and(|expr| !expr.is_none_literal_expr())
|
||||
if is_argument_non_default(&call.arguments, "src_dir_fd", 2)
|
||||
|| is_argument_non_default(&call.arguments, "dst_dir_fd", 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
OsRename.into()
|
||||
}
|
||||
// PTH105
|
||||
["os", "replace"] => OsReplace.into(),
|
||||
["os", "replace"] => {
|
||||
// `src_dir_fd` and `dst_dir_fd` are not supported by pathlib, so check if they are
|
||||
// set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.replace)
|
||||
// ```text
|
||||
// 0 1 2 3
|
||||
// os.replace(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "src_dir_fd", 2)
|
||||
|| is_argument_non_default(&call.arguments, "dst_dir_fd", 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
OsReplace.into()
|
||||
}
|
||||
// PTH106
|
||||
["os", "rmdir"] => OsRmdir.into(),
|
||||
["os", "rmdir"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.rmdir)
|
||||
// ```text
|
||||
// 0 1
|
||||
// os.rmdir(path, *, dir_fd=None)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "dir_fd", 1) {
|
||||
return;
|
||||
}
|
||||
OsRmdir.into()
|
||||
}
|
||||
// PTH107
|
||||
["os", "remove"] => OsRemove.into(),
|
||||
["os", "remove"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.remove)
|
||||
// ```text
|
||||
// 0 1
|
||||
// os.remove(path, *, dir_fd=None)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "dir_fd", 1) {
|
||||
return;
|
||||
}
|
||||
OsRemove.into()
|
||||
}
|
||||
// PTH108
|
||||
["os", "unlink"] => OsUnlink.into(),
|
||||
["os", "unlink"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.unlink)
|
||||
// ```text
|
||||
// 0 1
|
||||
// os.unlink(path, *, dir_fd=None)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "dir_fd", 1) {
|
||||
return;
|
||||
}
|
||||
OsUnlink.into()
|
||||
}
|
||||
// PTH109
|
||||
["os", "getcwd"] => OsGetcwd.into(),
|
||||
["os", "getcwdb"] => OsGetcwd.into(),
|
||||
|
@ -76,10 +144,17 @@ pub(crate) fn replaceable_by_pathlib(checker: &Checker, call: &ExprCall) {
|
|||
["os", "path", "islink"] => OsPathIslink.into(),
|
||||
// PTH116
|
||||
["os", "stat"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.stat)
|
||||
// ```text
|
||||
// 0 1 2
|
||||
// os.stat(path, *, dir_fd=None, follow_symlinks=True)
|
||||
// ```
|
||||
if call
|
||||
.arguments
|
||||
.find_positional(0)
|
||||
.find_argument_value("path", 0)
|
||||
.is_some_and(|expr| is_file_descriptor(expr, checker.semantic()))
|
||||
|| is_argument_non_default(&call.arguments, "dir_fd", 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -148,13 +223,10 @@ pub(crate) fn replaceable_by_pathlib(checker: &Checker, call: &ExprCall) {
|
|||
Expr::BooleanLiteral(ExprBooleanLiteral { value: true, .. })
|
||||
)
|
||||
})
|
||||
|| is_argument_non_default(&call.arguments, "opener", 7)
|
||||
|| call
|
||||
.arguments
|
||||
.find_argument_value("opener", 7)
|
||||
.is_some_and(|expr| !expr.is_none_literal_expr())
|
||||
|| call
|
||||
.arguments
|
||||
.find_positional(0)
|
||||
.find_argument_value("file", 0)
|
||||
.is_some_and(|expr| is_file_descriptor(expr, checker.semantic()))
|
||||
{
|
||||
return;
|
||||
|
@ -164,17 +236,53 @@ pub(crate) fn replaceable_by_pathlib(checker: &Checker, call: &ExprCall) {
|
|||
// PTH124
|
||||
["py", "path", "local"] => PyPath.into(),
|
||||
// PTH207
|
||||
["glob", "glob"] => Glob {
|
||||
function: "glob".to_string(),
|
||||
["glob", "glob"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/glob.html#glob.glob)
|
||||
// ```text
|
||||
// 0 1 2 3 4
|
||||
// glob.glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, include_hidden=False)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "dir_fd", 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Glob {
|
||||
function: "glob".to_string(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
.into(),
|
||||
["glob", "iglob"] => Glob {
|
||||
function: "iglob".to_string(),
|
||||
|
||||
["glob", "iglob"] => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/glob.html#glob.iglob)
|
||||
// ```text
|
||||
// 0 1 2 3 4
|
||||
// glob.iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False, include_hidden=False)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "dir_fd", 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Glob {
|
||||
function: "iglob".to_string(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
.into(),
|
||||
// PTH115
|
||||
// Python 3.9+
|
||||
["os", "readlink"] if checker.target_version() >= PythonVersion::PY39 => OsReadlink.into(),
|
||||
["os", "readlink"] if checker.target_version() >= PythonVersion::PY39 => {
|
||||
// `dir_fd` is not supported by pathlib, so check if it's set to non-default values.
|
||||
// Signature as of Python 3.13 (https://docs.python.org/3/library/os.html#os.readlink)
|
||||
// ```text
|
||||
// 0 1
|
||||
// os.readlink(path, *, dir_fd=None)
|
||||
// ```
|
||||
if is_argument_non_default(&call.arguments, "dir_fd", 1) {
|
||||
return;
|
||||
}
|
||||
OsReadlink.into()
|
||||
}
|
||||
// PTH208
|
||||
["os", "listdir"] => {
|
||||
if call
|
||||
|
@ -224,3 +332,10 @@ fn get_name_expr(expr: &Expr) -> Option<&ast::ExprName> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if argument `name` is set to a non-default `None` value.
|
||||
fn is_argument_non_default(arguments: &ast::Arguments, name: &str, position: usize) -> bool {
|
||||
arguments
|
||||
.find_argument_value(name, position)
|
||||
.is_some_and(|expr| !expr.is_none_literal_expr())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_use_pathlib/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PTH207.py:9:1: PTH207 Replace `glob` with `Path.glob` or `Path.rglob`
|
||||
|
|
||||
|
@ -26,4 +25,6 @@ PTH207.py:11:1: PTH207 Replace `glob` with `Path.glob` or `Path.rglob`
|
|||
10 | list(glob.iglob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp")))
|
||||
11 | search("*.png")
|
||||
| ^^^^^^ PTH207
|
||||
12 |
|
||||
13 | # if `dir_fd` is set, suppress the diagnostic
|
||||
|
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue