mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-14 15:40:20 +00:00
Implement flake8-module-naming
(#2855)
- Implement N999 (following flake8-module-naming) in pep8_naming - Refactor pep8_naming: split rules.rs into file per rule - Documentation for majority of the violations Closes https://github.com/charliermarsh/ruff/issues/2734
This commit is contained in:
parent
147c6ff1db
commit
cc30738148
45 changed files with 1263 additions and 591 deletions
27
README.md
27
README.md
|
@ -818,21 +818,22 @@ For more, see [pep8-naming](https://pypi.org/project/pep8-naming/) on PyPI.
|
||||||
|
|
||||||
| Code | Name | Message | Fix |
|
| Code | Name | Message | Fix |
|
||||||
| ---- | ---- | ------- | --- |
|
| ---- | ---- | ------- | --- |
|
||||||
| N801 | invalid-class-name | Class name `{name}` should use CapWords convention | |
|
| N801 | [invalid-class-name](https://beta.ruff.rs/docs/rules/invalid-class-name/) | Class name `{name}` should use CapWords convention | |
|
||||||
| N802 | invalid-function-name | Function name `{name}` should be lowercase | |
|
| N802 | [invalid-function-name](https://beta.ruff.rs/docs/rules/invalid-function-name/) | Function name `{name}` should be lowercase | |
|
||||||
| N803 | invalid-argument-name | Argument name `{name}` should be lowercase | |
|
| N803 | invalid-argument-name | Argument name `{name}` should be lowercase | |
|
||||||
| N804 | invalid-first-argument-name-for-class-method | First argument of a class method should be named `cls` | |
|
| N804 | [invalid-first-argument-name-for-class-method](https://beta.ruff.rs/docs/rules/invalid-first-argument-name-for-class-method/) | First argument of a class method should be named `cls` | |
|
||||||
| N805 | invalid-first-argument-name-for-method | First argument of a method should be named `self` | |
|
| N805 | [invalid-first-argument-name-for-method](https://beta.ruff.rs/docs/rules/invalid-first-argument-name-for-method/) | First argument of a method should be named `self` | |
|
||||||
| N806 | non-lowercase-variable-in-function | Variable `{name}` in function should be lowercase | |
|
| N806 | [non-lowercase-variable-in-function](https://beta.ruff.rs/docs/rules/non-lowercase-variable-in-function/) | Variable `{name}` in function should be lowercase | |
|
||||||
| N807 | dunder-function-name | Function name should not start and end with `__` | |
|
| N807 | [dunder-function-name](https://beta.ruff.rs/docs/rules/dunder-function-name/) | Function name should not start and end with `__` | |
|
||||||
| N811 | constant-imported-as-non-constant | Constant `{name}` imported as non-constant `{asname}` | |
|
| N811 | [constant-imported-as-non-constant](https://beta.ruff.rs/docs/rules/constant-imported-as-non-constant/) | Constant `{name}` imported as non-constant `{asname}` | |
|
||||||
| N812 | lowercase-imported-as-non-lowercase | Lowercase `{name}` imported as non-lowercase `{asname}` | |
|
| N812 | [lowercase-imported-as-non-lowercase](https://beta.ruff.rs/docs/rules/lowercase-imported-as-non-lowercase/) | Lowercase `{name}` imported as non-lowercase `{asname}` | |
|
||||||
| N813 | camelcase-imported-as-lowercase | Camelcase `{name}` imported as lowercase `{asname}` | |
|
| N813 | [camelcase-imported-as-lowercase](https://beta.ruff.rs/docs/rules/camelcase-imported-as-lowercase/) | Camelcase `{name}` imported as lowercase `{asname}` | |
|
||||||
| N814 | camelcase-imported-as-constant | Camelcase `{name}` imported as constant `{asname}` | |
|
| N814 | [camelcase-imported-as-constant](https://beta.ruff.rs/docs/rules/camelcase-imported-as-constant/) | Camelcase `{name}` imported as constant `{asname}` | |
|
||||||
| N815 | mixed-case-variable-in-class-scope | Variable `{name}` in class scope should not be mixedCase | |
|
| N815 | mixed-case-variable-in-class-scope | Variable `{name}` in class scope should not be mixedCase | |
|
||||||
| N816 | mixed-case-variable-in-global-scope | Variable `{name}` in global scope should not be mixedCase | |
|
| N816 | mixed-case-variable-in-global-scope | Variable `{name}` in global scope should not be mixedCase | |
|
||||||
| N817 | camelcase-imported-as-acronym | Camelcase `{name}` imported as acronym `{asname}` | |
|
| N817 | [camelcase-imported-as-acronym](https://beta.ruff.rs/docs/rules/camelcase-imported-as-acronym/) | CamelCase `{name}` imported as acronym `{asname}` | |
|
||||||
| N818 | error-suffix-on-exception-name | Exception name `{name}` should be named with an Error suffix | |
|
| N818 | [error-suffix-on-exception-name](https://beta.ruff.rs/docs/rules/error-suffix-on-exception-name/) | Exception name `{name}` should be named with an Error suffix | |
|
||||||
|
| N999 | [invalid-module-name](https://beta.ruff.rs/docs/rules/invalid-module-name/) | Invalid module name: '{name}' | |
|
||||||
|
|
||||||
### pydocstyle (D)
|
### pydocstyle (D)
|
||||||
|
|
||||||
|
@ -3236,7 +3237,7 @@ raises-require-match-for = ["requests.RequestException"]
|
||||||
#### [`avoid-escape`](#avoid-escape)
|
#### [`avoid-escape`](#avoid-escape)
|
||||||
|
|
||||||
Whether to avoid using single quotes if a string contains single quotes,
|
Whether to avoid using single quotes if a string contains single quotes,
|
||||||
or vice-versa with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes).
|
or vice-versa with double quotes, as per [PEP 8](https://peps.python.org/pep-0008/#string-quotes).
|
||||||
This minimizes the need to escape quotation marks within strings.
|
This minimizes the need to escape quotation marks within strings.
|
||||||
|
|
||||||
**Default value**: `true`
|
**Default value**: `true`
|
||||||
|
|
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/flake9/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/flake9/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file2.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file2.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod-with-dashes/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod-with-dashes/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/no_module/test.txt
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/no_module/test.txt
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/file-with-dashes.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/file-with-dashes.py
vendored
Normal file
|
@ -2,6 +2,7 @@ use std::path::Path;
|
||||||
|
|
||||||
use crate::registry::{Diagnostic, Rule};
|
use crate::registry::{Diagnostic, Rule};
|
||||||
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
|
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
|
||||||
|
use crate::rules::pep8_naming::rules::invalid_module_name;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
pub fn check_file_path(
|
pub fn check_file_path(
|
||||||
|
@ -20,5 +21,12 @@ pub fn check_file_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pep8-naming
|
||||||
|
if settings.rules.enabled(&Rule::InvalidModuleName) {
|
||||||
|
if let Some(diagnostic) = invalid_module_name(path, package) {
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diagnostics
|
diagnostics
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,6 +391,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||||
(PEP8Naming, "816") => Rule::MixedCaseVariableInGlobalScope,
|
(PEP8Naming, "816") => Rule::MixedCaseVariableInGlobalScope,
|
||||||
(PEP8Naming, "817") => Rule::CamelcaseImportedAsAcronym,
|
(PEP8Naming, "817") => Rule::CamelcaseImportedAsAcronym,
|
||||||
(PEP8Naming, "818") => Rule::ErrorSuffixOnExceptionName,
|
(PEP8Naming, "818") => Rule::ErrorSuffixOnExceptionName,
|
||||||
|
(PEP8Naming, "999") => Rule::InvalidModuleName,
|
||||||
|
|
||||||
// isort
|
// isort
|
||||||
(Isort, "001") => Rule::UnsortedImports,
|
(Isort, "001") => Rule::UnsortedImports,
|
||||||
|
|
|
@ -376,6 +376,7 @@ ruff_macros::register_rules!(
|
||||||
rules::pep8_naming::rules::MixedCaseVariableInGlobalScope,
|
rules::pep8_naming::rules::MixedCaseVariableInGlobalScope,
|
||||||
rules::pep8_naming::rules::CamelcaseImportedAsAcronym,
|
rules::pep8_naming::rules::CamelcaseImportedAsAcronym,
|
||||||
rules::pep8_naming::rules::ErrorSuffixOnExceptionName,
|
rules::pep8_naming::rules::ErrorSuffixOnExceptionName,
|
||||||
|
rules::pep8_naming::rules::InvalidModuleName,
|
||||||
// isort
|
// isort
|
||||||
rules::isort::rules::UnsortedImports,
|
rules::isort::rules::UnsortedImports,
|
||||||
rules::isort::rules::MissingRequiredImport,
|
rules::isort::rules::MissingRequiredImport,
|
||||||
|
@ -796,7 +797,7 @@ impl Rule {
|
||||||
| Rule::TrailingCommaProhibited => &LintSource::Tokens,
|
| Rule::TrailingCommaProhibited => &LintSource::Tokens,
|
||||||
Rule::IOError => &LintSource::Io,
|
Rule::IOError => &LintSource::Io,
|
||||||
Rule::UnsortedImports | Rule::MissingRequiredImport => &LintSource::Imports,
|
Rule::UnsortedImports | Rule::MissingRequiredImport => &LintSource::Imports,
|
||||||
Rule::ImplicitNamespacePackage => &LintSource::Filesystem,
|
Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => &LintSource::Filesystem,
|
||||||
#[cfg(feature = "logical_lines")]
|
#[cfg(feature = "logical_lines")]
|
||||||
Rule::IndentationWithInvalidMultiple
|
Rule::IndentationWithInvalidMultiple
|
||||||
| Rule::IndentationWithInvalidMultipleComment
|
| Rule::IndentationWithInvalidMultipleComment
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub struct Options {
|
||||||
"#
|
"#
|
||||||
)]
|
)]
|
||||||
/// Whether to avoid using single quotes if a string contains single quotes,
|
/// Whether to avoid using single quotes if a string contains single quotes,
|
||||||
/// or vice-versa with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes).
|
/// or vice-versa with double quotes, as per [PEP 8](https://peps.python.org/pep-0008/#string-quotes).
|
||||||
/// This minimizes the need to escape quotation marks within strings.
|
/// This minimizes the need to escape quotation marks within strings.
|
||||||
pub avoid_escape: Option<bool>,
|
pub avoid_escape: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,22 @@ mod tests {
|
||||||
#[test_case(Rule::MixedCaseVariableInGlobalScope, Path::new("N816.py"); "N816")]
|
#[test_case(Rule::MixedCaseVariableInGlobalScope, Path::new("N816.py"); "N816")]
|
||||||
#[test_case(Rule::CamelcaseImportedAsAcronym, Path::new("N817.py"); "N817")]
|
#[test_case(Rule::CamelcaseImportedAsAcronym, Path::new("N817.py"); "N817")]
|
||||||
#[test_case(Rule::ErrorSuffixOnExceptionName, Path::new("N818.py"); "N818")]
|
#[test_case(Rule::ErrorSuffixOnExceptionName, Path::new("N818.py"); "N818")]
|
||||||
|
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/mod with spaces/__init__.py"); "N999_1")]
|
||||||
|
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/mod with spaces/file.py"); "N999_2")]
|
||||||
|
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/flake9/__init__.py"); "N999_3")]
|
||||||
|
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/MODULE/__init__.py"); "N999_4")]
|
||||||
|
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/MODULE/file.py"); "N999_5")]
|
||||||
|
#[test_case(Rule::InvalidModuleName, Path::new("N999/module/mod-with-dashes/__init__.py"); "N999_6")]
|
||||||
|
#[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")]
|
||||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||||
let diagnostics = test_path(
|
let diagnostics = test_path(
|
||||||
Path::new("pep8_naming").join(path).as_path(),
|
Path::new("pep8_naming").join(path).as_path(),
|
||||||
&settings::Settings::for_rule(rule_code),
|
&settings::Settings {
|
||||||
|
..settings::Settings::for_rule(rule_code)
|
||||||
|
},
|
||||||
)?;
|
)?;
|
||||||
assert_yaml_snapshot!(snapshot, diagnostics);
|
assert_yaml_snapshot!(snapshot, diagnostics);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,573 +0,0 @@
|
||||||
use ruff_macros::{define_violation, derive_message_formats};
|
|
||||||
use ruff_python::string::{self};
|
|
||||||
use rustpython_parser::ast::{Arg, Arguments, Expr, ExprKind, Stmt};
|
|
||||||
|
|
||||||
use super::helpers;
|
|
||||||
use crate::ast::function_type;
|
|
||||||
use crate::ast::helpers::identifier_range;
|
|
||||||
use crate::ast::types::{Range, Scope, ScopeKind};
|
|
||||||
use crate::checkers::ast::Checker;
|
|
||||||
use crate::registry::Diagnostic;
|
|
||||||
use crate::source_code::Locator;
|
|
||||||
use crate::violation::Violation;
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct InvalidClassName {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for InvalidClassName {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let InvalidClassName { name } = self;
|
|
||||||
format!("Class name `{name}` should use CapWords convention ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct InvalidFunctionName {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for InvalidFunctionName {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let InvalidFunctionName { name } = self;
|
|
||||||
format!("Function name `{name}` should be lowercase")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct InvalidArgumentName {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for InvalidArgumentName {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let InvalidArgumentName { name } = self;
|
|
||||||
format!("Argument name `{name}` should be lowercase")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct InvalidFirstArgumentNameForClassMethod;
|
|
||||||
);
|
|
||||||
impl Violation for InvalidFirstArgumentNameForClassMethod {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
format!("First argument of a class method should be named `cls`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct InvalidFirstArgumentNameForMethod;
|
|
||||||
);
|
|
||||||
impl Violation for InvalidFirstArgumentNameForMethod {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
format!("First argument of a method should be named `self`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct NonLowercaseVariableInFunction {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for NonLowercaseVariableInFunction {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let NonLowercaseVariableInFunction { name } = self;
|
|
||||||
format!("Variable `{name}` in function should be lowercase")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct DunderFunctionName;
|
|
||||||
);
|
|
||||||
impl Violation for DunderFunctionName {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
format!("Function name should not start and end with `__`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct ConstantImportedAsNonConstant {
|
|
||||||
pub name: String,
|
|
||||||
pub asname: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for ConstantImportedAsNonConstant {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let ConstantImportedAsNonConstant { name, asname } = self;
|
|
||||||
format!("Constant `{name}` imported as non-constant `{asname}`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct LowercaseImportedAsNonLowercase {
|
|
||||||
pub name: String,
|
|
||||||
pub asname: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for LowercaseImportedAsNonLowercase {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let LowercaseImportedAsNonLowercase { name, asname } = self;
|
|
||||||
format!("Lowercase `{name}` imported as non-lowercase `{asname}`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct CamelcaseImportedAsLowercase {
|
|
||||||
pub name: String,
|
|
||||||
pub asname: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for CamelcaseImportedAsLowercase {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let CamelcaseImportedAsLowercase { name, asname } = self;
|
|
||||||
format!("Camelcase `{name}` imported as lowercase `{asname}`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct CamelcaseImportedAsConstant {
|
|
||||||
pub name: String,
|
|
||||||
pub asname: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for CamelcaseImportedAsConstant {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let CamelcaseImportedAsConstant { name, asname } = self;
|
|
||||||
format!("Camelcase `{name}` imported as constant `{asname}`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct MixedCaseVariableInClassScope {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for MixedCaseVariableInClassScope {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let MixedCaseVariableInClassScope { name } = self;
|
|
||||||
format!("Variable `{name}` in class scope should not be mixedCase")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct MixedCaseVariableInGlobalScope {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for MixedCaseVariableInGlobalScope {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let MixedCaseVariableInGlobalScope { name } = self;
|
|
||||||
format!("Variable `{name}` in global scope should not be mixedCase")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct CamelcaseImportedAsAcronym {
|
|
||||||
pub name: String,
|
|
||||||
pub asname: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for CamelcaseImportedAsAcronym {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let CamelcaseImportedAsAcronym { name, asname } = self;
|
|
||||||
format!("Camelcase `{name}` imported as acronym `{asname}`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_violation!(
|
|
||||||
pub struct ErrorSuffixOnExceptionName {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
impl Violation for ErrorSuffixOnExceptionName {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
let ErrorSuffixOnExceptionName { name } = self;
|
|
||||||
format!("Exception name `{name}` should be named with an Error suffix")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N801
|
|
||||||
pub fn invalid_class_name(class_def: &Stmt, name: &str, locator: &Locator) -> Option<Diagnostic> {
|
|
||||||
let stripped = name.strip_prefix('_').unwrap_or(name);
|
|
||||||
if !stripped.chars().next().map_or(false, char::is_uppercase) || stripped.contains('_') {
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
InvalidClassName {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(class_def, locator),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N802
|
|
||||||
pub fn invalid_function_name(
|
|
||||||
func_def: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
ignore_names: &[String],
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if ignore_names.iter().any(|ignore_name| ignore_name == name) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if name.to_lowercase() != name {
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
InvalidFunctionName {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(func_def, locator),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N803
|
|
||||||
pub fn invalid_argument_name(name: &str, arg: &Arg, ignore_names: &[String]) -> Option<Diagnostic> {
|
|
||||||
if ignore_names.iter().any(|ignore_name| ignore_name == name) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if name.to_lowercase() != name {
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
InvalidArgumentName {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
Range::from_located(arg),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N804
|
|
||||||
pub fn invalid_first_argument_name_for_class_method(
|
|
||||||
checker: &Checker,
|
|
||||||
scope: &Scope,
|
|
||||||
name: &str,
|
|
||||||
decorator_list: &[Expr],
|
|
||||||
args: &Arguments,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if !matches!(
|
|
||||||
function_type::classify(
|
|
||||||
checker,
|
|
||||||
scope,
|
|
||||||
name,
|
|
||||||
decorator_list,
|
|
||||||
&checker.settings.pep8_naming.classmethod_decorators,
|
|
||||||
&checker.settings.pep8_naming.staticmethod_decorators,
|
|
||||||
),
|
|
||||||
function_type::FunctionType::ClassMethod
|
|
||||||
) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
|
||||||
if arg.node.arg != "cls" {
|
|
||||||
if checker
|
|
||||||
.settings
|
|
||||||
.pep8_naming
|
|
||||||
.ignore_names
|
|
||||||
.iter()
|
|
||||||
.any(|ignore_name| ignore_name == name)
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
InvalidFirstArgumentNameForClassMethod,
|
|
||||||
Range::from_located(arg),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N805
|
|
||||||
pub fn invalid_first_argument_name_for_method(
|
|
||||||
checker: &Checker,
|
|
||||||
scope: &Scope,
|
|
||||||
name: &str,
|
|
||||||
decorator_list: &[Expr],
|
|
||||||
args: &Arguments,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if !matches!(
|
|
||||||
function_type::classify(
|
|
||||||
checker,
|
|
||||||
scope,
|
|
||||||
name,
|
|
||||||
decorator_list,
|
|
||||||
&checker.settings.pep8_naming.classmethod_decorators,
|
|
||||||
&checker.settings.pep8_naming.staticmethod_decorators,
|
|
||||||
),
|
|
||||||
function_type::FunctionType::Method
|
|
||||||
) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let arg = args.posonlyargs.first().or_else(|| args.args.first())?;
|
|
||||||
if arg.node.arg == "self" {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if checker
|
|
||||||
.settings
|
|
||||||
.pep8_naming
|
|
||||||
.ignore_names
|
|
||||||
.iter()
|
|
||||||
.any(|ignore_name| ignore_name == name)
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(Diagnostic::new(
|
|
||||||
InvalidFirstArgumentNameForMethod,
|
|
||||||
Range::from_located(arg),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N806
|
|
||||||
pub fn non_lowercase_variable_in_function(
|
|
||||||
checker: &mut Checker,
|
|
||||||
expr: &Expr,
|
|
||||||
stmt: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
) {
|
|
||||||
if checker
|
|
||||||
.settings
|
|
||||||
.pep8_naming
|
|
||||||
.ignore_names
|
|
||||||
.iter()
|
|
||||||
.any(|ignore_name| ignore_name == name)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if name.to_lowercase() != name
|
|
||||||
&& !helpers::is_namedtuple_assignment(checker, stmt)
|
|
||||||
&& !helpers::is_typeddict_assignment(checker, stmt)
|
|
||||||
&& !helpers::is_type_var_assignment(checker, stmt)
|
|
||||||
{
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
|
||||||
NonLowercaseVariableInFunction {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
Range::from_located(expr),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N807
|
|
||||||
pub fn dunder_function_name(
|
|
||||||
scope: &Scope,
|
|
||||||
stmt: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if matches!(scope.kind, ScopeKind::Class(_)) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if !(name.starts_with("__") && name.ends_with("__")) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
// Allowed under PEP 562 (https://peps.python.org/pep-0562/).
|
|
||||||
if matches!(scope.kind, ScopeKind::Module) && (name == "__getattr__" || name == "__dir__") {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Diagnostic::new(
|
|
||||||
DunderFunctionName,
|
|
||||||
identifier_range(stmt, locator),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N811
|
|
||||||
pub fn constant_imported_as_non_constant(
|
|
||||||
import_from: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
asname: &str,
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if string::is_upper(name) && !string::is_upper(asname) {
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
ConstantImportedAsNonConstant {
|
|
||||||
name: name.to_string(),
|
|
||||||
asname: asname.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(import_from, locator),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N812
|
|
||||||
pub fn lowercase_imported_as_non_lowercase(
|
|
||||||
import_from: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
asname: &str,
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if !string::is_upper(name) && string::is_lower(name) && asname.to_lowercase() != asname {
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
LowercaseImportedAsNonLowercase {
|
|
||||||
name: name.to_string(),
|
|
||||||
asname: asname.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(import_from, locator),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N813
|
|
||||||
pub fn camelcase_imported_as_lowercase(
|
|
||||||
import_from: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
asname: &str,
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if helpers::is_camelcase(name) && string::is_lower(asname) {
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
CamelcaseImportedAsLowercase {
|
|
||||||
name: name.to_string(),
|
|
||||||
asname: asname.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(import_from, locator),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N814
|
|
||||||
pub fn camelcase_imported_as_constant(
|
|
||||||
import_from: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
asname: &str,
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if helpers::is_camelcase(name)
|
|
||||||
&& !string::is_lower(asname)
|
|
||||||
&& string::is_upper(asname)
|
|
||||||
&& !helpers::is_acronym(name, asname)
|
|
||||||
{
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
CamelcaseImportedAsConstant {
|
|
||||||
name: name.to_string(),
|
|
||||||
asname: asname.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(import_from, locator),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N815
|
|
||||||
pub fn mixed_case_variable_in_class_scope(
|
|
||||||
checker: &mut Checker,
|
|
||||||
expr: &Expr,
|
|
||||||
stmt: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
) {
|
|
||||||
if checker
|
|
||||||
.settings
|
|
||||||
.pep8_naming
|
|
||||||
.ignore_names
|
|
||||||
.iter()
|
|
||||||
.any(|ignore_name| ignore_name == name)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if helpers::is_mixed_case(name) && !helpers::is_namedtuple_assignment(checker, stmt) {
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
|
||||||
MixedCaseVariableInClassScope {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
Range::from_located(expr),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N816
|
|
||||||
pub fn mixed_case_variable_in_global_scope(
|
|
||||||
checker: &mut Checker,
|
|
||||||
expr: &Expr,
|
|
||||||
stmt: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
) {
|
|
||||||
if checker
|
|
||||||
.settings
|
|
||||||
.pep8_naming
|
|
||||||
.ignore_names
|
|
||||||
.iter()
|
|
||||||
.any(|ignore_name| ignore_name == name)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if helpers::is_mixed_case(name) && !helpers::is_namedtuple_assignment(checker, stmt) {
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
|
||||||
MixedCaseVariableInGlobalScope {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
Range::from_located(expr),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N817
|
|
||||||
pub fn camelcase_imported_as_acronym(
|
|
||||||
import_from: &Stmt,
|
|
||||||
name: &str,
|
|
||||||
asname: &str,
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if helpers::is_camelcase(name)
|
|
||||||
&& !string::is_lower(asname)
|
|
||||||
&& string::is_upper(asname)
|
|
||||||
&& helpers::is_acronym(name, asname)
|
|
||||||
{
|
|
||||||
return Some(Diagnostic::new(
|
|
||||||
CamelcaseImportedAsAcronym {
|
|
||||||
name: name.to_string(),
|
|
||||||
asname: asname.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(import_from, locator),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// N818
|
|
||||||
pub fn error_suffix_on_exception_name(
|
|
||||||
class_def: &Stmt,
|
|
||||||
bases: &[Expr],
|
|
||||||
name: &str,
|
|
||||||
locator: &Locator,
|
|
||||||
) -> Option<Diagnostic> {
|
|
||||||
if !bases.iter().any(|base| {
|
|
||||||
if let ExprKind::Name { id, .. } = &base.node {
|
|
||||||
id == "Exception" || id.ends_with("Error")
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if name.ends_with("Error") {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(Diagnostic::new(
|
|
||||||
ErrorSuffixOnExceptionName {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
identifier_range(class_def, locator),
|
|
||||||
))
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use ruff_python::string::{self};
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::rules::pep8_naming::helpers;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for `CamelCase` imports that are aliased as acronyms.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends naming conventions for classes, functions,
|
||||||
|
/// constants, and more. The use of inconsistent naming styles between
|
||||||
|
/// import and alias names may lead readers to expect an import to be of
|
||||||
|
/// another type (e.g., confuse a Python class with a constant).
|
||||||
|
///
|
||||||
|
/// Import aliases should thus follow the same naming style as the member
|
||||||
|
/// being imported.
|
||||||
|
///
|
||||||
|
/// Note that this rule is distinct from `camelcase-imported-as-constant`
|
||||||
|
/// to accommodate selective enforcement.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// from example import MyClassName as MCN
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// from example import MyClassName
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
|
pub struct CamelcaseImportedAsAcronym {
|
||||||
|
pub name: String,
|
||||||
|
pub asname: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for CamelcaseImportedAsAcronym {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let CamelcaseImportedAsAcronym { name, asname } = self;
|
||||||
|
format!("CamelCase `{name}` imported as acronym `{asname}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N817
|
||||||
|
pub fn camelcase_imported_as_acronym(
|
||||||
|
import_from: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
asname: &str,
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if helpers::is_camelcase(name)
|
||||||
|
&& !string::is_lower(asname)
|
||||||
|
&& string::is_upper(asname)
|
||||||
|
&& helpers::is_acronym(name, asname)
|
||||||
|
{
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
CamelcaseImportedAsAcronym {
|
||||||
|
name: name.to_string(),
|
||||||
|
asname: asname.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(import_from, locator),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use ruff_python::string::{self};
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::rules::pep8_naming::helpers;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for `CamelCase` imports that are aliased to constant-style names.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends naming conventions for classes, functions,
|
||||||
|
/// constants, and more. The use of inconsistent naming styles between
|
||||||
|
/// import and alias names may lead readers to expect an import to be of
|
||||||
|
/// another type (e.g., confuse a Python class with a constant).
|
||||||
|
///
|
||||||
|
/// Import aliases should thus follow the same naming style as the member
|
||||||
|
/// being imported.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// from example import MyClassName as MY_CLASS_NAME
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// from example import MyClassName
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
|
pub struct CamelcaseImportedAsConstant {
|
||||||
|
pub name: String,
|
||||||
|
pub asname: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for CamelcaseImportedAsConstant {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let CamelcaseImportedAsConstant { name, asname } = self;
|
||||||
|
format!("Camelcase `{name}` imported as constant `{asname}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N814
|
||||||
|
pub fn camelcase_imported_as_constant(
|
||||||
|
import_from: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
asname: &str,
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if helpers::is_camelcase(name)
|
||||||
|
&& !string::is_lower(asname)
|
||||||
|
&& string::is_upper(asname)
|
||||||
|
&& !helpers::is_acronym(name, asname)
|
||||||
|
{
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
CamelcaseImportedAsConstant {
|
||||||
|
name: name.to_string(),
|
||||||
|
asname: asname.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(import_from, locator),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use ruff_python::string;
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::rules::pep8_naming::helpers;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for `CamelCase` imports that are aliased to lowercase names.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends naming conventions for classes, functions,
|
||||||
|
/// constants, and more. The use of inconsistent naming styles between
|
||||||
|
/// import and alias names may lead readers to expect an import to be of
|
||||||
|
/// another type (e.g., confuse a Python class with a constant).
|
||||||
|
///
|
||||||
|
/// Import aliases should thus follow the same naming style as the member
|
||||||
|
/// being imported.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// from example import MyClassName as myclassname
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// from example import MyClassName
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
|
pub struct CamelcaseImportedAsLowercase {
|
||||||
|
pub name: String,
|
||||||
|
pub asname: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for CamelcaseImportedAsLowercase {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let CamelcaseImportedAsLowercase { name, asname } = self;
|
||||||
|
format!("Camelcase `{name}` imported as lowercase `{asname}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N813
|
||||||
|
pub fn camelcase_imported_as_lowercase(
|
||||||
|
import_from: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
asname: &str,
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if helpers::is_camelcase(name) && string::is_lower(asname) {
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
CamelcaseImportedAsLowercase {
|
||||||
|
name: name.to_string(),
|
||||||
|
asname: asname.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(import_from, locator),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use ruff_python::string;
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for constant imports that are aliased to non-constant-style
|
||||||
|
/// names.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends naming conventions for classes, functions,
|
||||||
|
/// constants, and more. The use of inconsistent naming styles between
|
||||||
|
/// import and alias names may lead readers to expect an import to be of
|
||||||
|
/// another type (e.g., confuse a Python class with a constant).
|
||||||
|
///
|
||||||
|
/// Import aliases should thus follow the same naming style as the member
|
||||||
|
/// being imported.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// from example import CONSTANT_VALUE as ConstantValue
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// from example import CONSTANT_VALUE
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
|
pub struct ConstantImportedAsNonConstant {
|
||||||
|
pub name: String,
|
||||||
|
pub asname: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for ConstantImportedAsNonConstant {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let ConstantImportedAsNonConstant { name, asname } = self;
|
||||||
|
format!("Constant `{name}` imported as non-constant `{asname}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N811
|
||||||
|
pub fn constant_imported_as_non_constant(
|
||||||
|
import_from: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
asname: &str,
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if string::is_upper(name) && !string::is_upper(asname) {
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
ConstantImportedAsNonConstant {
|
||||||
|
name: name.to_string(),
|
||||||
|
asname: asname.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(import_from, locator),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::ast::types::{Scope, ScopeKind};
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for functions with "dunder" names (that is, names with two
|
||||||
|
/// leading and trailing underscores) that are not documented.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends that only documented "dunder" methods are used:
|
||||||
|
///
|
||||||
|
/// > ..."magic" objects or attributes that live in user-controlled
|
||||||
|
/// > namespaces. E.g. `__init__`, `__import__` or `__file__`. Never invent
|
||||||
|
/// such names; only use them as documented.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// def __my_function__():
|
||||||
|
/// pass
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// def my_function():
|
||||||
|
/// pass
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
|
pub struct DunderFunctionName;
|
||||||
|
);
|
||||||
|
impl Violation for DunderFunctionName {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("Function name should not start and end with `__`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N807
|
||||||
|
pub fn dunder_function_name(
|
||||||
|
scope: &Scope,
|
||||||
|
stmt: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if matches!(scope.kind, ScopeKind::Class(_)) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if !(name.starts_with("__") && name.ends_with("__")) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Allowed under PEP 562 (https://peps.python.org/pep-0562/).
|
||||||
|
if matches!(scope.kind, ScopeKind::Module) && (name == "__getattr__" || name == "__dir__") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Diagnostic::new(
|
||||||
|
DunderFunctionName,
|
||||||
|
identifier_range(stmt, locator),
|
||||||
|
))
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::{Expr, ExprKind, Stmt};
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for custom exception definitions that omit the `Error` suffix.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// The `Error` suffix is recommended by [PEP 8]:
|
||||||
|
///
|
||||||
|
/// > Because exceptions should be classes, the class naming convention
|
||||||
|
/// > applies here. However, you should use the suffix `"Error"` on your
|
||||||
|
/// > exception names (if the exception actually is an error).
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// class Validation(Exception):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// class ValidationError(Exception):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/#exception-names
|
||||||
|
pub struct ErrorSuffixOnExceptionName {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for ErrorSuffixOnExceptionName {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let ErrorSuffixOnExceptionName { name } = self;
|
||||||
|
format!("Exception name `{name}` should be named with an Error suffix")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N818
|
||||||
|
pub fn error_suffix_on_exception_name(
|
||||||
|
class_def: &Stmt,
|
||||||
|
bases: &[Expr],
|
||||||
|
name: &str,
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if !bases.iter().any(|base| {
|
||||||
|
if let ExprKind::Name { id, .. } = &base.node {
|
||||||
|
id == "Exception" || id.ends_with("Error")
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.ends_with("Error") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Diagnostic::new(
|
||||||
|
ErrorSuffixOnExceptionName {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(class_def, locator),
|
||||||
|
))
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::Arg;
|
||||||
|
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
pub struct InvalidArgumentName {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for InvalidArgumentName {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let InvalidArgumentName { name } = self;
|
||||||
|
format!("Argument name `{name}` should be lowercase")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N803
|
||||||
|
pub fn invalid_argument_name(name: &str, arg: &Arg, ignore_names: &[String]) -> Option<Diagnostic> {
|
||||||
|
if ignore_names.iter().any(|ignore_name| ignore_name == name) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if name.to_lowercase() != name {
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
InvalidArgumentName {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
Range::from_located(arg),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for class names that do not follow the `CamelCase` convention.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends the use of the `CapWords` (or `CamelCase`) convention
|
||||||
|
/// for class names:
|
||||||
|
///
|
||||||
|
/// > Class names should normally use the `CapWords` convention.
|
||||||
|
/// >
|
||||||
|
/// > The naming convention for functions may be used instead in cases where the interface is
|
||||||
|
/// > documented and used primarily as a callable.
|
||||||
|
/// >
|
||||||
|
/// > Note that there is a separate convention for builtin names: most builtin names are single
|
||||||
|
/// > words (or two words run together), with the `CapWords` convention used only for exception
|
||||||
|
/// > names and builtin constants.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// class my_class:
|
||||||
|
/// pass
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// class MyClass:
|
||||||
|
/// pass
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/#class-names
|
||||||
|
pub struct InvalidClassName {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for InvalidClassName {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let InvalidClassName { name } = self;
|
||||||
|
format!("Class name `{name}` should use CapWords convention ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N801
|
||||||
|
pub fn invalid_class_name(class_def: &Stmt, name: &str, locator: &Locator) -> Option<Diagnostic> {
|
||||||
|
let stripped = name.strip_prefix('_').unwrap_or(name);
|
||||||
|
if !stripped.chars().next().map_or(false, char::is_uppercase) || stripped.contains('_') {
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
InvalidClassName {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(class_def, locator),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::{Arguments, Expr};
|
||||||
|
|
||||||
|
use crate::ast::function_type;
|
||||||
|
use crate::ast::types::{Range, Scope};
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for class methods that use a name other than `cls` for their
|
||||||
|
/// first argument.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends the use of `cls` as the first argument for all class
|
||||||
|
/// methods:
|
||||||
|
///
|
||||||
|
/// > Always use cls for the first argument to class methods.
|
||||||
|
/// >
|
||||||
|
/// > If a function argument’s name clashes with a reserved keyword, it is generally better to
|
||||||
|
/// > append a single trailing underscore rather than use an abbreviation or spelling corruption.
|
||||||
|
/// > Thus class_ is better than clss. (Perhaps better is to avoid such clashes by using a synonym.)
|
||||||
|
///
|
||||||
|
/// ## Options
|
||||||
|
/// * `pep8-naming.classmethod-decorators`
|
||||||
|
/// * `pep8-naming.staticmethod-decorators`
|
||||||
|
/// * `pep8-naming.ignore-names`
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// class Example:
|
||||||
|
/// @classmethod
|
||||||
|
/// def function(self, data):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// class Example:
|
||||||
|
/// @classmethod
|
||||||
|
/// def function(cls, data):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-method-arguments
|
||||||
|
///
|
||||||
|
pub struct InvalidFirstArgumentNameForClassMethod;
|
||||||
|
);
|
||||||
|
impl Violation for InvalidFirstArgumentNameForClassMethod {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("First argument of a class method should be named `cls`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N804
|
||||||
|
pub fn invalid_first_argument_name_for_class_method(
|
||||||
|
checker: &Checker,
|
||||||
|
scope: &Scope,
|
||||||
|
name: &str,
|
||||||
|
decorator_list: &[Expr],
|
||||||
|
args: &Arguments,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if !matches!(
|
||||||
|
function_type::classify(
|
||||||
|
checker,
|
||||||
|
scope,
|
||||||
|
name,
|
||||||
|
decorator_list,
|
||||||
|
&checker.settings.pep8_naming.classmethod_decorators,
|
||||||
|
&checker.settings.pep8_naming.staticmethod_decorators,
|
||||||
|
),
|
||||||
|
function_type::FunctionType::ClassMethod
|
||||||
|
) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||||
|
if arg.node.arg != "cls" {
|
||||||
|
if checker
|
||||||
|
.settings
|
||||||
|
.pep8_naming
|
||||||
|
.ignore_names
|
||||||
|
.iter()
|
||||||
|
.any(|ignore_name| ignore_name == name)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
InvalidFirstArgumentNameForClassMethod,
|
||||||
|
Range::from_located(arg),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::{Arguments, Expr};
|
||||||
|
|
||||||
|
use crate::ast::function_type;
|
||||||
|
use crate::ast::types::{Range, Scope};
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for instance methods that use a name other than `self` for their
|
||||||
|
/// first argument.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends the use of `self` as first argument for all instance
|
||||||
|
/// methods:
|
||||||
|
///
|
||||||
|
/// > Always use self for the first argument to instance methods.
|
||||||
|
/// >
|
||||||
|
/// > If a function argument’s name clashes with a reserved keyword, it is generally better to
|
||||||
|
/// > append a single trailing underscore rather than use an abbreviation or spelling corruption.
|
||||||
|
/// > Thus class_ is better than clss. (Perhaps better is to avoid such clashes by using a synonym.)
|
||||||
|
///
|
||||||
|
/// ## Options
|
||||||
|
/// * `pep8-naming.classmethod-decorators`
|
||||||
|
/// * `pep8-naming.staticmethod-decorators`
|
||||||
|
/// * `pep8-naming.ignore-names`
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// class Example:
|
||||||
|
/// def function(cls, data):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// class Example:
|
||||||
|
/// def function(self, data):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-method-arguments
|
||||||
|
pub struct InvalidFirstArgumentNameForMethod;
|
||||||
|
);
|
||||||
|
impl Violation for InvalidFirstArgumentNameForMethod {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("First argument of a method should be named `self`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N805
|
||||||
|
pub fn invalid_first_argument_name_for_method(
|
||||||
|
checker: &Checker,
|
||||||
|
scope: &Scope,
|
||||||
|
name: &str,
|
||||||
|
decorator_list: &[Expr],
|
||||||
|
args: &Arguments,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if !matches!(
|
||||||
|
function_type::classify(
|
||||||
|
checker,
|
||||||
|
scope,
|
||||||
|
name,
|
||||||
|
decorator_list,
|
||||||
|
&checker.settings.pep8_naming.classmethod_decorators,
|
||||||
|
&checker.settings.pep8_naming.staticmethod_decorators,
|
||||||
|
),
|
||||||
|
function_type::FunctionType::Method
|
||||||
|
) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let arg = args.posonlyargs.first().or_else(|| args.args.first())?;
|
||||||
|
if arg.node.arg == "self" {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if checker
|
||||||
|
.settings
|
||||||
|
.pep8_naming
|
||||||
|
.ignore_names
|
||||||
|
.iter()
|
||||||
|
.any(|ignore_name| ignore_name == name)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Diagnostic::new(
|
||||||
|
InvalidFirstArgumentNameForMethod,
|
||||||
|
Range::from_located(arg),
|
||||||
|
))
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for functions names that do not follow the `snake_case` naming
|
||||||
|
/// convention.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends that function names follow `snake_case`:
|
||||||
|
///
|
||||||
|
/// > Function names should be lowercase, with words separated by underscores as necessary to
|
||||||
|
/// > improve readability. mixedCase is allowed only in contexts where that’s already the
|
||||||
|
/// > prevailing style (e.g. threading.py), to retain backwards compatibility.
|
||||||
|
///
|
||||||
|
/// ## Options
|
||||||
|
/// * `pep8-naming.ignore-names`
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// def myFunction():
|
||||||
|
/// pass
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// def my_function():
|
||||||
|
/// pass
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-variable-names
|
||||||
|
pub struct InvalidFunctionName {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for InvalidFunctionName {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let InvalidFunctionName { name } = self;
|
||||||
|
format!("Function name `{name}` should be lowercase")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N802
|
||||||
|
pub fn invalid_function_name(
|
||||||
|
func_def: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
ignore_names: &[String],
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if ignore_names.iter().any(|ignore_name| ignore_name == name) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if name.to_lowercase() != name {
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
InvalidFunctionName {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(func_def, locator),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use ruff_python::string::is_lower_with_underscore;
|
||||||
|
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for module names that do not follow the `snake_case` naming
|
||||||
|
/// convention.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends the use of the `snake_case` naming convention for
|
||||||
|
/// module names:
|
||||||
|
///
|
||||||
|
/// > Modules should have short, all-lowercase names. Underscores can be used in the
|
||||||
|
/// > module name if it improves readability. Python packages should also have short,
|
||||||
|
/// > all-lowercase names, although the use of underscores is discouraged.
|
||||||
|
/// >
|
||||||
|
/// > When an extension module written in C or C++ has an accompanying Python module that
|
||||||
|
/// > provides a higher level (e.g. more object oriented) interface, the C/C++ module has
|
||||||
|
/// > a leading underscore (e.g. `_socket`).
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// * Instead of `example-module-name` or `example module name`, use `example_module_name`.
|
||||||
|
/// * Instead of `ExampleModule`, use `example_module`.
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/#package-and-module-names
|
||||||
|
pub struct InvalidModuleName {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for InvalidModuleName {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let InvalidModuleName { name } = self;
|
||||||
|
format!("Invalid module name: '{name}'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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" {
|
||||||
|
package.file_name().unwrap().to_string_lossy()
|
||||||
|
} else {
|
||||||
|
path.file_stem().unwrap().to_string_lossy()
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_lower_with_underscore(&module_name) {
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
InvalidModuleName {
|
||||||
|
name: module_name.to_string(),
|
||||||
|
},
|
||||||
|
Range::default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use ruff_python::string;
|
||||||
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use crate::ast::helpers::identifier_range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for lowercase imports that are aliased to non-lowercase names.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends naming conventions for classes, functions,
|
||||||
|
/// constants, and more. The use of inconsistent naming styles between
|
||||||
|
/// import and alias names may lead readers to expect an import to be of
|
||||||
|
/// another type (e.g., confuse a Python class with a constant).
|
||||||
|
///
|
||||||
|
/// Import aliases should thus follow the same naming style as the member
|
||||||
|
/// being imported.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// from example import myclassname as MyClassName
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// from example import myclassname
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
|
pub struct LowercaseImportedAsNonLowercase {
|
||||||
|
pub name: String,
|
||||||
|
pub asname: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for LowercaseImportedAsNonLowercase {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let LowercaseImportedAsNonLowercase { name, asname } = self;
|
||||||
|
format!("Lowercase `{name}` imported as non-lowercase `{asname}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N812
|
||||||
|
pub fn lowercase_imported_as_non_lowercase(
|
||||||
|
import_from: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
asname: &str,
|
||||||
|
locator: &Locator,
|
||||||
|
) -> Option<Diagnostic> {
|
||||||
|
if !string::is_upper(name) && string::is_lower(name) && asname.to_lowercase() != asname {
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
LowercaseImportedAsNonLowercase {
|
||||||
|
name: name.to_string(),
|
||||||
|
asname: asname.to_string(),
|
||||||
|
},
|
||||||
|
identifier_range(import_from, locator),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::{Expr, Stmt};
|
||||||
|
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::rules::pep8_naming::helpers;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
pub struct MixedCaseVariableInClassScope {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for MixedCaseVariableInClassScope {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let MixedCaseVariableInClassScope { name } = self;
|
||||||
|
format!("Variable `{name}` in class scope should not be mixedCase")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N815
|
||||||
|
pub fn mixed_case_variable_in_class_scope(
|
||||||
|
checker: &mut Checker,
|
||||||
|
expr: &Expr,
|
||||||
|
stmt: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
) {
|
||||||
|
if checker
|
||||||
|
.settings
|
||||||
|
.pep8_naming
|
||||||
|
.ignore_names
|
||||||
|
.iter()
|
||||||
|
.any(|ignore_name| ignore_name == name)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if helpers::is_mixed_case(name) && !helpers::is_namedtuple_assignment(checker, stmt) {
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
MixedCaseVariableInClassScope {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
Range::from_located(expr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::{Expr, Stmt};
|
||||||
|
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::rules::pep8_naming::helpers;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
pub struct MixedCaseVariableInGlobalScope {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for MixedCaseVariableInGlobalScope {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let MixedCaseVariableInGlobalScope { name } = self;
|
||||||
|
format!("Variable `{name}` in global scope should not be mixedCase")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N816
|
||||||
|
pub fn mixed_case_variable_in_global_scope(
|
||||||
|
checker: &mut Checker,
|
||||||
|
expr: &Expr,
|
||||||
|
stmt: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
) {
|
||||||
|
if checker
|
||||||
|
.settings
|
||||||
|
.pep8_naming
|
||||||
|
.ignore_names
|
||||||
|
.iter()
|
||||||
|
.any(|ignore_name| ignore_name == name)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if helpers::is_mixed_case(name) && !helpers::is_namedtuple_assignment(checker, stmt) {
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
MixedCaseVariableInGlobalScope {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
Range::from_located(expr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
55
crates/ruff/src/rules/pep8_naming/rules/mod.rs
Normal file
55
crates/ruff/src/rules/pep8_naming/rules/mod.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
pub use camelcase_imported_as_acronym::{
|
||||||
|
camelcase_imported_as_acronym, CamelcaseImportedAsAcronym,
|
||||||
|
};
|
||||||
|
pub use camelcase_imported_as_constant::{
|
||||||
|
camelcase_imported_as_constant, CamelcaseImportedAsConstant,
|
||||||
|
};
|
||||||
|
pub use camelcase_imported_as_lowercase::{
|
||||||
|
camelcase_imported_as_lowercase, CamelcaseImportedAsLowercase,
|
||||||
|
};
|
||||||
|
pub use constant_imported_as_non_constant::{
|
||||||
|
constant_imported_as_non_constant, ConstantImportedAsNonConstant,
|
||||||
|
};
|
||||||
|
pub use dunder_function_name::{dunder_function_name, DunderFunctionName};
|
||||||
|
pub use error_suffix_on_exception_name::{
|
||||||
|
error_suffix_on_exception_name, ErrorSuffixOnExceptionName,
|
||||||
|
};
|
||||||
|
pub use invalid_argument_name::{invalid_argument_name, InvalidArgumentName};
|
||||||
|
pub use invalid_class_name::{invalid_class_name, InvalidClassName};
|
||||||
|
pub use invalid_first_argument_name_for_class_method::{
|
||||||
|
invalid_first_argument_name_for_class_method, InvalidFirstArgumentNameForClassMethod,
|
||||||
|
};
|
||||||
|
pub use invalid_first_argument_name_for_method::{
|
||||||
|
invalid_first_argument_name_for_method, InvalidFirstArgumentNameForMethod,
|
||||||
|
};
|
||||||
|
pub use invalid_function_name::{invalid_function_name, InvalidFunctionName};
|
||||||
|
pub use invalid_module_name::{invalid_module_name, InvalidModuleName};
|
||||||
|
pub use lowercase_imported_as_non_lowercase::{
|
||||||
|
lowercase_imported_as_non_lowercase, LowercaseImportedAsNonLowercase,
|
||||||
|
};
|
||||||
|
pub use mixed_case_variable_in_class_scope::{
|
||||||
|
mixed_case_variable_in_class_scope, MixedCaseVariableInClassScope,
|
||||||
|
};
|
||||||
|
pub use mixed_case_variable_in_global_scope::{
|
||||||
|
mixed_case_variable_in_global_scope, MixedCaseVariableInGlobalScope,
|
||||||
|
};
|
||||||
|
pub use non_lowercase_variable_in_function::{
|
||||||
|
non_lowercase_variable_in_function, NonLowercaseVariableInFunction,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod camelcase_imported_as_acronym;
|
||||||
|
mod camelcase_imported_as_constant;
|
||||||
|
mod camelcase_imported_as_lowercase;
|
||||||
|
mod constant_imported_as_non_constant;
|
||||||
|
mod dunder_function_name;
|
||||||
|
mod error_suffix_on_exception_name;
|
||||||
|
mod invalid_argument_name;
|
||||||
|
mod invalid_class_name;
|
||||||
|
mod invalid_first_argument_name_for_class_method;
|
||||||
|
mod invalid_first_argument_name_for_method;
|
||||||
|
mod invalid_function_name;
|
||||||
|
mod invalid_module_name;
|
||||||
|
mod lowercase_imported_as_non_lowercase;
|
||||||
|
mod mixed_case_variable_in_class_scope;
|
||||||
|
mod mixed_case_variable_in_global_scope;
|
||||||
|
mod non_lowercase_variable_in_function;
|
|
@ -0,0 +1,81 @@
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
use rustpython_parser::ast::{Expr, Stmt};
|
||||||
|
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::rules::pep8_naming::helpers;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for the use of non-lowercase variable names in functions.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// [PEP 8] recommends that all function variables use lowercase names:
|
||||||
|
///
|
||||||
|
/// > Function names should be lowercase, with words separated by underscores as necessary to
|
||||||
|
/// > improve readability. Variable names follow the same convention as function names. mixedCase
|
||||||
|
/// > is allowed only in contexts where that's already the prevailing style (e.g. threading.py),
|
||||||
|
/// to retain backwards compatibility.
|
||||||
|
///
|
||||||
|
/// ## Options
|
||||||
|
/// * `pep8-naming.ignore-names`
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// def my_function(a):
|
||||||
|
/// B = a + 3
|
||||||
|
/// return B
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// def my_function(a):
|
||||||
|
/// b = a + 3
|
||||||
|
/// return b
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-variable-names
|
||||||
|
pub struct NonLowercaseVariableInFunction {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
impl Violation for NonLowercaseVariableInFunction {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let NonLowercaseVariableInFunction { name } = self;
|
||||||
|
format!("Variable `{name}` in function should be lowercase")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// N806
|
||||||
|
pub fn non_lowercase_variable_in_function(
|
||||||
|
checker: &mut Checker,
|
||||||
|
expr: &Expr,
|
||||||
|
stmt: &Stmt,
|
||||||
|
name: &str,
|
||||||
|
) {
|
||||||
|
if checker
|
||||||
|
.settings
|
||||||
|
.pep8_naming
|
||||||
|
.ignore_names
|
||||||
|
.iter()
|
||||||
|
.any(|ignore_name| ignore_name == name)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.to_lowercase() != name
|
||||||
|
&& !helpers::is_namedtuple_assignment(checker, stmt)
|
||||||
|
&& !helpers::is_typeddict_assignment(checker, stmt)
|
||||||
|
&& !helpers::is_type_var_assignment(checker, stmt)
|
||||||
|
{
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
NonLowercaseVariableInFunction {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
Range::from_located(expr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
InvalidModuleName:
|
||||||
|
name: MODULE
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
|
@ -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,16 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
InvalidModuleName:
|
||||||
|
name: mod with spaces
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
[]
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
InvalidModuleName:
|
||||||
|
name: mod-with-dashes
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
|
@ -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,16 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
InvalidModuleName:
|
||||||
|
name: file-with-dashes
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 1
|
||||||
|
column: 0
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
|
@ -3,7 +3,8 @@ use regex::Regex;
|
||||||
|
|
||||||
pub static STRING_QUOTE_PREFIX_REGEX: Lazy<Regex> =
|
pub static STRING_QUOTE_PREFIX_REGEX: Lazy<Regex> =
|
||||||
Lazy::new(|| Regex::new(r#"^(?i)[urb]*['"](?P<raw>.*)['"]$"#).unwrap());
|
Lazy::new(|| Regex::new(r#"^(?i)[urb]*['"](?P<raw>.*)['"]$"#).unwrap());
|
||||||
pub static LOWER_OR_UNDERSCORE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[a-z_]+$").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 {
|
pub fn is_lower(s: &str) -> bool {
|
||||||
let mut cased = false;
|
let mut cased = false;
|
||||||
|
@ -64,10 +65,15 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_lower_underscore() {
|
fn test_is_lower_underscore() {
|
||||||
|
assert!(is_lower_with_underscore("a"));
|
||||||
assert!(is_lower_with_underscore("abc"));
|
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("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]
|
#[test]
|
||||||
|
|
|
@ -775,7 +775,7 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"avoid-escape": {
|
"avoid-escape": {
|
||||||
"description": "Whether to avoid using single quotes if a string contains single quotes, or vice-versa with double quotes, as per [PEP8](https://peps.python.org/pep-0008/#string-quotes). This minimizes the need to escape quotation marks within strings.",
|
"description": "Whether to avoid using single quotes if a string contains single quotes, or vice-versa with double quotes, as per [PEP 8](https://peps.python.org/pep-0008/#string-quotes). This minimizes the need to escape quotation marks within strings.",
|
||||||
"type": [
|
"type": [
|
||||||
"boolean",
|
"boolean",
|
||||||
"null"
|
"null"
|
||||||
|
@ -1656,6 +1656,9 @@
|
||||||
"N816",
|
"N816",
|
||||||
"N817",
|
"N817",
|
||||||
"N818",
|
"N818",
|
||||||
|
"N9",
|
||||||
|
"N99",
|
||||||
|
"N999",
|
||||||
"NPY",
|
"NPY",
|
||||||
"NPY0",
|
"NPY0",
|
||||||
"NPY00",
|
"NPY00",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue