Skip to content

Conversation

@joao-faria-dev
Copy link
Contributor

Description

Fixes a false positive where module-level constants were incorrectly classified as variables when a class-level attribute with the same name exists. I added a scope check so now when we check for reassignments, we make sure we only look at nodes within the same scope

Closes #10719

@joao-faria-dev joao-faria-dev force-pushed the fix-c0103-module-class-name-conflict branch 2 times, most recently from 1a5cff6 to 178bdc8 Compare November 6, 2025 17:52
Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great first PR, thank you. Could you add a functional test in tests/functional to check it automatically, please ?

@joao-faria-dev
Copy link
Contributor Author

joao-faria-dev commented Nov 6, 2025

Thanks for the review @Pierre-Sassoulas, just added it!

@github-actions

This comment has been minimized.

Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a suggestion to match the example from the issue, let me know what you think. Changed Input to input, maybe it was the reason for the second invalid-name (shouldn't have been pascal case ?)

@@ -0,0 +1,8 @@
"""Test module-level constants with class attribute same name"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Test module-level constants with class attribute same name"""
"""Test module-level constants with class attribute same name
Regression test for #10719.
"""

Comment on lines 7 to 8
class MyClass:
MY_CONST = 10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class MyClass:
MY_CONST = 10
class MyClass:
MY_CONST = 10
class Theme:
INPUT = ">>> "
INPUT = Theme()
input = Theme()
OUTPUT = Theme()
output = Theme()

@joao-faria-dev joao-faria-dev force-pushed the fix-c0103-module-class-name-conflict branch from 8f658a3 to 6459607 Compare November 6, 2025 19:48
@github-actions

This comment has been minimized.

@Pierre-Sassoulas
Copy link
Member

There's lot of changes from the primer which is worrying. Also the tests are not passing you can launch them with pytest locally, see https://pylint.readthedocs.io/en/stable/development_guide/contributor_guide/tests/launching_test.html#pytest

@Pierre-Sassoulas Pierre-Sassoulas modified the milestones: 4.0.3, 4.0.4 Nov 9, 2025
@joao-faria-dev joao-faria-dev force-pushed the fix-c0103-module-class-name-conflict branch 2 times, most recently from 23c90df to 284a794 Compare November 11, 2025 01:48
@jacobtylerwalls jacobtylerwalls self-requested a review November 11, 2025 22:21
Copy link
Member

@jacobtylerwalls jacobtylerwalls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I checked a few of the primer changes, and they look good. Does anything look concerning to you?

if isinstance(a, (nodes.ClassDef, nodes.FunctionDef)):
if a.parent and a.parent.scope() == node_scope:
return True
elif a.scope() == node_scope:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is is usually used for specific node comparisons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still applies

@joao-faria-dev joao-faria-dev force-pushed the fix-c0103-module-class-name-conflict branch from 284a794 to dc44856 Compare November 17, 2025 20:15
Copy link
Member

@jacobtylerwalls jacobtylerwalls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!

@joao-faria-dev joao-faria-dev force-pushed the fix-c0103-module-class-name-conflict branch from dc44856 to 47b22a7 Compare November 19, 2025 19:06
@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@4f0716a). Learn more about missing BASE report.
⚠️ Report is 26 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main   #10723   +/-   ##
=======================================
  Coverage        ?   95.98%           
=======================================
  Files           ?      176           
  Lines           ?    19559           
  Branches        ?        0           
=======================================
  Hits            ?    18774           
  Misses          ?      785           
  Partials        ?        0           
Files with missing lines Coverage Δ
pylint/checkers/utils.py 96.03% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

This comment has been minimized.

Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but would you mind covering the missing lines with automated tests, please ?

@joao-faria-dev joao-faria-dev force-pushed the fix-c0103-module-class-name-conflict branch from 47b22a7 to 17828a6 Compare November 21, 2025 14:58
@github-actions

This comment has been minimized.

…ames

- Add scope comparision to avoid module-level constants to be incorrectly
classified as variables when a class-level attribute with the same name exists

Closes pylint-dev#10719
@github-actions
Copy link
Contributor

🤖 Effect of this PR on checked open source code: 🤖

Effect on ansible:
The following messages are now emitted:

  1. invalid-name:
    Constant name "current_worker" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/executor/process/worker.py#L52
  2. invalid-name:
    Constant name "cur_id" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/utils/vars.py#L39
  3. invalid-name:
    Constant name "_module_tracebacks_enabled_events" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/module_utils/_internal/_traceback.py#L68
  4. invalid-name:
    Constant name "module" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/modules/file.py#L244
  5. invalid-name:
    Constant name "apt_key_bin" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/modules/apt_key.py#L181
  6. invalid-name:
    Constant name "gpg_bin" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/modules/apt_key.py#L182
  7. invalid-name:
    Constant name "locale" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/modules/apt_key.py#L183
  8. invalid-name:
    Constant name "job_path" doesn't conform to UPPER_CASE naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/modules/async_wrapper.py#L29

The following messages are no longer emitted:

  1. invalid-name:
    Variable name "CLIARGS" doesn't conform to snake_case naming style
    https://github.com/ansible/ansible/blob/76fb182b63a321aa513ee1c259eb39dd390e94c5/lib/ansible/context.py#L25

Effect on django:
The following messages are now emitted:

  1. invalid-name:
    Constant name "_exception" doesn't conform to UPPER_CASE naming style
    https://github.com/django/django/blob/3c005b5f79bf6d71f3f4c3692ed670e1722b0fb6/django/utils/autoreload.py#L35
  2. invalid-name:
    Constant name "_default" doesn't conform to UPPER_CASE naming style
    https://github.com/django/django/blob/3c005b5f79bf6d71f3f4c3692ed670e1722b0fb6/django/utils/translation/trans_real.py#L29
  3. invalid-name:
    Constant name "_worker_id" doesn't conform to UPPER_CASE naming style
    https://github.com/django/django/blob/3c005b5f79bf6d71f3f4c3692ed670e1722b0fb6/django/test/runner.py#L430

The following messages are no longer emitted:

  1. invalid-name:
    Variable name "SITE_CACHE" doesn't conform to snake_case naming style
    https://github.com/django/django/blob/3c005b5f79bf6d71f3f4c3692ed670e1722b0fb6/django/contrib/sites/models.py#L9

Effect on pandas:
The following messages are now emitted:

  1. invalid-name:
    Constant name "_evaluate" doesn't conform to UPPER_CASE naming style
    https://github.com/pandas-dev/pandas/blob/2d73d629552cfc5c6ecc1a73f753f383fc7966c1/pandas/core/computation/expressions.py#L33
  2. invalid-name:
    Constant name "_where" doesn't conform to UPPER_CASE naming style
    https://github.com/pandas-dev/pandas/blob/2d73d629552cfc5c6ecc1a73f753f383fc7966c1/pandas/core/computation/expressions.py#L34
  3. invalid-name:
    Constant name "_is_scipy_sparse" doesn't conform to UPPER_CASE naming style
    https://github.com/pandas-dev/pandas/blob/2d73d629552cfc5c6ecc1a73f753f383fc7966c1/pandas/core/dtypes/common.py#L73

The following messages are no longer emitted:

  1. invalid-name:
    Variable name "_TEST_RESULT" doesn't conform to snake_case naming style
    https://github.com/pandas-dev/pandas/blob/2d73d629552cfc5c6ecc1a73f753f383fc7966c1/pandas/core/computation/expressions.py#L31

Effect on pytest:
The following messages are no longer emitted:

  1. invalid-name:
    Variable name "RUNNER_CLASS" doesn't conform to snake_case naming style
    https://github.com/pytest-dev/pytest/blob/bbb0c0778a0fce3afb456fa8850994a63320a996/src/_pytest/doctest.py#L65
  2. invalid-name:
    Variable name "CHECKER_CLASS" doesn't conform to snake_case naming style
    https://github.com/pytest-dev/pytest/blob/bbb0c0778a0fce3afb456fa8850994a63320a996/src/_pytest/doctest.py#L67

Effect on flask:
The following messages are now emitted:

  1. invalid-name:
    Constant name "_werkzeug_version" doesn't conform to UPPER_CASE naming style
    https://github.com/pallets/flask/blob/2579ce9f18e67ec3213c6eceb5240310ccd46af8/src/flask/testing.py#L97

Effect on poetry-core:
The following messages are now emitted:

  1. invalid-name:
    Constant name "_executable" doesn't conform to UPPER_CASE naming style
    https://github.com/python-poetry/poetry-core/blob/acc1bc9dda925ee47311c951e69d7993e81cae62/src/poetry/core/vcs/git.py#L147

Effect on sentry:
The following messages are now emitted:

  1. invalid-name:
    Constant name "_local_cache_generation" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/db/models/manager/base.py#L29
  2. invalid-name:
    Constant name "_local_cache_enabled" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/db/models/manager/base.py#L30
  3. invalid-name:
    Constant name "_global_regions" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/types/region.py#L203
  4. invalid-name:
    Constant name "rust_geoip" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/utils/geo.py#L17
  5. invalid-name:
    Constant name "outcomes_publisher" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/utils/outcomes.py#L159
  6. invalid-name:
    Constant name "billing_publisher" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/utils/outcomes.py#L160
  7. invalid-name:
    Constant name "_from_email_domain_cache" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/utils/email/address.py#L14
  8. invalid-name:
    Constant name "__installed" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/runner/settings.py#L136
  9. invalid-name:
    Constant name "_accountant_backend" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/usage_accountant/accountant.py#L21
  10. invalid-name:
    Constant name "_last_validation_log" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/buffer/redis.py#L36
  11. invalid-name:
    Constant name "__rrweb_id" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/replays/testutils.py#L471
  12. invalid-name:
    Constant name "sync_publisher" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/replays/lib/kafka.py#L59
  13. invalid-name:
    Constant name "async_publisher" doesn't conform to UPPER_CASE naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/replays/lib/kafka.py#L60

The following messages are no longer emitted:

  1. invalid-name:
    Variable name "_LOGIN_URL" doesn't conform to snake_case naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/utils/auth.py#L36
  2. invalid-name:
    Variable name "AUTOFIX_POST_RESPONSE" doesn't conform to snake_case naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/apidocs/examples/autofix_examples.py#L3
  3. invalid-name:
    Variable name "AUTOFIX_GET_RESPONSE" doesn't conform to snake_case naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/apidocs/examples/autofix_examples.py#L12
  4. invalid-name:
    Variable name "_CONCURRENT_RATE_LIMITER" doesn't conform to snake_case naming style
    https://github.com/getsentry/sentry/blob/ec5ed207fd261a4f8f1e60ea59618b33f8f40b12/src/sentry/ratelimits/utils.py#L40

Effect on home-assistant:
The following messages are no longer emitted:

  1. invalid-name:
    Variable name "CONTROLLER_MODES" doesn't conform to snake_case naming style
    https://github.com/home-assistant/core/blob/433712b407600ef40771d7fa371ebca2df96695c/homeassistant/components/knx/const.py#L170

Effect on coverage:
The following messages are no longer emitted:

  1. invalid-name:
    Variable name "CANONICAL_FILENAME_CACHE" doesn't conform to snake_case naming style
    https://github.com/nedbat/coveragepy/blob/fff5e59b28e0a4660a5e19975eb02aeffcb05a01/coverage/files.py#L26

Effect on pygame:
The following messages are now emitted:

  1. invalid-name:
    Constant name "_ft_init" doesn't conform to UPPER_CASE naming style
    https://github.com/pygame/pygame/blob/85fda3f719d437cf27106afae8c890e6b88ba5f5/src_py/fastevent.py#L13
  2. invalid-name:
    Constant name "is_init" doesn't conform to UPPER_CASE naming style
    https://github.com/pygame/pygame/blob/85fda3f719d437cf27106afae8c890e6b88ba5f5/src_py/sysfont.py#L39
  3. invalid-name:
    Constant name "_is_init" doesn't conform to UPPER_CASE naming style
    https://github.com/pygame/pygame/blob/85fda3f719d437cf27106afae8c890e6b88ba5f5/src_py/camera.py#L9
  4. invalid-name:
    Constant name "_wq" doesn't conform to UPPER_CASE naming style
    https://github.com/pygame/pygame/blob/85fda3f719d437cf27106afae8c890e6b88ba5f5/src_py/threads/__init__.py#L28
  5. invalid-name:
    Constant name "_use_workers" doesn't conform to UPPER_CASE naming style
    https://github.com/pygame/pygame/blob/85fda3f719d437cf27106afae8c890e6b88ba5f5/src_py/threads/__init__.py#L31

This comment was generated for commit d77f097

@Pierre-Sassoulas
Copy link
Member

Thank you, great PR !

@Pierre-Sassoulas Pierre-Sassoulas merged commit e55e830 into pylint-dev:main Nov 22, 2025
44 checks passed
pylint-backport bot pushed a commit that referenced this pull request Nov 22, 2025
…ames (#10723)

Add scope comparision to avoid module-level constants to be incorrectly
classified as variables when a class-level attribute with the same name exists

Closes #10719

(cherry picked from commit e55e830)
Pierre-Sassoulas pushed a commit that referenced this pull request Nov 22, 2025
…vel names match class-level names (#10753)

fix: avoid false positive when module-level names match class-level names (#10723)

Add scope comparision to avoid module-level constants to be incorrectly
classified as variables when a class-level attribute with the same name exists

Closes #10719

(cherry picked from commit e55e830)

Co-authored-by: Joao Faria <joaovitorfaria.dev@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pylint C0103 (invalid-name) contradiction when module level names matches will class level names

3 participants