Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 8 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF064.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,11 @@

os.fchmod(0, 256) # 0o400
os.fchmod(0, 493) # 0o755

# https://github.com/astral-sh/ruff/issues/19010
os.chmod("foo", 000) # Error
os.chmod("foo", 0000) # Error

os.chmod("foo", 0b0) # Error
os.chmod("foo", 0x0) # Error
os.chmod("foo", 0) # Ok
20 changes: 19 additions & 1 deletion crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ use crate::{FixAvailability, Violation};
/// original code really intended to use `0o256` (`u=w,g=rx,o=rw`) instead of
/// `256`, this fix should not be accepted.
///
/// As a special case, zero is allowed to omit the `0o` prefix unless it has
/// multiple digits:
///
/// ```python
/// os.chmod("foo", 0) # Ok
/// os.chmod("foo", 0o000) # Ok
/// os.chmod("foo", 000) # Lint emitted and fix suggested
/// ```
///
/// Ruff will suggest a safe fix for multi-digit zeros to add the `0o` prefix.
///
/// ## Fix availability
///
/// A fix is only available if the integer literal matches a set of common modes.
Expand Down Expand Up @@ -102,7 +113,14 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) {
let mut diagnostic = checker.report_diagnostic(NonOctalPermissions, mode_arg.range());

// Don't suggest a fix for 0x or 0b literals.
if mode_literal.starts_with('0') {
if mode_literal.starts_with("0x") || mode_literal.starts_with("0b") {
return;
}

if mode_literal.chars().all(|c| c == '0') {
// Fix e.g. 000 as 0o000
let edit = Edit::range_replacement(format!("0o{mode_literal}"), mode_arg.range());
diagnostic.set_fix(Fix::safe_edit(edit));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,17 @@ help: Replace with octal literal
52 |-os.fchmod(0, 256) # 0o400
52 |+os.fchmod(0, 0o400) # 0o400
53 53 | os.fchmod(0, 493) # 0o755
54 54 |
55 55 | # https://github.com/astral-sh/ruff/issues/19010

RUF064 [*] Non-octal mode
--> RUF064.py:53:14
|
52 | os.fchmod(0, 256) # 0o400
53 | os.fchmod(0, 493) # 0o755
| ^^^
54 |
55 | # https://github.com/astral-sh/ruff/issues/19010
|
help: Replace with octal literal

Expand All @@ -364,3 +368,70 @@ help: Replace with octal literal
52 52 | os.fchmod(0, 256) # 0o400
53 |-os.fchmod(0, 493) # 0o755
53 |+os.fchmod(0, 0o755) # 0o755
54 54 |
55 55 | # https://github.com/astral-sh/ruff/issues/19010
56 56 | os.chmod("foo", 000) # Error

RUF064 [*] Non-octal mode
--> RUF064.py:56:17
|
55 | # https://github.com/astral-sh/ruff/issues/19010
56 | os.chmod("foo", 000) # Error
| ^^^
57 | os.chmod("foo", 0000) # Error
|
help: Replace with octal literal

ℹ Safe fix
53 53 | os.fchmod(0, 493) # 0o755
54 54 |
55 55 | # https://github.com/astral-sh/ruff/issues/19010
56 |-os.chmod("foo", 000) # Error
56 |+os.chmod("foo", 0o000) # Error
57 57 | os.chmod("foo", 0000) # Error
58 58 |
59 59 | os.chmod("foo", 0b0) # Error

RUF064 [*] Non-octal mode
--> RUF064.py:57:17
|
55 | # https://github.com/astral-sh/ruff/issues/19010
56 | os.chmod("foo", 000) # Error
57 | os.chmod("foo", 0000) # Error
| ^^^^
58 |
59 | os.chmod("foo", 0b0) # Error
|
help: Replace with octal literal

ℹ Safe fix
54 54 |
55 55 | # https://github.com/astral-sh/ruff/issues/19010
56 56 | os.chmod("foo", 000) # Error
57 |-os.chmod("foo", 0000) # Error
57 |+os.chmod("foo", 0o0000) # Error
58 58 |
59 59 | os.chmod("foo", 0b0) # Error
60 60 | os.chmod("foo", 0x0) # Error

RUF064 Non-octal mode
--> RUF064.py:59:17
|
57 | os.chmod("foo", 0000) # Error
58 |
59 | os.chmod("foo", 0b0) # Error
| ^^^
60 | os.chmod("foo", 0x0) # Error
61 | os.chmod("foo", 0) # Ok
|
help: Replace with octal literal

RUF064 Non-octal mode
--> RUF064.py:60:17
|
59 | os.chmod("foo", 0b0) # Error
60 | os.chmod("foo", 0x0) # Error
| ^^^
61 | os.chmod("foo", 0) # Ok
|
help: Replace with octal literal
Loading