mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-04-18 23:15:48 +00:00
Fix async iterable not showing up attributetable
Co-authored-by: Danny <Rapptz@users.noreply.github.com>
This commit is contained in:
parent
65a1c1014b
commit
c3d175fbc3
@ -1,78 +1,105 @@
|
|||||||
from sphinx.util.docutils import SphinxDirective
|
from __future__ import annotations
|
||||||
from sphinx.locale import _
|
|
||||||
from docutils import nodes
|
|
||||||
from sphinx import addnodes
|
|
||||||
|
|
||||||
from collections import OrderedDict, namedtuple
|
|
||||||
import importlib
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
|
from typing import Dict, List, NamedTuple, Optional, Tuple, Sequence, TYPE_CHECKING
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from sphinx import addnodes
|
||||||
|
from sphinx.application import Sphinx
|
||||||
|
from sphinx.environment import BuildEnvironment
|
||||||
|
from sphinx.locale import _
|
||||||
|
from sphinx.util.docutils import SphinxDirective
|
||||||
|
from sphinx.util.typing import OptionSpec
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .builder import DPYHTML5Translator
|
||||||
|
|
||||||
|
|
||||||
class attributetable(nodes.General, nodes.Element):
|
class attributetable(nodes.General, nodes.Element):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class attributetablecolumn(nodes.General, nodes.Element):
|
class attributetablecolumn(nodes.General, nodes.Element):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class attributetabletitle(nodes.TextElement):
|
class attributetabletitle(nodes.TextElement):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class attributetableplaceholder(nodes.General, nodes.Element):
|
class attributetableplaceholder(nodes.General, nodes.Element):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class attributetablebadge(nodes.TextElement):
|
class attributetablebadge(nodes.TextElement):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class attributetable_item(nodes.Part, nodes.Element):
|
class attributetable_item(nodes.Part, nodes.Element):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def visit_attributetable_node(self, node):
|
|
||||||
class_ = node["python-class"]
|
def visit_attributetable_node(self: DPYHTML5Translator, node: attributetable) -> None:
|
||||||
|
class_ = node['python-class']
|
||||||
self.body.append(f'<div class="py-attribute-table" data-move-to-id="{class_}">')
|
self.body.append(f'<div class="py-attribute-table" data-move-to-id="{class_}">')
|
||||||
|
|
||||||
def visit_attributetablecolumn_node(self, node):
|
|
||||||
|
def visit_attributetablecolumn_node(self: DPYHTML5Translator, node: attributetablecolumn) -> None:
|
||||||
self.body.append(self.starttag(node, 'div', CLASS='py-attribute-table-column'))
|
self.body.append(self.starttag(node, 'div', CLASS='py-attribute-table-column'))
|
||||||
|
|
||||||
def visit_attributetabletitle_node(self, node):
|
|
||||||
|
def visit_attributetabletitle_node(self: DPYHTML5Translator, node: attributetabletitle) -> None:
|
||||||
self.body.append(self.starttag(node, 'span'))
|
self.body.append(self.starttag(node, 'span'))
|
||||||
|
|
||||||
def visit_attributetablebadge_node(self, node):
|
|
||||||
|
def visit_attributetablebadge_node(self: DPYHTML5Translator, node: attributetablebadge) -> None:
|
||||||
attributes = {
|
attributes = {
|
||||||
'class': 'py-attribute-table-badge',
|
'class': 'py-attribute-table-badge',
|
||||||
'title': node['badge-type'],
|
'title': node['badge-type'],
|
||||||
}
|
}
|
||||||
self.body.append(self.starttag(node, 'span', **attributes))
|
self.body.append(self.starttag(node, 'span', **attributes))
|
||||||
|
|
||||||
def visit_attributetable_item_node(self, node):
|
|
||||||
|
def visit_attributetable_item_node(self: DPYHTML5Translator, node: attributetable_item) -> None:
|
||||||
self.body.append(self.starttag(node, 'li', CLASS='py-attribute-table-entry'))
|
self.body.append(self.starttag(node, 'li', CLASS='py-attribute-table-entry'))
|
||||||
|
|
||||||
def depart_attributetable_node(self, node):
|
|
||||||
|
def depart_attributetable_node(self: DPYHTML5Translator, node: attributetable) -> None:
|
||||||
self.body.append('</div>')
|
self.body.append('</div>')
|
||||||
|
|
||||||
def depart_attributetablecolumn_node(self, node):
|
|
||||||
|
def depart_attributetablecolumn_node(self: DPYHTML5Translator, node: attributetablecolumn) -> None:
|
||||||
self.body.append('</div>')
|
self.body.append('</div>')
|
||||||
|
|
||||||
def depart_attributetabletitle_node(self, node):
|
|
||||||
|
def depart_attributetabletitle_node(self: DPYHTML5Translator, node: attributetabletitle) -> None:
|
||||||
self.body.append('</span>')
|
self.body.append('</span>')
|
||||||
|
|
||||||
def depart_attributetablebadge_node(self, node):
|
|
||||||
|
def depart_attributetablebadge_node(self: DPYHTML5Translator, node: attributetablebadge) -> None:
|
||||||
self.body.append('</span>')
|
self.body.append('</span>')
|
||||||
|
|
||||||
def depart_attributetable_item_node(self, node):
|
|
||||||
|
def depart_attributetable_item_node(self: DPYHTML5Translator, node: attributetable_item) -> None:
|
||||||
self.body.append('</li>')
|
self.body.append('</li>')
|
||||||
|
|
||||||
|
|
||||||
_name_parser_regex = re.compile(r'(?P<module>[\w.]+\.)?(?P<name>\w+)')
|
_name_parser_regex = re.compile(r'(?P<module>[\w.]+\.)?(?P<name>\w+)')
|
||||||
|
|
||||||
|
|
||||||
class PyAttributeTable(SphinxDirective):
|
class PyAttributeTable(SphinxDirective):
|
||||||
has_content = False
|
has_content = False
|
||||||
required_arguments = 1
|
required_arguments = 1
|
||||||
optional_arguments = 0
|
optional_arguments = 0
|
||||||
final_argument_whitespace = False
|
final_argument_whitespace = False
|
||||||
option_spec = {}
|
option_spec: OptionSpec = {}
|
||||||
|
|
||||||
def parse_name(self, content):
|
def parse_name(self, content: str) -> Tuple[str, str]:
|
||||||
path, name = _name_parser_regex.match(content).groups()
|
match = _name_parser_regex.match(content)
|
||||||
|
if match is None:
|
||||||
|
raise RuntimeError(f"content {content} somehow doesn't match regex in {self.env.docname}.")
|
||||||
|
path, name = match.groups()
|
||||||
if path:
|
if path:
|
||||||
modulename = path.rstrip('.')
|
modulename = path.rstrip('.')
|
||||||
else:
|
else:
|
||||||
@ -80,11 +107,11 @@ class PyAttributeTable(SphinxDirective):
|
|||||||
if not modulename:
|
if not modulename:
|
||||||
modulename = self.env.ref_context.get('py:module')
|
modulename = self.env.ref_context.get('py:module')
|
||||||
if modulename is None:
|
if modulename is None:
|
||||||
raise RuntimeError('modulename somehow None for %s in %s.' % (content, self.env.docname))
|
raise RuntimeError(f'modulename somehow None for {content} in {self.env.docname}.')
|
||||||
|
|
||||||
return modulename, name
|
return modulename, name
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> List[attributetableplaceholder]:
|
||||||
"""If you're curious on the HTML this is meant to generate:
|
"""If you're curious on the HTML this is meant to generate:
|
||||||
|
|
||||||
<div class="py-attribute-table">
|
<div class="py-attribute-table">
|
||||||
@ -120,17 +147,21 @@ class PyAttributeTable(SphinxDirective):
|
|||||||
node['python-full-name'] = f'{modulename}.{name}'
|
node['python-full-name'] = f'{modulename}.{name}'
|
||||||
return [node]
|
return [node]
|
||||||
|
|
||||||
def build_lookup_table(env):
|
|
||||||
|
def build_lookup_table(env: BuildEnvironment) -> Dict[str, List[str]]:
|
||||||
# Given an environment, load up a lookup table of
|
# Given an environment, load up a lookup table of
|
||||||
# full-class-name: objects
|
# full-class-name: objects
|
||||||
result = {}
|
result = {}
|
||||||
domain = env.domains['py']
|
domain = env.domains['py']
|
||||||
|
|
||||||
ignored = {
|
ignored = {
|
||||||
'data', 'exception', 'module', 'class',
|
'data',
|
||||||
|
'exception',
|
||||||
|
'module',
|
||||||
|
'class',
|
||||||
}
|
}
|
||||||
|
|
||||||
for (fullname, _, objtype, docname, _, _) in domain.get_objects():
|
for fullname, _, objtype, docname, _, _ in domain.get_objects():
|
||||||
if objtype in ignored:
|
if objtype in ignored:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -143,9 +174,13 @@ def build_lookup_table(env):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
TableElement = namedtuple('TableElement', 'fullname label badge')
|
class TableElement(NamedTuple):
|
||||||
|
fullname: str
|
||||||
|
label: str
|
||||||
|
badge: Optional[attributetablebadge]
|
||||||
|
|
||||||
def process_attributetable(app, doctree, fromdocname):
|
|
||||||
|
def process_attributetable(app: Sphinx, doctree: nodes.Node, fromdocname: str) -> None:
|
||||||
env = app.builder.env
|
env = app.builder.env
|
||||||
|
|
||||||
lookup = build_lookup_table(env)
|
lookup = build_lookup_table(env)
|
||||||
@ -165,14 +200,17 @@ def process_attributetable(app, doctree, fromdocname):
|
|||||||
else:
|
else:
|
||||||
node.replace_self([table])
|
node.replace_self([table])
|
||||||
|
|
||||||
def get_class_results(lookup, modulename, name, fullname):
|
|
||||||
|
def get_class_results(
|
||||||
|
lookup: Dict[str, List[str]], modulename: str, name: str, fullname: str
|
||||||
|
) -> Dict[str, List[TableElement]]:
|
||||||
module = importlib.import_module(modulename)
|
module = importlib.import_module(modulename)
|
||||||
cls = getattr(module, name)
|
cls = getattr(module, name)
|
||||||
|
|
||||||
groups = OrderedDict([
|
groups: Dict[str, List[TableElement]] = {
|
||||||
(_('Attributes'), []),
|
_('Attributes'): [],
|
||||||
(_('Methods'), []),
|
_('Methods'): [],
|
||||||
])
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
members = lookup[fullname]
|
members = lookup[fullname]
|
||||||
@ -205,9 +243,13 @@ def get_class_results(lookup, modulename, name, fullname):
|
|||||||
elif inspect.isfunction(value):
|
elif inspect.isfunction(value):
|
||||||
if doc.startswith(('A decorator', 'A shortcut decorator')):
|
if doc.startswith(('A decorator', 'A shortcut decorator')):
|
||||||
# finicky but surprisingly consistent
|
# finicky but surprisingly consistent
|
||||||
|
key = _('Methods')
|
||||||
badge = attributetablebadge('@', '@')
|
badge = attributetablebadge('@', '@')
|
||||||
badge['badge-type'] = _('decorator')
|
badge['badge-type'] = _('decorator')
|
||||||
|
elif inspect.isasyncgenfunction(value):
|
||||||
key = _('Methods')
|
key = _('Methods')
|
||||||
|
badge = attributetablebadge('async for', 'async for')
|
||||||
|
badge['badge-type'] = _('async iterable')
|
||||||
else:
|
else:
|
||||||
key = _('Methods')
|
key = _('Methods')
|
||||||
badge = attributetablebadge('def', 'def')
|
badge = attributetablebadge('def', 'def')
|
||||||
@ -217,14 +259,14 @@ def get_class_results(lookup, modulename, name, fullname):
|
|||||||
|
|
||||||
return groups
|
return groups
|
||||||
|
|
||||||
def class_results_to_node(key, elements):
|
|
||||||
|
def class_results_to_node(key: str, elements: Sequence[TableElement]) -> attributetablecolumn:
|
||||||
title = attributetabletitle(key, key)
|
title = attributetabletitle(key, key)
|
||||||
ul = nodes.bullet_list('')
|
ul = nodes.bullet_list('')
|
||||||
for element in elements:
|
for element in elements:
|
||||||
ref = nodes.reference('', '', internal=True,
|
ref = nodes.reference(
|
||||||
refuri='#' + element.fullname,
|
'', '', internal=True, refuri=f'#{element.fullname}', anchorname='', *[nodes.Text(element.label)]
|
||||||
anchorname='',
|
)
|
||||||
*[nodes.Text(element.label)])
|
|
||||||
para = addnodes.compact_paragraph('', '', ref)
|
para = addnodes.compact_paragraph('', '', ref)
|
||||||
if element.badge is not None:
|
if element.badge is not None:
|
||||||
ul.append(attributetable_item('', element.badge, para))
|
ul.append(attributetable_item('', element.badge, para))
|
||||||
@ -233,7 +275,8 @@ def class_results_to_node(key, elements):
|
|||||||
|
|
||||||
return attributetablecolumn('', title, ul)
|
return attributetablecolumn('', title, ul)
|
||||||
|
|
||||||
def setup(app):
|
|
||||||
|
def setup(app: Sphinx) -> None:
|
||||||
app.add_directive('attributetable', PyAttributeTable)
|
app.add_directive('attributetable', PyAttributeTable)
|
||||||
app.add_node(attributetable, html=(visit_attributetable_node, depart_attributetable_node))
|
app.add_node(attributetable, html=(visit_attributetable_node, depart_attributetable_node))
|
||||||
app.add_node(attributetablecolumn, html=(visit_attributetablecolumn_node, depart_attributetablecolumn_node))
|
app.add_node(attributetablecolumn, html=(visit_attributetablecolumn_node, depart_attributetablecolumn_node))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user