python / python/mypy

Non-inline `__init_subclass__` definition not recognized, despite giving type hints.

Open
#18,987 7 comments 0 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

Mypy does not recognize overwritten __init_subclass__ and complains that it's different from object's __init_subclass__.

So a simple code would be something like:

import dataclasses as dcls
from typing import Protocol, TypeVar, Callable

class InitSubclassWithKey(Protocol):
    """
    The ``__init_subclass__`` method of the classes making use of a factory.
    """

    def __call__(self, cls, *, key: str = "") -> None: ...

GLOBAL_REGISTRY = {}

def generate_init_subclass[T](lazy_base_class: Callable[[], T]) -> InitSubclassWithKey:
    def __init_subclass__(cls, *, key: str = "") -> None:
        base_class = lazy_base_class()
        GLOBAL_REGISTRY[base_class, key] = cls
        print("Registered:", base_class, key, cls)

    return __init_subclass__


class Base:
    # Have to use a lazy getter here because or else it would be ``NameError``.
    __init_subclass__ = generate_init_subclass(lambda: Base)

class Derived(Base, key="derived"):
    pass

Expected Derived to pass without issue (as is the case if I define __init_subclass__ directly).
Note: mypy has full type information here because of the protocol given (InitSubclassWithKey).

However, I get:

main.py:26: error: Unexpected keyword argument "key" for "__init_subclass__" of "object"  [call-arg]
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: mypy 1.15.0 (compiled: yes)
  • Mypy command-line flags: main.py
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.13

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 reproducer in main.py and run mypy 1.15.0 under Python 3.13 to confirm the unexpected keyword argument error. Trace how mypy handles a non-inline assignment to init_subclass and falls back to object; done when the typed Protocol assignment allows Derived(Base, key="derived") without an error.

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
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.