Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
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))
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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())
}
Original file line number Diff line number Diff line change
@@ -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`
|
Expand All @@ -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