From ecbceaa15b743f1cba244e8ae426f6738a1278dd Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Fri, 21 Jul 2023 04:46:53 +0200 Subject: [PATCH] [`flake8-use-pathlib`] Implement `glob` (`PTH207`) --- .../fixtures/flake8_use_pathlib/PTH207.py | 10 +++++ crates/ruff/src/checkers/ast/mod.rs | 1 + crates/ruff/src/codes.rs | 1 + .../ruff/src/rules/flake8_use_pathlib/mod.rs | 1 + .../flake8_use_pathlib/rules/glob_rule.rs | 41 +++++++++++++++++++ .../src/rules/flake8_use_pathlib/rules/mod.rs | 2 + .../rules/replaceable_by_pathlib.rs | 4 +- ..._use_pathlib__tests__PTH205_PTH207.py.snap | 4 ++ ..._use_pathlib__tests__PTH207_PTH207.py.snap | 20 +++++++++ ruff.schema.json | 1 + 10 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 crates/ruff/resources/test/fixtures/flake8_use_pathlib/PTH207.py create mode 100644 crates/ruff/src/rules/flake8_use_pathlib/rules/glob_rule.rs create mode 100644 crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH205_PTH207.py.snap create mode 100644 crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH207_PTH207.py.snap diff --git a/crates/ruff/resources/test/fixtures/flake8_use_pathlib/PTH207.py b/crates/ruff/resources/test/fixtures/flake8_use_pathlib/PTH207.py new file mode 100644 index 00000000000000..aa3b45dd77df3f --- /dev/null +++ b/crates/ruff/resources/test/fixtures/flake8_use_pathlib/PTH207.py @@ -0,0 +1,10 @@ +import os +import glob +from glob import glob as search + + +extensions_dir = "./extensions" + +# PTH207 +glob.glob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp")) +search("*.png") diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index c48dcb59f4b3b7..d0ea5dd6f016ee 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -3004,6 +3004,7 @@ where Rule::OsPathGetatime, Rule::OsPathGetmtime, Rule::OsPathGetctime, + Rule::Glob, ]) { flake8_use_pathlib::rules::replaceable_by_pathlib(self, func); } diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index 38f97cf14857f7..c1d8a0d39f33b0 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -755,6 +755,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8UsePathlib, "203") => (RuleGroup::Unspecified, rules::flake8_use_pathlib::rules::OsPathGetatime), (Flake8UsePathlib, "204") => (RuleGroup::Unspecified, rules::flake8_use_pathlib::rules::OsPathGetmtime), (Flake8UsePathlib, "205") => (RuleGroup::Unspecified, rules::flake8_use_pathlib::rules::OsPathGetctime), + (Flake8UsePathlib, "207") => (RuleGroup::Unspecified, rules::flake8_use_pathlib::rules::Glob), // flake8-logging-format (Flake8LoggingFormat, "001") => (RuleGroup::Unspecified, rules::flake8_logging_format::violations::LoggingStringFormat), diff --git a/crates/ruff/src/rules/flake8_use_pathlib/mod.rs b/crates/ruff/src/rules/flake8_use_pathlib/mod.rs index 49787956292a43..095df3eb581c4e 100644 --- a/crates/ruff/src/rules/flake8_use_pathlib/mod.rs +++ b/crates/ruff/src/rules/flake8_use_pathlib/mod.rs @@ -61,6 +61,7 @@ mod tests { #[test_case(Rule::OsPathGetatime, Path::new("PTH203.py"))] #[test_case(Rule::OsPathGetmtime, Path::new("PTH204.py"))] #[test_case(Rule::OsPathGetctime, Path::new("PTH205.py"))] + #[test_case(Rule::Glob, Path::new("PTH207.py"))] fn rules_pypath(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff/src/rules/flake8_use_pathlib/rules/glob_rule.rs b/crates/ruff/src/rules/flake8_use_pathlib/rules/glob_rule.rs new file mode 100644 index 00000000000000..3b5fa0dcdaf635 --- /dev/null +++ b/crates/ruff/src/rules/flake8_use_pathlib/rules/glob_rule.rs @@ -0,0 +1,41 @@ +use ruff_diagnostics::Violation; +use ruff_macros::{derive_message_formats, violation}; + +/// ## What it does +/// Checks for the use of `glob`. +/// +/// ## Why is this bad? +/// `pathlib` offers a high-level API for path manipulation, as compared to +/// the lower-level API offered by `os` and `glob`. +/// +/// When possible, using `Path` object methods such as `Path.stat()` can +/// improve readability over their low-level counterparts (e.g., +/// `glob.glob()`). +/// +/// ## Example +/// ```python +/// import glob +/// import os +/// +/// glob.glob(os.path.join(path, "requirements*.txt")) +/// ``` +/// +/// Use instead: +/// ```python +/// from pathlib import Path +/// +/// Path(path).glob("requirements*.txt") +/// +/// ## References +/// - [Python documentation: `Path.glob`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob) +/// - [Python documentation: `glob.glob`](https://docs.python.org/3/library/glob.html#glob.glob) +/// ``` +#[violation] +pub struct Glob; + +impl Violation for Glob { + #[derive_message_formats] + fn message(&self) -> String { + format!("Replace `glob` with `Path.glob`") + } +} diff --git a/crates/ruff/src/rules/flake8_use_pathlib/rules/mod.rs b/crates/ruff/src/rules/flake8_use_pathlib/rules/mod.rs index 07966ab00acbbc..6c79be7a9c82a3 100644 --- a/crates/ruff/src/rules/flake8_use_pathlib/rules/mod.rs +++ b/crates/ruff/src/rules/flake8_use_pathlib/rules/mod.rs @@ -1,3 +1,4 @@ +pub(crate) use glob_rule::*; pub(crate) use os_path_getatime::*; pub(crate) use os_path_getctime::*; pub(crate) use os_path_getmtime::*; @@ -5,6 +6,7 @@ pub(crate) use os_path_getsize::*; pub(crate) use path_constructor_current_directory::*; pub(crate) use replaceable_by_pathlib::*; +mod glob_rule; mod os_path_getatime; mod os_path_getctime; mod os_path_getmtime; diff --git a/crates/ruff/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs b/crates/ruff/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs index c884d3a3e6e8d7..86cd202ce879bb 100644 --- a/crates/ruff/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs +++ b/crates/ruff/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs @@ -5,7 +5,7 @@ use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_use_pathlib::rules::{ - OsPathGetatime, OsPathGetctime, OsPathGetmtime, OsPathGetsize, + Glob, OsPathGetatime, OsPathGetctime, OsPathGetmtime, OsPathGetsize, }; use crate::rules::flake8_use_pathlib::violations::{ BuiltinOpen, OsChmod, OsGetcwd, OsMakedirs, OsMkdir, OsPathAbspath, OsPathBasename, @@ -89,6 +89,8 @@ pub(crate) fn replaceable_by_pathlib(checker: &mut Checker, expr: &Expr) { ["" | "builtin", "open"] => Some(BuiltinOpen.into()), // PTH124 ["py", "path", "local"] => Some(PyPath.into()), + // PTH207 + ["glob", "glob"] => Some(Glob.into()), // PTH115 // Python 3.9+ ["os", "readlink"] if checker.settings.target_version >= PythonVersion::Py39 => { diff --git a/crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH205_PTH207.py.snap b/crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH205_PTH207.py.snap new file mode 100644 index 00000000000000..1bea340c064a66 --- /dev/null +++ b/crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH205_PTH207.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff/src/rules/flake8_use_pathlib/mod.rs +--- + diff --git a/crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH207_PTH207.py.snap b/crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH207_PTH207.py.snap new file mode 100644 index 00000000000000..c8a21e5d8884b2 --- /dev/null +++ b/crates/ruff/src/rules/flake8_use_pathlib/snapshots/ruff__rules__flake8_use_pathlib__tests__PTH207_PTH207.py.snap @@ -0,0 +1,20 @@ +--- +source: crates/ruff/src/rules/flake8_use_pathlib/mod.rs +--- +PTH207.py:9:1: PTH207 Replace `glob` with `Path.glob` + | + 8 | # PTH207 + 9 | glob.glob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp")) + | ^^^^^^^^^ PTH207 +10 | search("*.png") + | + +PTH207.py:10:1: PTH207 Replace `glob` with `Path.glob` + | + 8 | # PTH207 + 9 | glob.glob(os.path.join(extensions_dir, "ops", "autograd", "*.cpp")) +10 | search("*.png") + | ^^^^^^ PTH207 + | + + diff --git a/ruff.schema.json b/ruff.schema.json index 66a99e5a568027..249df2e49db88a 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2333,6 +2333,7 @@ "PTH203", "PTH204", "PTH205", + "PTH207", "PYI", "PYI0", "PYI00",