Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Allow Self or Self-like type arguments for generics

Open
#2,276 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Quiet
Tech stack
python
Domain
tooling

Research direction

Start with the AbstractContextManager examples and the stated restriction on using Self as a generic type argument. Compare the desired behavior for ManagerB and SubManager with current rules for Self, subclassing, and generic type arguments. Done means a general solution accurately infers the concrete subclass while preserving correct behavior for overridden or inherited enter methods.

Written by the indexing model from the issue text.

Description

topic: feature
from contextlib import AbstractContextManager

class ManagerA(AbstractContextManager):
    def __init__(self, x: int) -> None:
        self._x = x
    def __enter__(self) -> int:
        return self._x

This can raise type check errors because AbstractContextManager is a generic type, and this code omits the type argument. Fair enough, and easy to fix:

from contextlib import AbstractContextManager

class ManagerA(AbstractContextManager[int]):
    def __init__(self, x: int) -> None:
        self._x = x
    def __enter__(self) -> int:
        return self._x

But what if we are not overriding the __enter__ method? Consider this example:

from contextlib import AbstractContextManager

class ManagerB(AbstractContextManager):
    def __init__(self, x: int) -> None:
        self._x = x
    # Other methods are defined, but __enter__ is not overridden

In this case, there is no great way to accurate type annotate it in order to reflect the fact that the __enter__ method always returns the object that it was called on (which is the default implementation of the __enter__ method in AbstractContextManager.

If we were willing to mark this class as final, then we could annotate it as:

class ManagerB(AbstractContextManager["ManagerB"]):

And that would work. But if we want to be able to subclass it, then this would no longer be accurate. Consider:

from contextlib import AbstractContextManager
from types import TracebackType
from typing import Type

class ManagerB(AbstractContextManager["ManagerB"]):
    def __init__(self, x: int) -> None:
        self._x = x

    # Other methods are defined, but __enter__ is not overridden

    def __exit__(
            self, exc_type: Type[BaseException] | None,
            exc_val: BaseException | None,
            exc_tb: TracebackType | None) -> bool | None:
        return None

class SubManager(ManagerB):
    def harf(self) -> None:
        print("harf")

with SubManager(1) as subman:
    subman.harf()

This runs fine, but the type checker will rightly complain. The annotations indicate that subman should be of type ManagerB, but ManagerB has no harf attribute.

It feels like it would be appropriate to use:

class ManagerB(AbstractContextManager[Self]):

But Self is not allowed to be used in this context.

The feature I would like to see is some way to accurately handle non-final subclasses of AbstractContextManager that do not overwrite the __enter__ method (or that overwrite it but still return self).

Obviously this issue applies generally to generics -- this is just an obvious example since the Python implementation of that class makes it impossible to type annotate many of its subclasses. But ideally any solution would apply generally to generics -- essentially giving a way to use Self (or something Self-like) as the type argument for a generic.

Dominant language
Python
Stars
1.8k
Forks
302
Avg merge
23h
Merged PRs (30d)
8

Contributor guide

No contributing guide indexed for this repository

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.

More from python/typing

All issues in python/typing

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.