Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop checking minimum name length by default #8813

Merged
merged 2 commits into from
Jul 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion doc/data/messages/i/invalid-name/details.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Pylint provides predefined naming patterns for some names. These patterns are of
based on a Naming Style but there is no option to choose one of the styles mentioned above.
The pattern can be overwritten with the options discussed below.

The following type of names are checked with a predefined pattern:
The following types of names are checked with a predefined pattern:

+--------------------+-------------------------------------------------------+------------------------------------------------------------+
| Name type | Good names | Bad names |
Expand All @@ -95,6 +95,13 @@ The following type of names are checked with a predefined pattern:
| | ``TopName`` is allowed but ``TTopName`` isn't. | |
+--------------------+-------------------------------------------------------+------------------------------------------------------------+

Before pylint 3.0, most predefined patterns also enforced a minimum length
jacobtylerwalls marked this conversation as resolved.
Show resolved Hide resolved
of three characters. If this behavior is desired in versions 3.0 and following,
it can be had by providing custom regular expressions as described next. (Or,
if the ``disallowed-name`` check is sufficient instead of ``invalid-name``,
providing the single option ``bad-names-rgxs="^..?$"`` will suffice to fail 1-2
character names.

Custom regular expressions
~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
20 changes: 20 additions & 0 deletions doc/whatsnew/fragments/2018.user_action
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The ``invalid-name`` message no longer checks for a minimum length of 3 characters by default.
(This was an unadvertised commingling of concerns between casing
and name length, and users regularly reported this to be surprising.)

If checking for a minimum length is still desired, it can be regained in two ways:

- If you are content with a ``disallowed-name`` message (instead of ``invalid-name``),
then simply add the option ``bad-names-rgxs="^..?$"``, which will fail 1-2
character-long names. (Ensure you enable ``disallowed-name``.)

- If you would prefer an ``invalid-name`` message to be emitted, or would prefer
finer-grained control over the circumstances in which messages are emitted
(classes vs. methods, etc.), then avail yourself of the regex options described
`here <https://pylint.readthedocs.io/en/stable/user_guide/configuration/all-options.html#main-checker>`_.
(In particular, take note of the commented out options in the "example configuration" given at
the bottom of the section.) The prior regexes can be found in the
`pull request <https://github.com/pylint-dev/pylint/pull/8813>`_
that removed the length requirements.

Closes #2018
24 changes: 12 additions & 12 deletions pylint/checkers/base/name_checker/naming_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,47 +47,47 @@ def get_regex(cls, name_type: str) -> Pattern[str]:
class SnakeCaseStyle(NamingStyle):
"""Regex rules for snake_case naming style."""

CLASS_NAME_RGX = re.compile(r"[^\W\dA-Z][^\WA-Z]+$")
CLASS_NAME_RGX = re.compile(r"[^\W\dA-Z][^\WA-Z]*$")
MOD_NAME_RGX = re.compile(r"[^\W\dA-Z][^\WA-Z]*$")
CONST_NAME_RGX = re.compile(r"([^\W\dA-Z][^\WA-Z]*|__.*__)$")
COMP_VAR_RGX = CLASS_NAME_RGX
DEFAULT_NAME_RGX = re.compile(
r"([^\W\dA-Z][^\WA-Z]{2,}|_[^\WA-Z]*|__[^\WA-Z\d_][^\WA-Z]+__)$"
r"([^\W\dA-Z][^\WA-Z]*|_[^\WA-Z]*|__[^\WA-Z\d_][^\WA-Z]+__)$"
)
CLASS_ATTRIBUTE_RGX = re.compile(r"([^\W\dA-Z][^\WA-Z]{2,}|__.*__)$")
CLASS_ATTRIBUTE_RGX = re.compile(r"([^\W\dA-Z][^\WA-Z]*|__.*__)$")


class CamelCaseStyle(NamingStyle):
"""Regex rules for camelCase naming style."""

CLASS_NAME_RGX = re.compile(r"[^\W\dA-Z][^\W_]+$")
CLASS_NAME_RGX = re.compile(r"[^\W\dA-Z][^\W_]*$")
MOD_NAME_RGX = re.compile(r"[^\W\dA-Z][^\W_]*$")
CONST_NAME_RGX = re.compile(r"([^\W\dA-Z][^\W_]*|__.*__)$")
COMP_VAR_RGX = MOD_NAME_RGX
DEFAULT_NAME_RGX = re.compile(r"([^\W\dA-Z][^\W_]{2,}|__[^\W\dA-Z_]\w+__)$")
CLASS_ATTRIBUTE_RGX = re.compile(r"([^\W\dA-Z][^\W_]{2,}|__.*__)$")
DEFAULT_NAME_RGX = re.compile(r"([^\W\dA-Z][^\W_]*|__[^\W\dA-Z_]\w+__)$")
CLASS_ATTRIBUTE_RGX = re.compile(r"([^\W\dA-Z][^\W_]*|__.*__)$")


class PascalCaseStyle(NamingStyle):
"""Regex rules for PascalCase naming style."""

CLASS_NAME_RGX = re.compile(r"[^\W\da-z][^\W_]+$")
CLASS_NAME_RGX = re.compile(r"[^\W\da-z][^\W_]*$")
MOD_NAME_RGX = CLASS_NAME_RGX
CONST_NAME_RGX = re.compile(r"([^\W\da-z][^\W_]*|__.*__)$")
COMP_VAR_RGX = CLASS_NAME_RGX
DEFAULT_NAME_RGX = re.compile(r"([^\W\da-z][^\W_]{2,}|__[^\W\dA-Z_]\w+__)$")
CLASS_ATTRIBUTE_RGX = re.compile(r"[^\W\da-z][^\W_]{2,}$")
DEFAULT_NAME_RGX = re.compile(r"([^\W\da-z][^\W_]*|__[^\W\dA-Z_]\w+__)$")
CLASS_ATTRIBUTE_RGX = re.compile(r"[^\W\da-z][^\W_]*$")


class UpperCaseStyle(NamingStyle):
"""Regex rules for UPPER_CASE naming style."""

CLASS_NAME_RGX = re.compile(r"[^\W\da-z][^\Wa-z]+$")
CLASS_NAME_RGX = re.compile(r"[^\W\da-z][^\Wa-z]*$")
MOD_NAME_RGX = CLASS_NAME_RGX
CONST_NAME_RGX = re.compile(r"([^\W\da-z][^\Wa-z]*|__.*__)$")
COMP_VAR_RGX = CLASS_NAME_RGX
DEFAULT_NAME_RGX = re.compile(r"([^\W\da-z][^\Wa-z]{2,}|__[^\W\dA-Z_]\w+__)$")
CLASS_ATTRIBUTE_RGX = re.compile(r"[^\W\da-z][^\Wa-z]{2,}$")
DEFAULT_NAME_RGX = re.compile(r"([^\W\da-z][^\Wa-z]*|__[^\W\dA-Z_]\w+__)$")
CLASS_ATTRIBUTE_RGX = re.compile(r"[^\W\da-z][^\Wa-z]*$")


class AnyStyle(NamingStyle):
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/d/disable_msg_next_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def function_B(arg1, arg2):

# pylint: disable-next=invalid-name, f-string-without-interpolation
def function_C():
x = "string" # [unused-variable, invalid-name]
X = "string" # [unused-variable, invalid-name]
return f"This should be a normal string" # [f-string-without-interpolation]


Expand Down
4 changes: 2 additions & 2 deletions tests/functional/d/disable_msg_next_line.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
invalid-name:15:4:15:5:function_C:"Variable name ""x"" doesn't conform to snake_case naming style":HIGH
unused-variable:15:4:15:5:function_C:Unused variable 'x':UNDEFINED
invalid-name:15:4:15:5:function_C:"Variable name ""X"" doesn't conform to snake_case naming style":HIGH
unused-variable:15:4:15:5:function_C:Unused variable 'X':UNDEFINED
f-string-without-interpolation:16:11:16:44:function_C:Using an f-string that does not have any interpolated variables:UNDEFINED
invalid-name:19:0:19:14:function_D:"Function name ""function_D"" doesn't conform to snake_case naming style":HIGH
unused-argument:19:21:19:25:function_D:Unused argument 'arg2':HIGH
Expand Down
8 changes: 6 additions & 2 deletions tests/functional/i/invalid/invalid_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ def test():
re = None
return re

def a(): # [invalid-name]
"""yo"""
def a():
"""We no longer fail 1-character names by default."""


def A(): # [invalid-name]
"""But we do check casing."""


def _generate_cmdline_tests():
Expand Down
12 changes: 6 additions & 6 deletions tests/functional/i/invalid/invalid_name.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
invalid-name:12:0:12:3::"Constant name ""aaa"" doesn't conform to UPPER_CASE naming style":HIGH
invalid-name:16:4:16:8::"Constant name ""time"" doesn't conform to UPPER_CASE naming style":HIGH
invalid-name:32:0:32:5:a:"Function name ""a"" doesn't conform to snake_case naming style":HIGH
invalid-name:46:4:46:13::"Constant name ""Foocapfor"" doesn't conform to UPPER_CASE naming style":HIGH
invalid-name:62:0:62:68:a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad:"Function name ""a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad"" doesn't conform to snake_case naming style":HIGH
invalid-name:70:23:70:29:FooBar.__init__:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH
invalid-name:76:8:76:14:FooBar.func1:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH
invalid-name:96:8:96:15:FooBar.test_disable_mixed:"Argument name ""fooBar2"" doesn't conform to snake_case naming style":HIGH
invalid-name:36:0:36:5:A:"Function name ""A"" doesn't conform to snake_case naming style":HIGH
invalid-name:50:4:50:13::"Constant name ""Foocapfor"" doesn't conform to UPPER_CASE naming style":HIGH
invalid-name:66:0:66:68:a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad:"Function name ""a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad"" doesn't conform to snake_case naming style":HIGH
invalid-name:74:23:74:29:FooBar.__init__:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH
invalid-name:80:8:80:14:FooBar.func1:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH
invalid-name:100:8:100:15:FooBar.test_disable_mixed:"Argument name ""fooBar2"" doesn't conform to snake_case naming style":HIGH
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import abc


def custom_prop(f): # [invalid-name]
return property(f)
def custom_prop(F): # [invalid-name]
return property(F)


class FooClass:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
invalid-name:9:16:9:17:custom_prop:"Argument name ""f"" doesn't conform to snake_case naming style":HIGH
invalid-name:9:16:9:17:custom_prop:"Argument name ""F"" doesn't conform to snake_case naming style":HIGH
invalid-name:21:4:21:11:FooClass.bar:"Attribute name ""bar"" doesn't conform to '[A-Z]+' pattern":INFERENCE
invalid-name:37:4:37:11:AnotherFooClass.foo:"Attribute name ""foo"" doesn't conform to '[A-Z]+' pattern":INFERENCE
8 changes: 4 additions & 4 deletions tests/functional/n/name/name_preset_snake_case.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
invalid-name:6:0:6:13::"Constant name ""SOME_CONSTANT"" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]*|__.*__)$' pattern)":HIGH
invalid-name:13:0:13:13:MyClass:"Class name ""MyClass"" doesn't conform to snake_case naming style ('[^\\W\\dA-Z][^\\WA-Z]+$' pattern)":HIGH
invalid-name:25:0:25:12:sayHello:"Function name ""sayHello"" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]{2,}|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)":HIGH
invalid-name:29:0:29:13:FooEnum:"Class name ""FooEnum"" doesn't conform to snake_case naming style ('[^\\W\\dA-Z][^\\WA-Z]+$' pattern)":HIGH
invalid-name:34:0:34:9:Bar:"Class name ""Bar"" doesn't conform to snake_case naming style ('[^\\W\\dA-Z][^\\WA-Z]+$' pattern)":HIGH
invalid-name:13:0:13:13:MyClass:"Class name ""MyClass"" doesn't conform to snake_case naming style ('[^\\W\\dA-Z][^\\WA-Z]*$' pattern)":HIGH
invalid-name:25:0:25:12:sayHello:"Function name ""sayHello"" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]*|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)":HIGH
invalid-name:29:0:29:13:FooEnum:"Class name ""FooEnum"" doesn't conform to snake_case naming style ('[^\\W\\dA-Z][^\\WA-Z]*$' pattern)":HIGH
invalid-name:34:0:34:9:Bar:"Class name ""Bar"" doesn't conform to snake_case naming style ('[^\\W\\dA-Z][^\\WA-Z]*$' pattern)":HIGH
4 changes: 2 additions & 2 deletions tests/functional/n/namePresetCamelCase.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
invalid-name:3:0:3:13::"Constant name ""SOME_CONSTANT"" doesn't conform to camelCase naming style ('([^\\W\\dA-Z][^\\W_]*|__.*__)$' pattern)":HIGH
invalid-name:10:0:10:13:MyClass:"Class name ""MyClass"" doesn't conform to camelCase naming style ('[^\\W\\dA-Z][^\\W_]+$' pattern)":HIGH
invalid-name:22:0:22:13:say_hello:"Function name ""say_hello"" doesn't conform to camelCase naming style ('([^\\W\\dA-Z][^\\W_]{2,}|__[^\\W\\dA-Z_]\\w+__)$' pattern)":HIGH
invalid-name:10:0:10:13:MyClass:"Class name ""MyClass"" doesn't conform to camelCase naming style ('[^\\W\\dA-Z][^\\W_]*$' pattern)":HIGH
invalid-name:22:0:22:13:say_hello:"Function name ""say_hello"" doesn't conform to camelCase naming style ('([^\\W\\dA-Z][^\\W_]*|__[^\\W\\dA-Z_]\\w+__)$' pattern)":HIGH
2 changes: 1 addition & 1 deletion tests/functional/r/regression/regression_4723.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ def play(): # [no-method-argument]

def func():
with B().get() as b:
b.play()
b.play() # [too-many-function-args]
jacobtylerwalls marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions tests/functional/r/regression/regression_4723.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
no-method-argument:15:4:15:12:B.play:Method 'play' has no argument:UNDEFINED
too-many-function-args:21:8:21:16:func:Too many positional arguments for method call:UNDEFINED