mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 10:01:15 +00:00
N811 & N814: eliminate false positives for single-letter names (#14584)
Co-authored-by: Micha Reiser <micha@reiser.io> Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
This commit is contained in:
parent
ef0e2a6e1b
commit
c40b37aa36
6 changed files with 72 additions and 4 deletions
|
@ -1,3 +1,9 @@
|
||||||
import mod.CONST as const
|
import mod.CONST as const
|
||||||
from mod import CONSTANT as constant
|
from mod import CONSTANT as constant
|
||||||
from mod import ANOTHER_CONSTANT as another_constant
|
from mod import ANOTHER_CONSTANT as another_constant
|
||||||
|
import mod.CON as c
|
||||||
|
from mod import C as c
|
||||||
|
|
||||||
|
# These are all OK:
|
||||||
|
import django.db.models.Q as Query1
|
||||||
|
from django.db.models import Q as Query2
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
import mod.Camel as CAMEL
|
import mod.Camel as CAMEL
|
||||||
from mod import CamelCase as CAMELCASE
|
from mod import CamelCase as CAMELCASE
|
||||||
from mod import AnotherCamelCase as ANOTHER_CAMELCASE
|
from mod import AnotherCamelCase as ANOTHER_CAMELCASE
|
||||||
|
|
||||||
|
# These are all OK:
|
||||||
|
import mod.AppleFruit as A
|
||||||
|
from mod import BananaFruit as B
|
||||||
|
|
|
@ -30,6 +30,20 @@ use crate::rules::pep8_naming::settings::IgnoreNames;
|
||||||
/// from example import MyClassName
|
/// from example import MyClassName
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Note
|
||||||
|
/// Identifiers consisting of a single uppercase character are ambiguous under
|
||||||
|
/// the rules of [PEP 8], which specifies `CamelCase` for classes and
|
||||||
|
/// `ALL_CAPS_SNAKE_CASE` for constants. Without a second character, it is not
|
||||||
|
/// possible to reliably guess whether the identifier is intended to be part
|
||||||
|
/// of a `CamelCase` string for a class or an `ALL_CAPS_SNAKE_CASE` string for
|
||||||
|
/// a constant, since both conventions will produce the same output when given
|
||||||
|
/// a single input character. Therefore, this lint rule does not apply to cases
|
||||||
|
/// where the alias for the imported identifier consists of a single uppercase
|
||||||
|
/// character.
|
||||||
|
///
|
||||||
|
/// A common example of a single uppercase character being used for a class
|
||||||
|
/// name can be found in Django's `django.db.models.Q` class.
|
||||||
|
///
|
||||||
/// [PEP 8]: https://peps.python.org/pep-0008/
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
pub(crate) struct CamelcaseImportedAsConstant {
|
pub(crate) struct CamelcaseImportedAsConstant {
|
||||||
|
@ -53,6 +67,9 @@ pub(crate) fn camelcase_imported_as_constant(
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
ignore_names: &IgnoreNames,
|
ignore_names: &IgnoreNames,
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
|
// Single-character names are ambiguous. It could be a class or a constant.
|
||||||
|
asname.chars().nth(1)?;
|
||||||
|
|
||||||
if helpers::is_camelcase(name)
|
if helpers::is_camelcase(name)
|
||||||
&& !str::is_cased_lowercase(asname)
|
&& !str::is_cased_lowercase(asname)
|
||||||
&& str::is_cased_uppercase(asname)
|
&& str::is_cased_uppercase(asname)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{Alias, Stmt};
|
||||||
use ruff_python_stdlib::str;
|
use ruff_python_stdlib::str;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::rules::pep8_naming::settings::IgnoreNames;
|
use crate::rules::pep8_naming::{helpers, settings::IgnoreNames};
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for constant imports that are aliased to non-constant-style
|
/// Checks for constant imports that are aliased to non-constant-style
|
||||||
|
@ -29,6 +29,19 @@ use crate::rules::pep8_naming::settings::IgnoreNames;
|
||||||
/// from example import CONSTANT_VALUE
|
/// from example import CONSTANT_VALUE
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Note
|
||||||
|
/// Identifiers consisting of a single uppercase character are ambiguous under
|
||||||
|
/// the rules of [PEP 8], which specifies `CamelCase` for classes and
|
||||||
|
/// `ALL_CAPS_SNAKE_CASE` for constants. Without a second character, it is not
|
||||||
|
/// possible to reliably guess whether the identifier is intended to be part
|
||||||
|
/// of a `CamelCase` string for a class or an `ALL_CAPS_SNAKE_CASE` string for
|
||||||
|
/// a constant, since both conventions will produce the same output when given
|
||||||
|
/// a single input character. Therefore, this lint rule does not apply to cases
|
||||||
|
/// where the imported identifier consists of a single uppercase character.
|
||||||
|
///
|
||||||
|
/// A common example of a single uppercase character being used for a class
|
||||||
|
/// name can be found in Django's `django.db.models.Q` class.
|
||||||
|
///
|
||||||
/// [PEP 8]: https://peps.python.org/pep-0008/
|
/// [PEP 8]: https://peps.python.org/pep-0008/
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
pub(crate) struct ConstantImportedAsNonConstant {
|
pub(crate) struct ConstantImportedAsNonConstant {
|
||||||
|
@ -52,7 +65,13 @@ pub(crate) fn constant_imported_as_non_constant(
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
ignore_names: &IgnoreNames,
|
ignore_names: &IgnoreNames,
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
if str::is_cased_uppercase(name) && !str::is_cased_uppercase(asname) {
|
if str::is_cased_uppercase(name)
|
||||||
|
&& !(str::is_cased_uppercase(asname)
|
||||||
|
// Single-character names are ambiguous.
|
||||||
|
// It could be a class or a constant, so allow it to be imported
|
||||||
|
// as `SCREAMING_SNAKE_CASE` *or* `CamelCase`.
|
||||||
|
|| (name.chars().nth(1).is_none() && helpers::is_camelcase(asname)))
|
||||||
|
{
|
||||||
// Ignore any explicitly-allowed names.
|
// Ignore any explicitly-allowed names.
|
||||||
if ignore_names.matches(name) || ignore_names.matches(asname) {
|
if ignore_names.matches(name) || ignore_names.matches(asname) {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
|
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
N811.py:1:8: N811 Constant `CONST` imported as non-constant `const`
|
N811.py:1:8: N811 Constant `CONST` imported as non-constant `const`
|
||||||
|
|
|
|
||||||
|
@ -16,6 +15,7 @@ N811.py:2:17: N811 Constant `CONSTANT` imported as non-constant `constant`
|
||||||
2 | from mod import CONSTANT as constant
|
2 | from mod import CONSTANT as constant
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ N811
|
| ^^^^^^^^^^^^^^^^^^^^ N811
|
||||||
3 | from mod import ANOTHER_CONSTANT as another_constant
|
3 | from mod import ANOTHER_CONSTANT as another_constant
|
||||||
|
4 | import mod.CON as c
|
||||||
|
|
|
|
||||||
|
|
||||||
N811.py:3:17: N811 Constant `ANOTHER_CONSTANT` imported as non-constant `another_constant`
|
N811.py:3:17: N811 Constant `ANOTHER_CONSTANT` imported as non-constant `another_constant`
|
||||||
|
@ -24,4 +24,25 @@ N811.py:3:17: N811 Constant `ANOTHER_CONSTANT` imported as non-constant `another
|
||||||
2 | from mod import CONSTANT as constant
|
2 | from mod import CONSTANT as constant
|
||||||
3 | from mod import ANOTHER_CONSTANT as another_constant
|
3 | from mod import ANOTHER_CONSTANT as another_constant
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ N811
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ N811
|
||||||
|
4 | import mod.CON as c
|
||||||
|
5 | from mod import C as c
|
||||||
|
|
|
||||||
|
|
||||||
|
N811.py:4:8: N811 Constant `CON` imported as non-constant `c`
|
||||||
|
|
|
||||||
|
2 | from mod import CONSTANT as constant
|
||||||
|
3 | from mod import ANOTHER_CONSTANT as another_constant
|
||||||
|
4 | import mod.CON as c
|
||||||
|
| ^^^^^^^^^^^^ N811
|
||||||
|
5 | from mod import C as c
|
||||||
|
|
|
||||||
|
|
||||||
|
N811.py:5:17: N811 Constant `C` imported as non-constant `c`
|
||||||
|
|
|
||||||
|
3 | from mod import ANOTHER_CONSTANT as another_constant
|
||||||
|
4 | import mod.CON as c
|
||||||
|
5 | from mod import C as c
|
||||||
|
| ^^^^^^ N811
|
||||||
|
6 |
|
||||||
|
7 | # These are all OK:
|
||||||
|
|
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
|
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
N814.py:1:8: N814 Camelcase `Camel` imported as constant `CAMEL`
|
N814.py:1:8: N814 Camelcase `Camel` imported as constant `CAMEL`
|
||||||
|
|
|
|
||||||
|
@ -24,4 +23,6 @@ N814.py:3:17: N814 Camelcase `AnotherCamelCase` imported as constant `ANOTHER_CA
|
||||||
2 | from mod import CamelCase as CAMELCASE
|
2 | from mod import CamelCase as CAMELCASE
|
||||||
3 | from mod import AnotherCamelCase as ANOTHER_CAMELCASE
|
3 | from mod import AnotherCamelCase as ANOTHER_CAMELCASE
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ N814
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ N814
|
||||||
|
4 |
|
||||||
|
5 | # These are all OK:
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue