mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00
Relax constraints on pep8-naming module validation (#3043)
This commit is contained in:
parent
c297d46899
commit
b39f960cd1
11 changed files with 59 additions and 28 deletions
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/0001_initial.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/0001_initial.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__main__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__main__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__setup__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__setup__.py
vendored
Normal file
|
@ -3,7 +3,7 @@ use schemars::JsonSchema;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use ruff_python::string::is_lower_with_underscore;
|
||||
use ruff_python::identifiers::is_module_name;
|
||||
|
||||
use crate::ast::helpers::{create_stmt, from_relative_import, unparse_stmt};
|
||||
use crate::ast::types::Range;
|
||||
|
@ -103,7 +103,7 @@ fn fix_banned_relative_import(
|
|||
let call_path = from_relative_import(&parts, module);
|
||||
// Require import to be a valid PEP 8 module:
|
||||
// https://python.org/dev/peps/pep-0008/#package-and-module-names
|
||||
if !call_path.iter().all(|part| is_lower_with_underscore(part)) {
|
||||
if !call_path.iter().all(|part| is_module_name(part)) {
|
||||
return None;
|
||||
}
|
||||
call_path.as_slice().join(".")
|
||||
|
@ -112,14 +112,14 @@ fn fix_banned_relative_import(
|
|||
let call_path = from_relative_import(&parts, module);
|
||||
// Require import to be a valid PEP 8 module:
|
||||
// https://python.org/dev/peps/pep-0008/#package-and-module-names
|
||||
if !call_path.iter().all(|part| is_lower_with_underscore(part)) {
|
||||
if !call_path.iter().all(|part| is_module_name(part)) {
|
||||
return None;
|
||||
}
|
||||
call_path.as_slice().join(".")
|
||||
} else {
|
||||
// Require import to be a valid PEP 8 module:
|
||||
// https://python.org/dev/peps/pep-0008/#package-and-module-names
|
||||
if !parts.iter().all(|part| is_lower_with_underscore(part)) {
|
||||
if !parts.iter().all(|part| is_module_name(part)) {
|
||||
return None;
|
||||
}
|
||||
parts.join(".")
|
||||
|
|
|
@ -39,6 +39,9 @@ mod tests {
|
|||
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/valid_name/__init__.py"); "N999_7")]
|
||||
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/no_module/test.txt"); "N999_8")]
|
||||
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/valid_name/file-with-dashes.py"); "N999_9")]
|
||||
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/valid_name/__main__.py"); "N999_10")]
|
||||
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/valid_name/0001_initial.py"); "N999_11")]
|
||||
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/valid_name/__setup__.py"); "N999_12")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::Path;
|
||||
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use ruff_python::string::is_lower_with_underscore;
|
||||
use ruff_python::identifiers::is_module_name;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::registry::Diagnostic;
|
||||
|
@ -44,13 +44,18 @@ impl Violation for InvalidModuleName {
|
|||
/// N999
|
||||
pub fn invalid_module_name(path: &Path, package: Option<&Path>) -> Option<Diagnostic> {
|
||||
if let Some(package) = package {
|
||||
let module_name = if path.file_name().unwrap().to_string_lossy() == "__init__.py" {
|
||||
let module_name = if path.file_name().map_or(false, |file_name| {
|
||||
file_name == "__init__.py"
|
||||
|| file_name == "__init__.pyi"
|
||||
|| file_name == "__main__.py"
|
||||
|| file_name == "__main__.pyi"
|
||||
}) {
|
||||
package.file_name().unwrap().to_string_lossy()
|
||||
} else {
|
||||
path.file_stem().unwrap().to_string_lossy()
|
||||
};
|
||||
|
||||
if !is_lower_with_underscore(&module_name) {
|
||||
if !is_module_name(&module_name) {
|
||||
return Some(Diagnostic::new(
|
||||
InvalidModuleName {
|
||||
name: module_name.to_string(),
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
|
@ -22,3 +22,28 @@ pub fn is_identifier(s: &str) -> bool {
|
|||
pub fn is_mangled_private(id: &str) -> bool {
|
||||
id.starts_with("__") && !id.ends_with("__")
|
||||
}
|
||||
|
||||
/// Returns `true` if a string is a PEP 8-compliant module name (i.e., consists of lowercase
|
||||
/// letters, numbers, and underscores).
|
||||
pub fn is_module_name(s: &str) -> bool {
|
||||
s.chars()
|
||||
.all(|c| c.is_lowercase() || c.is_numeric() || c == '_')
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::identifiers::is_module_name;
|
||||
|
||||
#[test]
|
||||
fn test_is_module_name() {
|
||||
assert!(is_module_name("a"));
|
||||
assert!(is_module_name("abc"));
|
||||
assert!(is_module_name("abc0"));
|
||||
assert!(is_module_name("abc_"));
|
||||
assert!(is_module_name("a_b_c"));
|
||||
assert!(is_module_name("0abc"));
|
||||
assert!(is_module_name("_abc"));
|
||||
assert!(!is_module_name("a-b-c"));
|
||||
assert!(!is_module_name("a_B_c"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ use regex::Regex;
|
|||
|
||||
pub static STRING_QUOTE_PREFIX_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r#"^(?i)[urb]*['"](?P<raw>.*)['"]$"#).unwrap());
|
||||
pub static LOWER_OR_UNDERSCORE: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^[a-z][a-z0-9_]*$").unwrap());
|
||||
|
||||
pub fn is_lower(s: &str) -> bool {
|
||||
let mut cased = false;
|
||||
|
@ -30,11 +28,6 @@ pub fn is_upper(s: &str) -> bool {
|
|||
cased
|
||||
}
|
||||
|
||||
// Module names should be lowercase, and may contain underscore
|
||||
pub fn is_lower_with_underscore(s: &str) -> bool {
|
||||
LOWER_OR_UNDERSCORE.is_match(s)
|
||||
}
|
||||
|
||||
/// Remove prefixes (u, r, b) and quotes around a string. This expects the given
|
||||
/// string to be a valid Python string representation, it doesn't do any
|
||||
/// validation.
|
||||
|
@ -50,7 +43,7 @@ pub fn strip_quotes_and_prefixes(s: &str) -> &str {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::string::{is_lower, is_lower_with_underscore, is_upper, strip_quotes_and_prefixes};
|
||||
use crate::string::{is_lower, is_upper, strip_quotes_and_prefixes};
|
||||
|
||||
#[test]
|
||||
fn test_is_lower() {
|
||||
|
@ -63,19 +56,6 @@ mod tests {
|
|||
assert!(!is_lower("_"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_lower_underscore() {
|
||||
assert!(is_lower_with_underscore("a"));
|
||||
assert!(is_lower_with_underscore("abc"));
|
||||
assert!(is_lower_with_underscore("abc0"));
|
||||
assert!(is_lower_with_underscore("abc_"));
|
||||
assert!(is_lower_with_underscore("a_b_c"));
|
||||
assert!(!is_lower_with_underscore("a-b-c"));
|
||||
assert!(!is_lower_with_underscore("a_B_c"));
|
||||
assert!(!is_lower_with_underscore("0abc"));
|
||||
assert!(!is_lower_with_underscore("_abc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_upper() {
|
||||
assert!(is_upper("ABC"));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue