Rework attributetable to look prettier
This commit is contained in:
		
							
								
								
									
										67
									
								
								docs/_static/style.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										67
									
								
								docs/_static/style.css
									
									
									
									
										vendored
									
									
								
							@@ -97,6 +97,13 @@ Historically however, thanks to:
 | 
				
			|||||||
  --rtd-ad-background: var(--grey-2);
 | 
					  --rtd-ad-background: var(--grey-2);
 | 
				
			||||||
  --rtd-ad-main-text: var(--grey-6);
 | 
					  --rtd-ad-main-text: var(--grey-6);
 | 
				
			||||||
  --rtd-ad-small-text: var(--grey-4);
 | 
					  --rtd-ad-small-text: var(--grey-4);
 | 
				
			||||||
 | 
					  --attribute-table-title: var(--grey-6);
 | 
				
			||||||
 | 
					  --attribute-table-entry-border: var(--grey-3);
 | 
				
			||||||
 | 
					  --attribute-table-entry-text: var(--grey-5);
 | 
				
			||||||
 | 
					  --attribute-table-entry-hover-border: var(--blue);
 | 
				
			||||||
 | 
					  --attribute-table-entry-hover-background: var(--grey-2);
 | 
				
			||||||
 | 
					  --attribute-table-entry-hover-text: var(--blue);
 | 
				
			||||||
 | 
					  --attribute-table-badge: var(--grey-7);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:root[data-font="sans"] {
 | 
					:root[data-font="sans"] {
 | 
				
			||||||
@@ -151,6 +158,13 @@ Historically however, thanks to:
 | 
				
			|||||||
  --rtd-ad-background: var(--grey-5);
 | 
					  --rtd-ad-background: var(--grey-5);
 | 
				
			||||||
  --rtd-ad-main-text: var(--grey-2);
 | 
					  --rtd-ad-main-text: var(--grey-2);
 | 
				
			||||||
  --rtd-ad-small-text: var(--grey-1);
 | 
					  --rtd-ad-small-text: var(--grey-1);
 | 
				
			||||||
 | 
					  --attribute-table-title: var(--grey-3);
 | 
				
			||||||
 | 
					  --attribute-table-entry-border: var(--grey-5);
 | 
				
			||||||
 | 
					  --attribute-table-entry-text: var(--grey-3);
 | 
				
			||||||
 | 
					  --attribute-table-entry-hover-border: var(--blue);
 | 
				
			||||||
 | 
					  --attribute-table-entry-hover-background: var(--grey-6);
 | 
				
			||||||
 | 
					  --attribute-table-entry-hover-text: var(--blue);
 | 
				
			||||||
 | 
					  --attribute-table-badge: var(--grey-4);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
img[src$="snake_dark.svg"]  {
 | 
					img[src$="snake_dark.svg"]  {
 | 
				
			||||||
@@ -744,19 +758,64 @@ div.helpful > p.admonition-title::after {
 | 
				
			|||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  flex-wrap: wrap;
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
  flex-direction: row;
 | 
					  flex-direction: row;
 | 
				
			||||||
  justify-content: space-between;
 | 
					 | 
				
			||||||
  margin: 0 2em;
 | 
					  margin: 0 2em;
 | 
				
			||||||
  padding-top: 16px;
 | 
					  padding-top: 16px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.py-attribute-table-column {
 | 
				
			||||||
 | 
					  flex: 1 1 auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.py-attribute-table-column:not(:first-child) {
 | 
				
			||||||
 | 
					  margin-top: 1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.py-attribute-table-column > span {
 | 
					.py-attribute-table-column > span {
 | 
				
			||||||
  font-weight: bold;
 | 
					  font-weight: bold;
 | 
				
			||||||
 | 
					  color: var(--attribute-table-title);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main .py-attribute-table-column > ul {
 | 
					main .py-attribute-table-column > ul {
 | 
				
			||||||
  list-style: none;
 | 
					  list-style: none;
 | 
				
			||||||
  margin: 4px 0px;
 | 
					  margin: 4px 0px;
 | 
				
			||||||
  padding-left: 12px;
 | 
					  padding-left: 0;
 | 
				
			||||||
 | 
					  font-size: 0.95em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.py-attribute-table-entry {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 2px 0;
 | 
				
			||||||
 | 
					  padding-left: 0.2em;
 | 
				
			||||||
 | 
					  border-left: 2px solid var(--attribute-table-entry-border);
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  line-height: 1.2em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.py-attribute-table-entry > a {
 | 
				
			||||||
 | 
					  padding-left: 0.5em;
 | 
				
			||||||
 | 
					  color: var(--attribute-table-entry-text);
 | 
				
			||||||
 | 
					  flex-grow: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.py-attribute-table-entry > a:hover {
 | 
				
			||||||
 | 
					  color: var(--attribute-table-entry-hover-text);
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.py-attribute-table-entry:hover {
 | 
				
			||||||
 | 
					  background-color: var(--attribute-table-entry-hover-background);
 | 
				
			||||||
 | 
					  border-left: 2px solid var(--attribute-table-entry-hover-border);
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.py-attribute-table-badge {
 | 
				
			||||||
 | 
					  flex-basis: 3em;
 | 
				
			||||||
 | 
					  text-align: right;
 | 
				
			||||||
 | 
					  font-size: 0.9em;
 | 
				
			||||||
 | 
					  color: var(--attribute-table-badge);
 | 
				
			||||||
 | 
					  -moz-user-select: none;
 | 
				
			||||||
 | 
					  -webkit-user-select: none;
 | 
				
			||||||
 | 
					  user-select: none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pre {
 | 
					pre {
 | 
				
			||||||
@@ -1076,6 +1135,10 @@ div.code-block-caption {
 | 
				
			|||||||
    font-size: 1.5em;
 | 
					    font-size: 1.5em;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .py-attribute-table-column:not(:first-child) {
 | 
				
			||||||
 | 
					    margin-top: unset;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  main img {
 | 
					  main img {
 | 
				
			||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
    margin-left: auto;
 | 
					    margin-left: auto;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ from sphinx.locale import _
 | 
				
			|||||||
from docutils import nodes
 | 
					from docutils import nodes
 | 
				
			||||||
from sphinx import addnodes
 | 
					from sphinx import addnodes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import OrderedDict
 | 
					from collections import OrderedDict, namedtuple
 | 
				
			||||||
import importlib
 | 
					import importlib
 | 
				
			||||||
import inspect
 | 
					import inspect
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
@@ -21,6 +21,12 @@ class attributetabletitle(nodes.TextElement):
 | 
				
			|||||||
class attributetableplaceholder(nodes.General, nodes.Element):
 | 
					class attributetableplaceholder(nodes.General, nodes.Element):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class attributetablebadge(nodes.TextElement):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class attributetable_item(nodes.Part, nodes.Element):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def visit_attributetable_node(self, node):
 | 
					def visit_attributetable_node(self, node):
 | 
				
			||||||
    self.body.append('<div class="py-attribute-table" data-move-to-id="%s">' % node['python-class'])
 | 
					    self.body.append('<div class="py-attribute-table" data-move-to-id="%s">' % node['python-class'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,6 +36,16 @@ def visit_attributetablecolumn_node(self, node):
 | 
				
			|||||||
def visit_attributetabletitle_node(self, node):
 | 
					def visit_attributetabletitle_node(self, node):
 | 
				
			||||||
    self.body.append(self.starttag(node, 'span'))
 | 
					    self.body.append(self.starttag(node, 'span'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def visit_attributetablebadge_node(self, node):
 | 
				
			||||||
 | 
					    attributes = {
 | 
				
			||||||
 | 
					        'class': 'py-attribute-table-badge',
 | 
				
			||||||
 | 
					        'title': node['badge-type'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    self.body.append(self.starttag(node, 'span', **attributes))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def visit_attributetable_item_node(self, node):
 | 
				
			||||||
 | 
					    self.body.append(self.starttag(node, 'li', CLASS='py-attribute-table-entry'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def depart_attributetable_node(self, node):
 | 
					def depart_attributetable_node(self, node):
 | 
				
			||||||
    self.body.append('</div>')
 | 
					    self.body.append('</div>')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,6 +55,12 @@ def depart_attributetablecolumn_node(self, node):
 | 
				
			|||||||
def depart_attributetabletitle_node(self, node):
 | 
					def depart_attributetabletitle_node(self, node):
 | 
				
			||||||
    self.body.append('</span>')
 | 
					    self.body.append('</span>')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def depart_attributetablebadge_node(self, node):
 | 
				
			||||||
 | 
					    self.body.append('</span>')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def depart_attributetable_item_node(self, node):
 | 
				
			||||||
 | 
					    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):
 | 
				
			||||||
@@ -68,22 +90,20 @@ class PyAttributeTable(SphinxDirective):
 | 
				
			|||||||
            <div class="py-attribute-table-column">
 | 
					            <div class="py-attribute-table-column">
 | 
				
			||||||
                <span>_('Attributes')</span>
 | 
					                <span>_('Attributes')</span>
 | 
				
			||||||
                <ul>
 | 
					                <ul>
 | 
				
			||||||
                    <li><a href="..."></li>
 | 
					                    <li>
 | 
				
			||||||
                </ul>
 | 
					                        <a href="...">
 | 
				
			||||||
            </div>
 | 
					                    </li>
 | 
				
			||||||
            <div class="py-attribute-table-column">
 | 
					 | 
				
			||||||
                <span>_('Coroutines')</span>
 | 
					 | 
				
			||||||
                <ul>
 | 
					 | 
				
			||||||
                    <li><a href="..."></li>
 | 
					 | 
				
			||||||
                </ul>
 | 
					                </ul>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="py-attribute-table-column">
 | 
					            <div class="py-attribute-table-column">
 | 
				
			||||||
                <span>_('Methods')</span>
 | 
					                <span>_('Methods')</span>
 | 
				
			||||||
                <ul>
 | 
					                <ul>
 | 
				
			||||||
                    <li><a href="..."></li>
 | 
					                    <li>
 | 
				
			||||||
 | 
					                        <a href="..."></a>
 | 
				
			||||||
 | 
					                        <span class="py-attribute-badge" title="decorator">D</span>
 | 
				
			||||||
 | 
					                    </li>
 | 
				
			||||||
                </ul>
 | 
					                </ul>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            ...
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        However, since this requires the tree to be complete
 | 
					        However, since this requires the tree to be complete
 | 
				
			||||||
@@ -120,6 +140,9 @@ def build_lookup_table(env):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return result
 | 
					    return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TableElement = namedtuple('TableElement', 'fullname label badge')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def process_attributetable(app, doctree, fromdocname):
 | 
					def process_attributetable(app, doctree, fromdocname):
 | 
				
			||||||
    env = app.builder.env
 | 
					    env = app.builder.env
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,7 +154,7 @@ def process_attributetable(app, doctree, fromdocname):
 | 
				
			|||||||
        for label, subitems in groups.items():
 | 
					        for label, subitems in groups.items():
 | 
				
			||||||
            if not subitems:
 | 
					            if not subitems:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            table.append(class_results_to_node(label, sorted(subitems)))
 | 
					            table.append(class_results_to_node(label, sorted(subitems, key=lambda c: c.label)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        table['python-class'] = fullname
 | 
					        table['python-class'] = fullname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,11 +168,8 @@ def get_class_results(lookup, modulename, name, fullname):
 | 
				
			|||||||
    cls_dict = getattr(module, name).__dict__
 | 
					    cls_dict = getattr(module, name).__dict__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    groups = OrderedDict([
 | 
					    groups = OrderedDict([
 | 
				
			||||||
        ('Attributes', []),
 | 
					        (_('Attributes'), []),
 | 
				
			||||||
        ('Coroutines', []),
 | 
					        (_('Methods'), []),
 | 
				
			||||||
        ('Classmethods', []),
 | 
					 | 
				
			||||||
        ('Methods', []),
 | 
					 | 
				
			||||||
        ('Decorators', []),
 | 
					 | 
				
			||||||
    ])
 | 
					    ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@@ -159,38 +179,50 @@ def get_class_results(lookup, modulename, name, fullname):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    for attr in members:
 | 
					    for attr in members:
 | 
				
			||||||
        attrlookup = '%s.%s' % (fullname, attr)
 | 
					        attrlookup = '%s.%s' % (fullname, attr)
 | 
				
			||||||
        key = 'Attributes'
 | 
					        key = _('Attributes')
 | 
				
			||||||
 | 
					        badge = None
 | 
				
			||||||
        label = attr
 | 
					        label = attr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        value = cls_dict.get(attr)
 | 
					        value = cls_dict.get(attr)
 | 
				
			||||||
        if value is not None:
 | 
					        if value is not None:
 | 
				
			||||||
            doc = value.__doc__ or ''
 | 
					            doc = value.__doc__ or ''
 | 
				
			||||||
            if inspect.iscoroutinefunction(value) or doc.startswith('|coro|'):
 | 
					            if inspect.iscoroutinefunction(value) or doc.startswith('|coro|'):
 | 
				
			||||||
                key = 'Coroutines'
 | 
					                key = _('Methods')
 | 
				
			||||||
 | 
					                badge = attributetablebadge('async', 'async')
 | 
				
			||||||
 | 
					                badge['badge-type'] = _('coroutine')
 | 
				
			||||||
            elif isinstance(value, classmethod):
 | 
					            elif isinstance(value, classmethod):
 | 
				
			||||||
                key = 'Classmethods'
 | 
					                key = _('Methods')
 | 
				
			||||||
 | 
					                label = '%s.%s' % (name, attr)
 | 
				
			||||||
 | 
					                badge = attributetablebadge('cls', 'cls')
 | 
				
			||||||
 | 
					                badge['badge-type'] = _('classmethod')
 | 
				
			||||||
            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 = 'Decorators'
 | 
					                    badge = attributetablebadge('@', '@')
 | 
				
			||||||
 | 
					                    badge['badge-type'] = _('decorator')
 | 
				
			||||||
 | 
					                    key = _('Methods')
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    key = 'Methods'
 | 
					                    key = _('Methods')
 | 
				
			||||||
 | 
					                    badge = attributetablebadge('def', 'def')
 | 
				
			||||||
 | 
					                    badge['badge-type'] = _('method')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        groups[key].append((attrlookup, label))
 | 
					        groups[key].append(TableElement(fullname=attrlookup, label=label, badge=badge))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return groups
 | 
					    return groups
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def class_results_to_node(key, elements):
 | 
					def class_results_to_node(key, elements):
 | 
				
			||||||
    title = attributetabletitle(key, key)
 | 
					    title = attributetabletitle(key, key)
 | 
				
			||||||
    ul = nodes.bullet_list('')
 | 
					    ul = nodes.bullet_list('')
 | 
				
			||||||
    for fullname, label in elements:
 | 
					    for element in elements:
 | 
				
			||||||
        ref = nodes.reference('', '', internal=True,
 | 
					        ref = nodes.reference('', '', internal=True,
 | 
				
			||||||
                                      refuri='#' + fullname,
 | 
					                                      refuri='#' + element.fullname,
 | 
				
			||||||
                                      anchorname='',
 | 
					                                      anchorname='',
 | 
				
			||||||
                                      *[nodes.Text(label)])
 | 
					                                      *[nodes.Text(element.label)])
 | 
				
			||||||
        para = addnodes.compact_paragraph('', '', ref)
 | 
					        para = addnodes.compact_paragraph('', '', ref)
 | 
				
			||||||
        item = nodes.list_item('', para)
 | 
					        if element.badge is not None:
 | 
				
			||||||
        ul.append(item)
 | 
					            ul.append(attributetable_item('', element.badge, para))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            ul.append(attributetable_item('', para))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return attributetablecolumn('', title, ul)
 | 
					    return attributetablecolumn('', title, ul)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -199,5 +231,7 @@ def setup(app):
 | 
				
			|||||||
    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))
 | 
				
			||||||
    app.add_node(attributetabletitle, html=(visit_attributetabletitle_node, depart_attributetabletitle_node))
 | 
					    app.add_node(attributetabletitle, html=(visit_attributetabletitle_node, depart_attributetabletitle_node))
 | 
				
			||||||
 | 
					    app.add_node(attributetablebadge, html=(visit_attributetablebadge_node, depart_attributetablebadge_node))
 | 
				
			||||||
 | 
					    app.add_node(attributetable_item, html=(visit_attributetable_item_node, depart_attributetable_item_node))
 | 
				
			||||||
    app.add_node(attributetableplaceholder)
 | 
					    app.add_node(attributetableplaceholder)
 | 
				
			||||||
    app.connect('doctree-resolved', process_attributetable)
 | 
					    app.connect('doctree-resolved', process_attributetable)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user