python / python/mypy

(false positive) Using `@final` decorator on a `Protocol` class results in an error in most cases

Open
#17,288 3 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Applying the @final decorator on a class that inherits from Protocol results in an error when the class implements abstract attributes (attributes, methods, properties). Protocols often implement abstract attributes or methods.


The original reasoning behind the error is that, for normal classes, the abstract attributes could never be implemented if the class is final.
But this reasoning doesn't really extend to Protocol since they support virtual subclasses.

There are at least a few potentially valid use cases for declaring a Protocol as final.
In my use case, a few of my concrete implementations are unable to subclass the Protocol because of issues with property overriding. Since this Protocol is very tiny and has no default implementations anyway, it makes sense to enforce that none of the concrete implementations subclass from it, for consistency and a bit more freedom, as in certain cases it isn't possible to and in my opinion there aren't many benefits.

To Reproduce

from typing import Protocol, final

@final
class Inter(Protocol):
    x: int
    
    def y(self) -> int:
        ...

    @property
    def z(self) -> int:
        ...

https://gist.github.com/mypy-play/95be80b2ef05cc43ed77677df133d9d5

Error
main.py:4: error: Final class __main__.Inter has abstract attributes "x", "y", "z" [misc]

mypy thinks that abstract implementations in a final class is useless, as per #8316.
For Protocols however, the virtual subclasses may implement the abstract attributes without needing to subclass the Protocol.

Your Environment

(Default mypy playground env)

  • Mypy version used: 1.10.0
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): default
  • Python version used: 3.12

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the provided Python reproducer and compare the diagnostic for a final Protocol with abstract attributes against the behavior for ordinary final classes. Done means a final Protocol with abstract attributes does not produce the reported false-positive error, while the existing final-class check remains correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.