Skip to content

Support type.__orig_bases__ as defined in PEP 560 #7811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
huntzhan opened this issue May 9, 2022 · 4 comments
Closed

Support type.__orig_bases__ as defined in PEP 560 #7811

huntzhan opened this issue May 9, 2022 · 4 comments

Comments

@huntzhan
Copy link

huntzhan commented May 9, 2022

__orig_bases__ is defined in PEP 560. Currently class type does not include this symbol. This symbol is helpful for writing type reflection code. It would be great if this symbol is supported.

related pyright issue: microsoft/pyright#3442

@AlexWaygood
Copy link
Member

AlexWaygood commented May 9, 2022

We can add this, for sure. A few thoughts, though.

(1) If you're using this in your code, I'd be wary of this sentence in PEP 560:

NOTE: These two method names are reserved for use by the typing module and the generic types machinery, and any other use is discouraged. The reference implementation (with tests) can be found in [4], and the proposal was originally posted and discussed on the typing tracker, see [5].

(2) The attribute does not exist on all type objects, only on subclasses of typing.Generic (so I think it should be added as a ClassVar on typing.Generic). On Python 3.9, for example:

>>> class Foo: ...
... 
>>> Foo.__orig_bases__
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute '__orig_bases__'
>>> from typing import TypeVar, Generic
>>> T = TypeVar('T')
>>> class Bar(Generic[T]): ...
... 
>>> Bar.__orig_bases__
(typing.Generic[~T],)
>>> list[int].__orig_bases__
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AttributeError: type object 'list' has no attribute '__orig_bases__'

(3) I'm not 100% sure what the type should be. I know Eric said in the pyright issue that he thought Sequence[type] would be a good choice. But check it out:

>>> from typing import TypeVar, Generic
>>> T = TypeVar('T')
>>> class Bar(Generic[T]): ...
... 
>>> Bar.__orig_bases__
(typing.Generic[~T],)
>>> isinstance(_[0], type)
False

@AlexWaygood
Copy link
Member

AlexWaygood commented May 9, 2022

Ah, but then on the other hand, we don't have typing.Generic as a class currently in typing.pyi, so adding a ClassVar to it in the stub might be slightly tricky:

Generic: _SpecialForm = ...

@hmc-cs-mdrissi
Copy link
Contributor

hmc-cs-mdrissi commented May 9, 2022

I'd probably call them typeforms instead of types. If we had typeform pep I think I'd do tuple[Typeform, ...]. It's similar to how list is a type, but list[int] is not a type (or how Union[int, str] fails to be a type). Most of the code I use that does orig_bases introspection is for stuff like,

class Container(Generic[T]):
  @classmethod
  def object_type(cls) -> T:
    return cls.__orig_bases__[0]

Here the type of object_type can be any valid typeform. Union[int, str], List[str], etc are all valid values.

Without typeform pep I think type serves as best approximation.

@huntzhan
Copy link
Author

huntzhan commented May 9, 2022

I'd probably call them typeforms instead of types. If we had typeform pep I think I'd do tuple[Typeform, ...]. It's similar to how list is a type, but list[int] is not a type (or how Union[int, str] fails to be a type). Most of the code I use that does orig_bases introspection is for stuff like,

class Container(Generic[T]):
  @classmethod
  def object_type(cls) -> T:
    return cls.__orig_bases__[0]

Here the type of object_type can be any valid typeform. Union[int, str], List[str], etc are all valid values.

Without typeform pep I think type serves as best approximation.

Probably this example ?

from typing import get_args

class Container(Generic[T]):
  @classmethod
  def object_type(cls) -> T:
    return get_args(cls.__orig_bases__[0])[0]

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 a pull request may close this issue.

4 participants