-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
autodoc for generic classes should include the type parameters #10568
Comments
PR welcome. What's the precedent here, though? A |
I don't know of any precedent; I just feel that a class being generic should be indicated on the class name itself and not only as part of the base classes. |
At present, autodoc and python domain expect to represent base classes via the I'm not sure the best way to represent the generic classes in the document. But we need to separate the class definition and constructor before the new implementation. |
There's quite a bit of precedent. If you're talking about usage of generic types: I'm not sure what was possible in Python 3.5, when type hints and generics were first introduced, because I don't have easy access to an interpreter for it. But certainly by Python 3.6 (released in 2016) you could use type parameters and regular constructor parameters together with both built-in classes and user-defined classes based on
The run-time types of the objects will be simply If you're talking about declaration rather than usage: that only came in with Python 3.12 (released in October 2023). Now instead of writing: T = TypeVar("T")
class MyGenericClass(SomeNonGenericBase, Generic[T]):
... You can simply write (without declaring class MyGenericClass[T](SomeNonGenericBase):
... Given the above, especially the usage syntax, it would make a lot of sense to me if you could automatically erase the class my_package.MyGenericClass[T](arg_1: str, arg_2: int) Edit: Having written all the above, I've just noticed that the Sphinx Python domain supports type lists to classes and function – presumably added since this ticket was filed to support Python 3.12.
|
Just to preempt a potential implementation question: There's a slight complication with getting the type list when you have generic base classes. In that case, there is no requirement to explicitly list the types with a Python 3.12-style type list or an older-style T1 = TypeVar("T1")
T2 = TypeVar("T2")
T3 = TypeVar("T3")
class Base1(Generic[T1, T2]): pass
class Base2(Generic[T1, T2]): pass
class Derived(Base1[T1, T2], Base2[T2, T3]): pass In that case, the type list is all the type variables used in the base list collected in order of first usage, i.e. for If class Derived(Base1[T1, T2], Base2[T2, T3], Generic[T3, T2, T1]): pass In that case, the type list to |
I implemented PEP 695 since cpython asked for it but we'll probably rewrite it when 3.12 becomes the minimal version. However I did not consider any autodoc approach because extracting the type variables are painful depending on the python version... I should have worked with astroid or implemented an improved version of the AST parser (+take care of inheritance and different modules!!!). So at that time I just gave up I think. |
Oh wow I didn't realise you needed to parse the code to get the type parameters out 😢 I can see that in 3.12 (if you use the new syntax) it's just a matter of reading the |
Yes, that's why I think we should postpone this until 3.12 becomes the base version. The main resaon is that the AST parser in <3.12 would not even recognize the syntax ! so I needed to make my own tokenizer (and also take into account some weird stuff because spaces are gobbled). |
I had another look at this and it turns out you don't need to parse the code to pick out the type parameters of a >>> from typing import get_type_hints, TypeVar, Generic
>>> T = TypeVar("T")
>>> U = TypeVar("U")
>>> class C(Generic[T, U]): pass
...
>>> C.__bases__
(<class 'typing.Generic'>,)
>>> C.__bases__[0]
<class 'typing.Generic'>
>>> C.__orig_bases__
(typing.Generic[~T, ~U],)
>>> C.__orig_bases__[0]
typing.Generic[~T, ~U]
>>> C.__orig_bases__[0].__parameters__[0].__name__
'T' |
Actually, we are not handling the object directly. We are given a signature as a string. So I need to do a parser-like approach and cannot rely on runtime analysis (for instance, we support PEP 695 syntax given at the RST level directly, so there is no class object) |
Currently, when autodoc renders a class of the form
class Foo(Generic[T])
, the resulting HTML just shows "class modulename.Foo", which omits information, as the type parameter is not shown. The only way to show the type parameter at the moment is to use:show-inheritance:
to add a line of the form "Bases: Generic[T]". A generic class should instead be rendered as "class modulename.Foo[T]".The text was updated successfully, but these errors were encountered: