mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-02 04:48:07 +00:00
[pylint] Detect indirect pathlib.Path usages for unspecified-encoding (PLW1514) (#19304)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
## Summary Fixes #19294 --------- Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
This commit is contained in:
parent
291699b375
commit
b2501b45e0
3 changed files with 70 additions and 10 deletions
|
|
@ -91,9 +91,16 @@ Path("foo.txt").write_text(text, encoding="utf-8")
|
|||
Path("foo.txt").write_text(text, *args)
|
||||
Path("foo.txt").write_text(text, **kwargs)
|
||||
|
||||
# Violation but not detectable
|
||||
# https://github.com/astral-sh/ruff/issues/19294
|
||||
x = Path("foo.txt")
|
||||
x.open()
|
||||
|
||||
# https://github.com/astral-sh/ruff/issues/18107
|
||||
codecs.open("plw1514.py", "r", "utf-8").close() # this is fine
|
||||
|
||||
# function argument annotated as Path
|
||||
from pathlib import Path
|
||||
|
||||
def format_file(file: Path):
|
||||
with file.open() as f:
|
||||
contents = f.read()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use ruff_macros::{ViolationMetadata, derive_message_formats};
|
|||
use ruff_python_ast::name::QualifiedName;
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_python_semantic::analyze::typing;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
|
@ -111,20 +112,34 @@ enum Callee<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Callee<'a> {
|
||||
fn is_pathlib_path_call(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||
semantic
|
||||
.resolve_qualified_name(func)
|
||||
.is_some_and(|qualified_name| {
|
||||
matches!(qualified_name.segments(), ["pathlib", "Path"])
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn try_from_call_expression(
|
||||
call: &'a ast::ExprCall,
|
||||
semantic: &'a SemanticModel,
|
||||
) -> Option<Self> {
|
||||
if let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = call.func.as_ref() {
|
||||
// Check for `pathlib.Path(...).open(...)` or equivalent
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
||||
if semantic
|
||||
.resolve_qualified_name(func)
|
||||
.is_some_and(|qualified_name| {
|
||||
matches!(qualified_name.segments(), ["pathlib", "Path"])
|
||||
})
|
||||
{
|
||||
return Some(Callee::Pathlib(attr));
|
||||
// Direct: Path(...).open()
|
||||
if Self::is_pathlib_path_call(value, semantic) {
|
||||
return Some(Callee::Pathlib(attr));
|
||||
}
|
||||
// Indirect: x.open() where x = Path(...)
|
||||
else if let Expr::Name(name) = value.as_ref() {
|
||||
if let Some(binding_id) = semantic.only_binding(name) {
|
||||
let binding = semantic.binding(binding_id);
|
||||
if typing::is_pathlib_path(binding, semantic) {
|
||||
return Some(Callee::Pathlib(attr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -435,3 +435,41 @@ unspecified_encoding.py:80:1: PLW1514 [*] `pathlib.Path(...).write_text` without
|
|||
81 81 |
|
||||
82 82 | # Non-errors.
|
||||
83 83 | Path("foo.txt").open(encoding="utf-8")
|
||||
|
||||
unspecified_encoding.py:96:1: PLW1514 [*] `pathlib.Path(...).open` in text mode without explicit `encoding` argument
|
||||
|
|
||||
94 | # https://github.com/astral-sh/ruff/issues/19294
|
||||
95 | x = Path("foo.txt")
|
||||
96 | x.open()
|
||||
| ^^^^^^ PLW1514
|
||||
97 |
|
||||
98 | # https://github.com/astral-sh/ruff/issues/18107
|
||||
|
|
||||
= help: Add explicit `encoding` argument
|
||||
|
||||
ℹ Unsafe fix
|
||||
93 93 |
|
||||
94 94 | # https://github.com/astral-sh/ruff/issues/19294
|
||||
95 95 | x = Path("foo.txt")
|
||||
96 |-x.open()
|
||||
96 |+x.open(encoding="utf-8")
|
||||
97 97 |
|
||||
98 98 | # https://github.com/astral-sh/ruff/issues/18107
|
||||
99 99 | codecs.open("plw1514.py", "r", "utf-8").close() # this is fine
|
||||
|
||||
unspecified_encoding.py:105:10: PLW1514 [*] `pathlib.Path(...).open` in text mode without explicit `encoding` argument
|
||||
|
|
||||
104 | def format_file(file: Path):
|
||||
105 | with file.open() as f:
|
||||
| ^^^^^^^^^ PLW1514
|
||||
106 | contents = f.read()
|
||||
|
|
||||
= help: Add explicit `encoding` argument
|
||||
|
||||
ℹ Unsafe fix
|
||||
102 102 | from pathlib import Path
|
||||
103 103 |
|
||||
104 104 | def format_file(file: Path):
|
||||
105 |- with file.open() as f:
|
||||
105 |+ with file.open(encoding="utf-8") as f:
|
||||
106 106 | contents = f.read()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue