Merge pull request #3961 from gaborbernat/master

fixes #3959 alias/rename support for classes inside inheritence diagrams
This commit is contained in:
Takeshi KOMIYA
2017-08-20 00:41:50 +09:00
committed by GitHub
6 changed files with 64 additions and 16 deletions

3
.gitignore vendored
View File

@@ -23,3 +23,6 @@ doc/_build/
tests/.coverage
tests/build/
utils/regression_test.js
# IDE
.idea

View File

@@ -66,3 +66,13 @@ New config values are:
.. confval:: inheritance_edge_attrs
A dictionary of graphviz edge attributes for inheritance diagrams.
.. confval:: inheritance_alias
Allows mapping the full qualified name of the class to custom values
(useful when exposing the underlying path of a class is not desirable,
e.g. it's a private class and should not be instantiated by the user).
For example::
inheritance_alias = {'_pytest.Magic': 'pytest.Magic'}

View File

@@ -55,7 +55,7 @@ from sphinx.util import force_decode
if False:
# For type annotation
from typing import Any, Dict, List, Tuple # NOQA
from typing import Any, Dict, List, Tuple, Dict, Optional # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.environment import BuildEnvironment # NOQA
@@ -130,8 +130,8 @@ class InheritanceGraph(object):
graphviz dot graph from them.
"""
def __init__(self, class_names, currmodule, show_builtins=False,
private_bases=False, parts=0):
# type: (unicode, str, bool, bool, int) -> None
private_bases=False, parts=0, aliases=None):
# type: (unicode, str, bool, bool, int, Optional[Dict[unicode, unicode]]) -> None
"""*class_names* is a list of child classes to show bases from.
If *show_builtins* is True, then Python builtins will be shown
@@ -140,7 +140,7 @@ class InheritanceGraph(object):
self.class_names = class_names
classes = self._import_classes(class_names, currmodule)
self.class_info = self._class_info(classes, show_builtins,
private_bases, parts)
private_bases, parts, aliases)
if not self.class_info:
raise InheritanceException('No classes found for '
'inheritance diagram')
@@ -153,8 +153,8 @@ class InheritanceGraph(object):
classes.extend(import_classes(name, currmodule))
return classes
def _class_info(self, classes, show_builtins, private_bases, parts):
# type: (List[Any], bool, bool, int) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA
def _class_info(self, classes, show_builtins, private_bases, parts, aliases):
# type: (List[Any], bool, bool, int, Optional[Dict[unicode, unicode]]) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA
"""Return name and bases for all classes that are ancestors of
*classes*.
@@ -171,8 +171,8 @@ class InheritanceGraph(object):
if not private_bases and cls.__name__.startswith('_'):
return
nodename = self.class_name(cls, parts)
fullname = self.class_name(cls, 0)
nodename = self.class_name(cls, parts, aliases)
fullname = self.class_name(cls, 0, aliases)
# Use first line of docstring as tooltip, if available
tooltip = None
@@ -194,7 +194,7 @@ class InheritanceGraph(object):
continue
if not private_bases and base.__name__.startswith('_'):
continue
baselist.append(self.class_name(base, parts))
baselist.append(self.class_name(base, parts, aliases))
if base not in all_classes:
recurse(base)
@@ -203,8 +203,8 @@ class InheritanceGraph(object):
return list(all_classes.values())
def class_name(self, cls, parts=0):
# type: (Any, int) -> unicode
def class_name(self, cls, parts=0, aliases=None):
# type: (Any, int, Optional[Dict[unicode, unicode]]) -> unicode
"""Given a class object, return a fully-qualified name.
This works for things I've tested in matplotlib so far, but may not be
@@ -216,9 +216,13 @@ class InheritanceGraph(object):
else:
fullname = '%s.%s' % (module, cls.__name__)
if parts == 0:
return fullname
name_parts = fullname.split('.')
return '.'.join(name_parts[-parts:])
result = fullname
else:
name_parts = fullname.split('.')
result = '.'.join(name_parts[-parts:])
if aliases is not None and result in aliases:
return aliases[result]
return result
def get_all_class_names(self):
# type: () -> List[unicode]
@@ -336,7 +340,8 @@ class InheritanceDiagram(Directive):
graph = InheritanceGraph(
class_names, env.ref_context.get('py:module'),
parts=node['parts'],
private_bases='private-bases' in self.options)
private_bases='private-bases' in self.options,
aliases=env.config.inheritance_alias)
except InheritanceException as err:
return [node.document.reporter.warning(err.args[0],
line=self.lineno)]
@@ -450,4 +455,5 @@ def setup(app):
app.add_config_value('inheritance_graph_attrs', {}, False)
app.add_config_value('inheritance_node_attrs', {}, False)
app.add_config_value('inheritance_edge_attrs', {}, False)
app.add_config_value('inheritance_alias', {}, False)
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -6,3 +6,5 @@ test-ext-inheritance_diagram
.. inheritance-diagram:: test.Foo
:caption: Test Foo!
.. inheritance-diagram:: test.Baz

View File

@@ -11,9 +11,11 @@
import re
import sys
from sphinx.ext.inheritance_diagram import InheritanceException, import_classes
import pytest
from sphinx.ext.inheritance_diagram import InheritanceException, import_classes
@pytest.mark.sphinx('html', testroot='ext-inheritance_diagram')
@pytest.mark.usefixtures('if_graphviz_found')
@@ -43,6 +45,30 @@ def test_inheritance_diagram_latex(app, status, warning):
assert re.search(pattern, content, re.M)
@pytest.mark.sphinx('html', testroot='ext-inheritance_diagram',
srcdir='ext-inheritance_diagram-alias')
@pytest.mark.usefixtures('if_graphviz_found')
def test_inheritance_diagram_latex_alias(app, status, warning):
app.config.inheritance_alias = {'test.Foo': 'alias.Foo'}
app.builder.build_all()
doc = app.env.get_and_resolve_doctree('index', app)
aliased_graph = doc.children[0].children[3]['graph'].class_info
assert len(aliased_graph) == 3
assert ('test.Baz', 'test.Baz', ['test.Bar'], None) in aliased_graph
assert ('test.Bar', 'test.Bar', ['alias.Foo'], None) in aliased_graph
assert ('alias.Foo', 'alias.Foo', [], None) in aliased_graph
content = (app.outdir / 'index.html').text()
pattern = ('<div class="figure" id="id1">\n'
'<img src="_images/inheritance-\\w+.png" alt="Inheritance diagram of test.Foo" '
'class="inheritance"/>\n<p class="caption"><span class="caption-text">'
'Test Foo!</span><a class="headerlink" href="#id1" '
'title="Permalink to this image">\xb6</a></p>')
assert re.search(pattern, content, re.M)
def test_import_classes(rootdir):
from sphinx.application import Sphinx, TemplateBridge
from sphinx.util.i18n import CatalogInfo

View File

@@ -2,6 +2,7 @@
envlist=flake8,py27,py34,py35,py36,pypy,du13,du12,du11
[testenv]
passenv = https_proxy http_proxy no_proxy
deps=
six
pytest