mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #3961 from gaborbernat/master
fixes #3959 alias/rename support for classes inside inheritence diagrams
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -23,3 +23,6 @@ doc/_build/
|
||||
tests/.coverage
|
||||
tests/build/
|
||||
utils/regression_test.js
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -6,3 +6,5 @@ test-ext-inheritance_diagram
|
||||
|
||||
.. inheritance-diagram:: test.Foo
|
||||
:caption: Test Foo!
|
||||
|
||||
.. inheritance-diagram:: test.Baz
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user