Skip to content

Pylint C0103 (invalid-name) contradiction for class-level typing.Final attributes. #10711

@xiahualiu-txg

Description

@xiahualiu-txg

Bug description

Pylint (C0103) generates contradictory invalid-name warnings for class-level attributes annotated with typing.Final.

  • It flags a snake_case attribute annotated with Final as an invalid constant (demanding UPPER_CASE).
  • It flags an UPPER_CASE attribute annotated with Final as an invalid attribute (demanding snake_case).

This creates a catch-22 where no naming convention is considered valid.

A Simple Example

# file: example.py from dataclasses import dataclass from typing import Final @dataclass class ExampleClass: parameter_one: int = 10 parameter_two: str = "default" parameter_three: float = 3.14 # C0103: Class constant name "parameter_six" doesn't conform to UPPER_CASE naming style (invalid-name) parameter_six: Final[int] = 42 # C0103: Attribute name "PARAMETER_FIVE" doesn't conform to snake_case naming style (invalid-name) PARAMETER_FIVE: Final[int] = 42

Analysis

The core purpose of both the UPPER_CASE naming convention (from PEP 8) and the typing.Final annotation is identical: to signal developer intent that a variable is a constant and should not be reassigned.

Pylint's linter appears to be applying two different rules inconsistently:

For parameter_six, it correctly identifies Final as indicating a constant and therefore demands the UPPER_CASE naming convention.

For PARAMETER_FIVE, it seems to ignore the Final annotation, classify the variable as a standard attribute (which can be modified), and therefore incorrectly demands the snake_case naming convention.

This logic is contradictory. The UPPER_CASE convention was created precisely to communicate the intent of immutability that typing.Final now enforces statically. These two signals should be seen as compatible and reinforcing, not mutually exclusive.

Proposed Behavior

When a class-level attribute is annotated with typing.Final, it should be treated as a constant for naming convention purposes.

  • PARAMETER_FIVE: Final[int] = 42 (UPPER_CASE) should NOT raise an invalid-name warning. It correctly uses the constant naming convention.
  • parameter_six: Final[int] = 42 (snake_case) SHOULD (as it currently does) raise an invalid-name warning, suggesting the UPPER_CASE convention is preferred for Final attributes.

I suggest Pylint treats UPPER_CASE same as Final because they are basically flagging the same thing in the code, that is DO NOT modify this. The logic behind because UPPER_CASE attributes can be modified so it needs to be snake_case reverses the logic.

Configuration

pylint 3.3.8 python 3.11.14

Command used

python -m pylint /home/ubuntu/GitHub/embedded-apps/example.py

Pylint output

************* Module example example.py:21:4: C0103: Attribute name "PARAMETER_FIVE" doesn't conform to snake_case naming style (invalid-name) example.py:18:4: C0103: Class constant name "parameter_six" doesn't conform to UPPER_CASE naming style (invalid-name)

Expected behavior

The first "PARAMETER_FIVE" is legit UPPER_CASE user case so pylint shouldn't raise anything.

Pylint version

pylint 3.3.8

OS / Environment

Ubuntu 24.04.3

Additional dependencies

No.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions