pydata-sphinx-theme
pydata-sphinx-theme copied to clipboard
Show methods and properties of autoclass in right column.
I am using pydata-sphinx-theme for the documentation of zfit. (The new version with the pydata theme can be found in the version doc_redesign).
Now it would be very useful to automatically list the methods and properties of a class in the right column without having to write a manual header for each section. I.e.
.. autoclass:: zfit.constraint.GaussianConstraint
:members:
Instead of
.. py:currentmodule:: zfit.constraint
.. autoclass:: GaussianConstraint
create_covariance
------------------------
.. automethod:: GaussianConstraint.create_covariance
covariance
------------------------
.. automethod:: GaussianConstraint.covariance
etc.
So my question now is:
Is this already possible? And if not would we have to change something about pydata theme or does this change have to be made in autodoc, i.e. generating headers for methods.
I am happy to help with implementation if you give me some guidance.
That sounds like an interesting idea, we just hit a similar issue and this would solve it. Are there any plans already for this?
Hi, me too use this great theme to generate documentation for python modules. Like @SebastianJL wrote, it would be really awesome to use just .. autoclass:: myclass
or maybe even .. automodule:: mymod
. Is it already possible?
The README says it uses toctree
's first, second and third level to populate top, left and right bar of this theme, bus Sphinx' autodoc
extention documentation says no word about if a module/class/method/etc. ends up in the toctree
or not.
I am a bloody beginner in this area so any help is appreciated :)
I've been having a bit of a dabble with this
I created a new template like
_template/class_page_toc.html
{% set class_toc = get_class_toc() %}
<nav id="bd-toc-nav">
<ul class="visible nav section-nav flex-column">
<li class="toc-h1 nav-item toc-entry" style="font-weight: 400; margin-left: 1rem; margin-bottom: 5px;">
{{class_toc.pretitle}}{{ class_toc.title }}
</li>
{% for item in class_toc.menu_items %}
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="{{ item.link }}">{{ item.title }}</a>
</li>
{% endfor %}
</ul>
</nav>
And then in your pydata theme you need to add a snippet like
def get_class_toc():
soup = bs(context["body"], "html.parser")
matches = soup.find_all('dl')
if matches is None or len(matches) is 0:
return ""
out = {
'title': '',
'menu_items': []
}
# remove the class dt
pyclass = matches.pop(0)
pyclass = pyclass.find('dt')
if pyclass is not None:
out['title'] = pyclass.get('id')
for match in matches:
match_dt = match.find('dt')
link = match.find(class_="headerlink")
if link is not None:
out['menu_items'].append({
'title': match_dt.get('id'),
'link': link['href']
})
return out
This gives me something like
Hope that helps somebody
Hello,
Thanks @rowanwins ! To give more precision you can add the following code in your conf.py
:
def _setup_navbar_side_toctree(app: Any):
def add_class_toctree_function(app: Any, pagename: Any, templatename: Any, context: Any, doctree: Any):
def get_class_toc() -> Any:
soup = BeautifulSoup(context["body"], "html.parser")
matches = soup.find_all('dl')
if matches is None or len(matches) == 0:
return ""
items = []
deeper_depth = matches[0].find('dt').get('id').count(".")
for match in matches:
match_dt = match.find('dt')
if match_dt is not None and match_dt.get('id') is not None:
current_title = match_dt.get('id')
current_depth = match_dt.get('id').count(".")
current_link = match.find(class_="headerlink")
if current_link is not None:
if deeper_depth > current_depth:
deeper_depth = current_depth
if deeper_depth == current_depth:
items.append({
"title": current_title,
"link": current_link["href"],
"attributes_and_methods": []
})
if deeper_depth < current_depth:
items[-1]["attributes_and_methods"].append(
{
"title": current_title,
"link": current_link["href"],
}
)
return items
context["get_class_toc"] = get_class_toc
app.connect("html-page-context", add_class_toctree_function)
def setup(app: Any):
for setup_function in [
_setup_navbar_side_toctree,
]:
setup_function(app)
and add add the folowing entry in conf.py
's html_theme_options
:
"page_sidebar_items": ["page-toc", "class-page-toc"],
and add the following html in template:
{% set class_toc = get_class_toc() %}
<nav id="bd-toc-nav", style="padding-top: 1rem;">
<ul class="visible nav section-nav flex-column">
{% for item in class_toc %}
<li class="toc-h1 nav-item toc-entry">
<a class="reference internal nav-link" href="{{ item.link }}">{{ item.title }}</a>
</li>
<ul class="visible nav section-nav flex-column">
{% for attr in item.attributes_and_methods %}
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="{{ attr.link }}">{{ attr.title }}</a>
</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
</nav>
@choldgraf, do you know if we have some snippets/recipes/wiki section to collect these examples from the community? I think this is probably beyond the configuration section in the docs... although it might be a new section, I guess... Thoughts?
@damianavila, I think github issues are well rferenced on Google so someone with the same need would ends up here eventually. I'm not sure we should duplicate them in the doc.
+1 on setting it to wontfix
and closing the issue as it's a heavy customisation of sphinx behaviours and @bloussou solutions seems to work
It seems Furo is integrating it in its secondary sidebar, we should do it as well: https://pradyunsg.me/furo/kitchen-sink/api/#furo._demo_module.show_warning
I think that this works on our site now, no?
I see this rST on the API page here.
.. automodule:: urllib.parse
:members:
and here's what it looks like:
I'm going to close this assuming it now works, but please re-open if it doesn't work on main
.
Reopen
I'd like to reopen this issue because:
- @choldgraf By default, only top-level functions and classes are shown, we'd like to control the visibility of the nested ones.
- Previous methods don't work anymore since current version used
secondary_sidebar_items
and there is nopage_sidebar_items
option (see layout).
Updated Solution
To show class methods and attributes/inner function, we need to set show_toc_level
as noted here, i.e., just specify in conf.py
:
html_theme_options = {
"show_toc_level": 2 # can increase, e.g., if there are nested classes
}
Which gives the following look:
Feature Request
There are still 2 problems I face and I wonder if these could be addressed:
- If the name of some item is too long, it is cropped - it would be better if the name could wrap (though this could be avoided by increasing the secondary sidebar width).
- There is an unnecessary pre-fix (
BaseGlassesModel
in the given example) for each autodoc-generated method/attribute name in the sidebar. Perhaps we could control whether or not to show the prefixes?
Workaround
The current workaround (for level 2 page-toc) is to add the following code to conf.py
:
from pathlib import Path
from bs4 import BeautifulSoup
def process_in_page_toc(app, exception):
if app.builder.format != "html":
return
for pagename in app.env.found_docs:
if not isinstance(pagename, str):
continue
with (Path(app.outdir) / f"{pagename}.html").open("r") as f:
# Parse HTML using BeautifulSoup html parser
soup = BeautifulSoup(f.read(), "html.parser")
for li in soup.find_all("li", class_="toc-h3 nav-item toc-entry"):
if span := li.find("span"):
# Modify the toc-nav span element here
span.string = span.string.split(".")[-1]
with (Path(app.outdir) / f"{pagename}.html").open("w") as f:
# Write back HTML
f.write(str(soup))
def setup(app):
app.connect("build-finished", process_in_page_toc)
Which gives the following look:
This is related with the anchors created by autosummary and the reason why you are not seeing them is because the scrollspy function from Bootstrap is not catching anchors with ".".
We're trying to find a solution and we are discussing the problem in https://github.com/pydata/pydata-sphinx-theme/issues/1435