aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/doc/inheritance_diagram.py
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/doc/inheritance_diagram.py')
-rw-r--r--sources/pyside6/doc/inheritance_diagram.py229
1 files changed, 11 insertions, 218 deletions
diff --git a/sources/pyside6/doc/inheritance_diagram.py b/sources/pyside6/doc/inheritance_diagram.py
index 5889abb6f..e972fac4c 100644
--- a/sources/pyside6/doc/inheritance_diagram.py
+++ b/sources/pyside6/doc/inheritance_diagram.py
@@ -37,10 +37,6 @@ r"""
:license: BSD, see LICENSE for details.
"""
-import os
-import re
-import sys
-import inspect
try:
from hashlib import md5
except ImportError:
@@ -51,211 +47,8 @@ from docutils.parsers.rst import directives, Directive
from sphinx.ext.graphviz import render_dot_html, render_dot_latex
-class InheritanceException(Exception):
- pass
-
-# When passed something like:
-# PySide6.QtCore.QStateMachine.SignalEvent
-# try to import the underlying module and return a
-# handle to the object. In a loop, import
-# PySide6.QtCore.QStateMachine.SignalEvent
-# PySide6.QtCore.QStateMachine
-# PySide6.QtCore
-# until the import succeeds and walk up the attributes
-# to obtain the object
-
-def importClassOrModule(name):
- components = name.split('.')
- for i in range(len(components), 0, -1):
- importPath = '.'.join(components[: i])
- try:
- __import__(importPath)
- except ImportError:
- continue
- if i == len(components):
- return sys.modules[importPath]
- remaining = components[i :]
- cls = sys.modules[importPath]
- for component in remaining:
- try:
- cls = getattr(cls, component)
- except Exception: # No such attribute
- return None
- return cls
- return None
-
-class InheritanceGraph(object):
- """
- Given a list of classes, determines the set of classes that they inherit
- from all the way to the root "object", and then is able to generate a
- graphviz dot graph from them.
- """
- def __init__(self, class_names, currmodule, show_builtins=False, parts=0):
- """
- *class_names* is a list of child classes to show bases from.
-
- If *show_builtins* is True, then Python builtins will be shown
- in the graph.
- """
- self.class_names = class_names
- classes = self._import_classes(class_names, currmodule)
- self.class_info = self._class_info(classes, show_builtins, parts)
- if not self.class_info:
- raise InheritanceException('No classes found for '
- 'inheritance diagram')
-
- def _import_class_or_module(self, name, currmodule):
- """
- Import a class using its fully-qualified *name*.
- """
- todoc = importClassOrModule(name)
- if not todoc and currmodule is not None:
- todoc = importClassOrModule(f"{currmodule}.{name}")
- if not todoc:
- moduleStr = f'(module {currmodule})' if currmodule else ''
- raise InheritanceException(f'Could not import class {name} specified for '
- f'inheritance diagram {moduleStr}.')
- if inspect.isclass(todoc):
- return [todoc]
- elif inspect.ismodule(todoc):
- classes = []
- for cls in todoc.__dict__.values():
- if inspect.isclass(cls) and cls.__module__ == todoc.__name__:
- classes.append(cls)
- return classes
- raise InheritanceException(f'{name} specified for inheritance diagram is '
- 'not a class or module')
-
- def _import_classes(self, class_names, currmodule):
- """Import a list of classes."""
- classes = []
- for name in class_names:
- classes.extend(self._import_class_or_module(name, currmodule))
- return classes
-
- def _class_info(self, classes, show_builtins, parts):
- """Return name and bases for all classes that are ancestors of
- *classes*.
-
- *parts* gives the number of dotted name parts that is removed from the
- displayed node names.
- """
- all_classes = {}
- builtins = __builtins__.values()
-
- def recurse(cls):
- if not show_builtins and cls in builtins:
- return
-
- nodename = self.class_name(cls, parts)
- fullname = self.class_name(cls, 0)
-
- baselist = []
- all_classes[cls] = (nodename, fullname, baselist)
- for base in cls.__bases__:
- if not show_builtins and base in builtins:
- continue
- if base.__name__ == "Object" and base.__module__ == "Shiboken":
- continue
- baselist.append(self.class_name(base, parts))
- if base not in all_classes:
- recurse(base)
-
- for cls in classes:
- recurse(cls)
-
- return list(all_classes.values())
-
- def class_name(self, cls, parts=0):
- """Given a class object, return a fully-qualified name.
-
- This works for things I've tested in matplotlib so far, but may not be
- completely general.
- """
- module = cls.__module__
- if module == '__builtin__':
- fullname = cls.__name__
- else:
- fullname = f"{module}.{cls.__qualname__}"
- if parts == 0:
- return fullname
- name_parts = fullname.split('.')
- return '.'.join(name_parts[-parts:])
-
- def get_all_class_names(self):
- """
- Get all of the class names involved in the graph.
- """
- return [fullname for (_, fullname, _) in self.class_info]
-
- # These are the default attrs for graphviz
- default_graph_attrs = {
- 'rankdir': 'LR',
- 'size': '"8.0, 12.0"',
- }
- default_node_attrs = {
- 'shape': 'box',
- 'fontsize': 10,
- 'height': 0.25,
- 'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, '
- 'Arial, Helvetica, sans"',
- 'style': '"setlinewidth(0.5)"',
- }
- default_edge_attrs = {
- 'arrowsize': 0.5,
- 'style': '"setlinewidth(0.5)"',
- }
-
- def _format_node_attrs(self, attrs):
- return ','.join(['%s=%s' % x for x in attrs.items()])
-
- def _format_graph_attrs(self, attrs):
- return ''.join([f"{x[0]}={x[1]};\n" for x in attrs.items()])
-
- def generate_dot(self, name, urls={}, env=None,
- graph_attrs={}, node_attrs={}, edge_attrs={}):
- """
- Generate a graphviz dot graph from the classes that
- were passed in to __init__.
-
- *name* is the name of the graph.
-
- *urls* is a dictionary mapping class names to HTTP URLs.
-
- *graph_attrs*, *node_attrs*, *edge_attrs* are dictionaries containing
- key/value pairs to pass on as graphviz properties.
- """
- g_attrs = self.default_graph_attrs.copy()
- n_attrs = self.default_node_attrs.copy()
- e_attrs = self.default_edge_attrs.copy()
- g_attrs.update(graph_attrs)
- n_attrs.update(node_attrs)
- e_attrs.update(edge_attrs)
- if env:
- g_attrs.update(env.config.inheritance_graph_attrs)
- n_attrs.update(env.config.inheritance_node_attrs)
- e_attrs.update(env.config.inheritance_edge_attrs)
-
- res = []
- res.append('digraph %s {\n' % name)
- res.append(self._format_graph_attrs(g_attrs))
-
- for name, fullname, bases in self.class_info:
- # Write the node
- this_node_attrs = n_attrs.copy()
- url = urls.get(fullname)
- if url is not None:
- this_node_attrs['URL'] = '"%s"' % url
- res.append(' "%s" [%s];\n' %
- (name, self._format_node_attrs(this_node_attrs)))
-
- # Write the edges
- for base_name in bases:
- res.append(' "%s" -> "%s" [%s];\n' %
- (base_name, name,
- self._format_node_attrs(e_attrs)))
- res.append('}\n')
- return ''.join(res)
+from inheritance_graph import InheritanceGraph
+from import_inheritance import (InheritanceException)
class inheritance_diagram(nodes.General, nodes.Element):
@@ -291,7 +84,7 @@ class InheritanceDiagram(Directive):
try:
graph = InheritanceGraph(
class_names, env.temp_data.get('py:module'),
- parts=node['parts'])
+ __builtins__, parts=node['parts'])
except InheritanceException as err:
return [node.document.reporter.warning(err.args[0],
line=self.lineno)]
@@ -301,8 +94,8 @@ class InheritanceDiagram(Directive):
# references to real URLs later. These nodes will eventually be
# removed from the doctree after we're done with them.
for name in graph.get_all_class_names():
- refnodes, x = class_role(
- 'class', ':class:`%s`' % name, name, 0, self.state)
+ refnodes, x = class_role('class', f':class:`{name}`', name,
+ 0, self.state)
node.extend(refnodes)
# Store the graph object so we can use it to generate the
# dot file later
@@ -323,15 +116,15 @@ def html_visit_inheritance_diagram(self, node):
graph = node['graph']
graph_hash = get_graph_hash(node)
- name = 'inheritance%s' % graph_hash
+ name = f'inheritance{graph_hash}'
# Create a mapping from fully-qualified class names to URLs.
urls = {}
for child in node:
- if child.get('refuri') is not None:
- urls[child['reftitle']] = child.get('refuri')
- elif child.get('refid') is not None:
- urls[child['reftitle']] = '#' + child.get('refid')
+ ref_title = child.get('reftitle')
+ uri = child.get('refuri')
+ if uri and ref_title:
+ urls[ref_title] = uri
dotcode = graph.generate_dot(name, urls, env=self.builder.env)
render_dot_html(self, node, dotcode, {}, 'inheritance', 'inheritance',
@@ -346,7 +139,7 @@ def latex_visit_inheritance_diagram(self, node):
graph = node['graph']
graph_hash = get_graph_hash(node)
- name = 'inheritance%s' % graph_hash
+ name = f'inheritance{graph_hash}'
dotcode = graph.generate_dot(name, env=self.builder.env,
graph_attrs={'size': '"6.0,6.0"'})