Skip to content

Allow covariants of __enter__, __aenter__, and @classmethod#1333

Closed
Congee wants to merge 1 commit intoencode:masterfrom
Congee:master
Closed

Allow covariants of __enter__, __aenter__, and @classmethod#1333
Congee wants to merge 1 commit intoencode:masterfrom
Congee:master

Conversation

@Congee
Copy link
Contributor

@Congee Congee commented Sep 30, 2020

The problem we currently have is the return type of classes such as
Client does not allow covariants when subclassing or context manager.
In other words:

class Base:
    def __enter__(self) -> Base:  # XXX
        return self

class Derived(Base):
    ...

with Derived() as derived:
    # The type of derived is Base but not Derived. It is WRONG
    ...

There are three approaches to improve type annotations.

  1. Just do not type-annotate and let the type checker infer
    return self.
  2. Use a generic type with a covariant bound
    _AsyncClient = TypeVar('_AsyncClient', bound=AsyncClient)
  3. Use a generic type T = TypeVar('T') or Self = TypeVar('Self')

They have pros and cons.

  1. It just works and is not friendly to developers as there is no type
    annotation at the first sight. A developer has to reveal its type via
    a type checker. Aslo, documentation tools that rely on type
    annotations lack the type. I haven't found any python docuementation
    tools that rely on type inference to infer return self. There are
    some tools simply check annotations.

  2. This approach is correct and has a nice covariant bound that adds
    type safety. It is also nice to documentation tools and somewhat
    friendly to developers. Type checkers, pyright that I use, always
    shows the the bounded type '_AsyncClient' rather than the subtype.
    Aslo, it requires more key strokes. Not good, not good.

    It is used by BaseException.with_traceback
    See https://github.com/python/typeshed/pull/4298/files

  3. This approach always type checks, and I believe it will be the
    official solution in the future. Fun fact, Rust has a Self type
    keyword. It is slightly unfriendly to documentation, but is simple to
    implement and easy to understand for developers. Most importantly,
    type checkers love it.

    See SelfType or another way to spell "type of self" (or, How to define a copy() function) python/mypy#1212

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants