pyTooling.Sphinx
Summary
- Doc-string:
documented
File |
Expected |
Covered |
Uncovered |
Coverage |
|---|---|---|---|---|
__init__.py |
73 |
73 |
0 |
100.0% |
Overall (25 files) |
1008 |
1004 |
4 |
99.6% |
Packages
Package |
Expected |
Covered |
Uncovered |
Coverage |
|---|---|---|---|---|
1 |
1 |
0 |
100.0% |
Modules
Module |
Expected |
Covered |
Uncovered |
Coverage |
|---|---|---|---|---|
41 |
41 |
0 |
100.0% |
|
70 |
70 |
0 |
100.0% |
|
22 |
22 |
0 |
100.0% |
|
28 |
27 |
1 |
96.4% |
|
28 |
28 |
0 |
100.0% |
|
129 |
127 |
2 |
98.4% |
|
76 |
76 |
0 |
100.0% |
|
61 |
61 |
0 |
100.0% |
|
30 |
30 |
0 |
100.0% |
|
56 |
56 |
0 |
100.0% |
|
24 |
24 |
0 |
100.0% |
|
44 |
44 |
0 |
100.0% |
|
27 |
27 |
0 |
100.0% |
|
47 |
47 |
0 |
100.0% |
|
7 |
7 |
0 |
100.0% |
|
13 |
13 |
0 |
100.0% |
|
32 |
32 |
0 |
100.0% |
|
31 |
31 |
0 |
100.0% |
|
48 |
48 |
0 |
100.0% |
|
90 |
89 |
1 |
98.9% |
|
17 |
17 |
0 |
100.0% |
|
6 |
6 |
0 |
100.0% |
|
7 |
7 |
0 |
100.0% |
Source
pyTooling.Sphinx/__init__.pydocumentedundocumentedignoredexcludednot counted
31"""
32A Sphinx extension providing the roles, nodes and directives shared by pyTooling and its sibling projects.
33
34Every project in the family used to carry its own :file:`doc/prolog.inc` - eighteen hand-copied files, 36 to 67
35lines each, already drifted apart - declaring the same roles as **ReST source** that is re-parsed into every
36document of every project. This extension declares them once:
37
38.. code-block:: Python
39
40 # doc/conf.py
41 extensions = [
42 ...,
43 "pyTooling.Sphinx",
44 ]
45
46.. rubric:: What it registers
47
48* the **style roles**, together with the stylesheet they need - so the styling is a CSS file instead of a
49 ``raw:: html`` block smuggled into every page - and the LaTeX package :file:`pyTooling.Sphinx.sty`, which strikes
50 through and underlines in LaTeX:
51
52 * ``:bolditalic:``, ``:underline:``, ``:strike:`` and ``:xlarge:`` - weight, decoration and size;
53 * ``:red:``, ``:green:``, ``:blue:`` and ``:purple:`` - colour, each from a CSS custom property a project can
54 redefine;
55 * ``:deletion:`` and ``:addition:`` - the two a diff needs.
56
57* the **code role**:
58
59 * ``:pycode:`` - highlights inline Python.
60
61* the **abbreviation roles**, named as in LaTeX' ``acro`` package:
62
63 * ``:acs:``, ``:acl:`` and ``:acf:`` - an abbreviation, its long form, or both;
64 * ``:acsp:``, ``:aclp:`` and ``:acfp:`` - their plurals.
65
66* the **directives**:
67
68 * :rst:dir:`condensed-class` - renders a class' public interface from its source;
69 * :rst:dir:`dependency-table` - renders a project's dependencies from its requirements files, which
70 :file:`conf.py` declares under ``pyTooling_Dependency_Requirements``;
71 * :rst:dir:`xmlschema-graph` - draws an XML schema as a Graphviz graph. It sets up :mod:`sphinx.ext.graphviz`
72 itself, and needs :mod:`xmlschema` only in a project that uses it.
73 * :rst:dir:`shields` - renders a project's badges from shields.io, in rows, from the coordinates its options
74 state: the GitHub repository, the PyPI package, the licenses, the workflow and the documentation's URL.
75 * :rst:dir:`tree` - draws a hierarchy written as an indented list as a tree, each node foldable in HTML.
76 * :rst:dir:`unicode-table` - lists icons with their Unicode names and code points, which HTML copies into the
77 clipboard on a click; the script doing so is linked like the stylesheet.
78 * :rst:dir:`abbreviations` - lists abbreviations, which the abbreviation roles refer to.
79
80* the domain ``report`` - unit test, code coverage and documentation coverage reports as tables -, with the
81 configuration values ``pyTooling_Unittest_Testsuites``, ``pyTooling_CodeCoverage_Packages`` and
82 ``pyTooling_DocCoverage_Packages`` declaring the reports. Reading a report needs the extra ``reports``
83 (pyEDAA.Reports), which is imported only then:
84
85 * :rst:dir:`report:unittest-summary` - a unit test report, per testsuite and testcase; a report declared with
86 ``pages`` gets a page per testsuite and testcase (:mod:`~pyTooling.Sphinx.UnittestPages`), which the roles
87 ``:ts:`` and ``:tc:`` - also ``:report:ts:`` and ``:report:tc:`` - refer to;
88 * :rst:dir:`report:code-coverage` and :rst:dir:`report:code-coverage-legend` - a code coverage report and its
89 coverage levels;
90 * :rst:dir:`report:doc-coverage` and :rst:dir:`report:doc-coverage-legend` - a package's documentation coverage
91 and its coverage levels; a package declared with ``pages`` gets a page per package and module
92 (:class:`~pyTooling.Sphinx.DocCoverage.DocCoverageReportPages`), which the role ``:doccov:`` refers to.
93
94* the **nodes** the directives emit, listed in :data:`NODES` with their visitors per output format.
95
96* the **external link icons** - in HTML, an icon behind each external link, chosen by its target, and the size behind
97 each download -, with the configuration values ``pyTooling_ExternalLink_Icons``, ``pyTooling_ExternalLink_NewTab``,
98 ``pyTooling_ExternalLink_Hosts``, ``pyTooling_ExternalLink_DownloadSizes``, ``pyTooling_ExternalLink_RemoteSizes``
99 and ``pyTooling_ExternalLink_RemoteSizeTimeout`` (:mod:`~pyTooling.Sphinx.ExternalLink`).
100
101Two classes aren't registered, because they are base-classes for a project's own directives:
102:class:`~pyTooling.Sphinx.BaseDirective` offers typed option access and table construction
103over the untyped mapping and the hand-assembled node trees docutils presents, and
104:class:`~pyTooling.Sphinx.SchemaGraph.SchemaGraph` draws a schema file named as a directive's
105argument, leaving only the reading of that schema to a derived class.
106
107.. attention::
108
109 This package requires **Python 3.12 or newer**, because it requires Sphinx 9.1 and Sphinx 9.1 does.
110
111.. seealso::
112
113 :mod:`pyTooling.Documentation`
114 |rarr| The doc-string helpers, which need no Sphinx.
115"""
116__author__ = "Patrick Lehmann"
117__email__ = "Paebbels@gmail.com"
118__copyright__ = "2026-2026, Patrick Lehmann"
119__license__ = "Apache License, Version 2.0"
120__version__ = "1.0.0"
121__keywords__ = ["Sphinx", "Sphinx Extension", "Documentation", "Directive", "Role", "Domain", "docutils"]
122__project_url__ = "https://github.com/pyTooling/pyTooling.Sphinx"
123__documentation_url__ = "https://pyTooling.github.io/pyTooling.Sphinx"
124__issue_tracker_url__ = "https://GitHub.com/pyTooling/pyTooling.Sphinx/issues"
125
...
169
171__all__ = [
172 "STYLESHEET", "SCRIPT", "LATEX_PACKAGE", "SUBSTITUTIONS", "NODES", "LINE_ANCHOR", "REPORT_ROLES"
173]
174
175STYLESHEET = "pyTooling.css"
176"""Name of the stylesheet, in :mod:`pyTooling.Sphinx.Resources`."""
177
178SCRIPT = "pyTooling.js"
179"""
180Name of the script, in :mod:`pyTooling.Sphinx.Resources`: it gives the copy buttons of the ``unicode-table``
181directive their function.
182"""
183
184LATEX_PACKAGE = "pyTooling.Sphinx"
185"""
186Name of the LaTeX package, whose file :file:`pyTooling.Sphinx.sty` is in :mod:`pyTooling.Sphinx.Resources`: it
187defines the commands LaTeX writes for the style roles ``:strike:`` and ``:underline:``.
188"""
189
190SUBSTITUTIONS = """
191.. |degree| unicode:: U+00B0
192 :trim:
193
194.. |br| replace:: :br:`.`
195
196.. |hr| replace:: :hr:`.`
197"""
198"""
199Substitutions that have to stay substitutions, because ``|br|`` is written as one in every project.
200
201``|br|`` and ``|hr|`` delegate to the ``:br:`` and ``:hr:`` roles rather than writing HTML themselves, so they
202reach every output format instead of only HTML - see :func:`~pyTooling.Sphinx.Roles.breakRole`.
203"""
204
205NODES: tuple[RegisteredNode, ...] = (
206 {"name": "TreeItem", "node": TreeItem, "html": translateTreeItem},
207 {"name": "TreeLabel", "node": TreeLabel, "html": translateTreeLabel},
208 {"name": "TreeSeparator", "node": TreeSeparator, "html": translateTreeSeparator},
209 {"name": "TreeDescription", "node": TreeDescription, "html": translateTreeDescription},
210 {"name": "TreeLegend", "node": TreeLegend, "html": translateTreeLegend},
211 {"name": "TreeLegendItem", "node": TreeLegendItem, "html": translateTreeLegendItem},
212 {"name": "CopyButton", "node": CopyButton, "html": translateCopyButton},
213 {"name": "Abbreviation", "node": Abbreviation, "html": translateAbbreviation},
214 {"name": "Landscape", "node": Landscape, "html": translateLandscapeAsHTML,
215 "latex": translateLandscapeAsLaTeX},
216 {"name": "CoverageListing", "node": CoverageListing, "html": translateCoverageListingAsHTML,
217 "latex": translateCoverageListingAsLaTeX},
218 {"name": "DocCoverageListing", "node": DocCoverageListing, "html": translateDocCoverageListingAsHTML,
219 "latex": translateDocCoverageListingAsLaTeX},
220 {"name": "Emoji", "node": Emoji, "html": translateEmoji},
221 {"name": "TaskListCheckbox", "node": TaskListCheckbox, "html": translateTaskListCheckboxAsHTML,
222 "latex": translateTaskListCheckboxAsLaTeX},
223 {"name": "LineBreak", "node": LineBreak, "html": translateLineBreakAsHTML,
224 "latex": translateLineBreakAsLaTeX},
225 {"name": "ReportIndentation", "node": ReportIndentation, "html": translateReportIndentationAsHTML,
226 "latex": translateReportIndentationAsLaTeX},
227 {"name": "FoldedDependencies", "node": FoldedDependencies, "html": translateFoldedDependencies},
228 {"name": "FoldedSummary", "node": FoldedSummary, "html": translateFoldedSummary},
229)
230"""
231The nodes the extension registers, each with its visitors per output format.
232
233A format without visitors of its own - e.g. LaTeX for the tree's nodes - writes a node with the visitors of its
234base-class.
235"""
236
238@export
239class SphinxExtensionError(ExtensionError, DocumentationError):
240 """
241 Base-exception of all exceptions raised by :mod:`pyTooling.Sphinx`.
242
243 It derives from **both** hierarchies on purpose: :exc:`~sphinx.errors.ExtensionError` is what Sphinx catches and
244 reports with the position of the directive, and :exc:`~pyTooling.Documentation.DocumentationError` is what a
245 caller of pyTooling catches. Neither would be enough alone.
246 """
247
249@export
250class ReportExtensionError(SphinxExtensionError):
251 """
252 The exception raised by the ``report`` domain.
253
254 It is raised e.g. for a mistake in the domain's configuration values or options.
255 """
256
258@export
259class ReportsPackageMissingError(ReportExtensionError):
260 """
261 The exception raised when a report is read, but the optional packages of the extra ``reports`` aren't installed.
262
263 The message names what was attempted and the packages it needs; a note says how to install them.
264 """
265
266 def __init__(self, task: str, packages: str = "'pyEDAA.Reports'") -> None:
267 """
268 Initialize the exception with what was attempted and the packages it needs.
269
270 :param task: What needs the packages, e.g. ``Reading a unit test report``.
271 :param packages: Optional, the packages needed, quoted. Default: ``'pyEDAA.Reports'``.
272 """
...
275
277@export
278class LegendStyle(StringEnum):
279 """
280 How a legend directive of domain ``report`` lays out the coverage levels, as its option ``:style:`` states it.
281 """
282
283 HorizontalTable = "horizontal-table" #: A table with a column per level.
284 VerticalTable = "vertical-table" #: A table with a row per level.
285
286 DEFAULT = HorizontalTable #: Without the option, a legend has a column per level.
287
289@export
290def strip(option: str) -> str:
291 """
292 Option converter removing surrounding whitespace.
293
294 :param option: The option's value as it was written.
295 :returns: The value without surrounding whitespace.
296 """
...
298
300@export
301def stripAndNormalize(option: str) -> str:
302 """
303 Option converter removing surrounding whitespace and lowering the case.
304
305 :param option: The option's value as it was written.
306 :returns: The value without surrounding whitespace, in lower case.
307 """
...
309
311@export
312class BaseDirective(ObjectDescription[str]):
313 """
314 Base-class for a directive, offering typed option access and table construction.
315
316 A derived class sets :attr:`directiveName` - which is what the error messages name - and declares
317 ``option_spec`` as any directive does. What it gets in return is a ``_Parse***Option`` per type instead of
318 reaching into :attr:`options` and validating by hand, and a ``_Create***TableHeader`` per table shape instead of
319 assembling :class:`~docutils.nodes.tgroup`, :class:`~docutils.nodes.colspec`, :class:`~docutils.nodes.thead`
320 and :class:`~docutils.nodes.row` in the right order.
321 """
322
323 has_content = False #: A boolean; ``True`` if content is allowed.
324 required_arguments = 0 #: Number of required directive arguments.
325 optional_arguments = 0 #: Number of optional arguments after the required ones.
326 final_argument_whitespace = False #: A boolean; ``True`` if the last argument may contain spaces.
327 option_spec = {} #: Mapping of option names to validator functions.
328
329 directiveName: str #: Name the directive is invoked by, used in every error message.
330
331 def _ParseBooleanOption(self, optionName: str, default: Nullable[bool] = None) -> bool:
332 """
333 Read an option written as ``yes``/``true`` or ``no``/``false``.
334
335 :param optionName: Name of the option to read.
336 :param default: Optional, the value to return when the option wasn't given.
337 :returns: The option's value.
338 :raises SphinxExtensionError: If the option wasn't given and has no default.
339 :raises SphinxExtensionError: If the option's value is neither of the two accepted spellings.
340 """
...
359
360 def _ParseStringOption(self, optionName: str, default: Nullable[str] = None, regexp: str = "\\w+") -> str:
361 """
362 Read an option that has to match a regular expression.
363
364 The pattern defaults to one or more word characters.
365
366 :param optionName: Name of the option to read.
367 :param default: Optional, the value to return when the option wasn't given.
368 :param regexp: Optional, the pattern the value has to match.
369 :returns: The option's value.
370 :raises SphinxExtensionError: If the option wasn't given and has no default.
371 :raises SphinxExtensionError: If the option's value doesn't match the pattern.
372 """
...
389
390 def _CreateSingleRowTableHeader(
391 self,
392 columns: list[tuple[str, Nullable[int]]],
393 identifier: str,
394 classes: list[str]
395 ) -> nodes.tgroup:
396 """
397 Create a table with a single header row.
398
399 :param columns: One ``(title, width)`` pair per column; a width of ``None`` leaves it to the writer.
400 :param identifier: Identifier of the table.
401 :param classes: CSS classes to put on the table.
402 :returns: The table's column group, with the header row already in it.
403 """
...
419
420 def _CreateDoubleRowTableHeader(
421 self,
422 columns: list[tuple[str, Nullable[list[tuple[str, int]]], Nullable[int]]],
423 identifier: str,
424 classes: list[str]
425 ) -> nodes.tgroup:
426 """
427 Create a table whose header spans two rows, so a column can group sub-columns.
428
429 A column's ``subColumns`` is ``None`` when it spans both header rows, and otherwise holds the
430 ``(title, width)`` pairs below it.
431
432 :param columns: One ``(title, subColumns, width)`` triple per column.
433 :param identifier: Identifier of the table.
434 :param classes: CSS classes to put on the table.
435 :returns: The table's column group, with both header rows already in it.
436 """
...
473
474 def _CreateRotatedTableHeader(
475 self,
476 columns: list[tuple[str, Nullable[list[str]]]],
477 identifier: str,
478 classes: list[str]
479 ) -> nodes.tgroup:
480 """
481 Create a table whose header titles are rotated, for many narrow columns.
482
483 :param columns: One ``(title, classes)`` pair per column; the classes are put on the header cell.
484 :param identifier: Identifier of the table.
485 :param classes: CSS classes to put on the table.
486 :returns: The table's column group, with the header row already in it.
487 """
...
505
506 def _internalError(
507 self,
508 container: nodes.container,
509 location: str,
510 message: str,
511 exception: Exception
512 ) -> list[nodes.Node]:
513 """
514 Report an exception a directive couldn't recover from, in the log **and** on the page.
515
516 A directive that fails silently leaves a hole in the documentation that nobody notices. This puts the message
517 where a reader sees it and the traceback where a maintainer does. The exception's notes - e.g. how to install a
518 missing package - are logged below it.
519
520 :param container: The container the message is put into.
521 :param location: Name of the logger, which is what the log line is attributed to.
522 :param message: What went wrong, in one sentence.
523 :param exception: The exception that was caught.
524 :returns: The container, as the list a directive's ``run`` returns.
525 """
...
539
541@export
542def installStaticFiles(sphinx: Sphinx) -> None:
543 """
544 Call-back for Sphinx' ``builder-inited`` event, writing the stylesheet and the script into the build and linking
545 them.
546
547 A file is named by the hash of its content, so a browser re-reads it when it changes and re-uses it when it doesn't.
548 Older copies are removed when the content changed.
549
550 :param sphinx: The Sphinx application.
551 """
...
570
572@export
573def installLaTeXPackage(sphinx: Sphinx) -> None:
574 """
575 Call-back for Sphinx' ``builder-inited`` event, writing the LaTeX package :data:`LATEX_PACKAGE` into the build of a
576 LaTeX builder, where the document's ``\\usepackage`` finds it.
577
578 :param sphinx: The Sphinx application.
579 """
...
586
588@export
589def extendProlog(sphinx: Sphinx, config: Any) -> None:
590 """
591 Call-back for Sphinx' ``config-inited`` event, appending the shared substitutions to ``rst_prolog``.
592
593 A role can be registered; a **substitution** cannot - ``|br|`` is substitution syntax, and every project writes
594 it that way already. Appending them here is what lets a project delete them from its own prolog without changing
595 a single document.
596
597 :param sphinx: The Sphinx application.
598 :param config: The configuration, after :file:`conf.py` was read.
599 """
...
601
603@export
604def setLaTeXDefaults(sphinx: Sphinx, config: Config) -> None:
605 """
606 Call-back for Sphinx' ``config-inited`` event, setting LaTeX defaults, unless :file:`conf.py` sets them.
607
608 * ``latex_table_style``: ``["booktabs"]``, without Sphinx' default ``colorrows``.
609 * ``latex_elements["maxlistdepth"]``: ``"10"`` nested lists, e.g. a :rst:dir:`tree` with more than 4 levels.
610
611 :param sphinx: The Sphinx application.
612 :param config: The configuration, after :file:`conf.py` was read.
613 """
...
618
620@export
621class ReportEntry(NamedTuple):
622 """
623 An object of a report shown by a generated page - a testcase, a source file, ...: where it is, and its names.
624
625 An object is shown by a page of its own, or - with an anchor - by a part of another page.
626 """
627
628 docName: str #: Name of the generated document showing the object.
629 reportID: str #: Identifier of the report in its configuration value.
630 path: tuple[str, ...] #: Names of the objects from the report's root down to this object's own name.
631 separator: str #: Separator of the names in a qualified name, e.g. ``.`` or ``/``.
632 title: Nullable[str] #: Title of the object written for a reader, if the report has one.
633 anchor: Nullable[str] = None #: Anchor of the object's part of the page, or ``None`` for the whole page.
634
635 @readonly
636 def Name(self) -> str:
637 """
638 Read-only property to return the object's own name, the last element of :attr:`path`.
639
640 :returns: The name.
641 """
...
643
644 @readonly
645 def QualifiedName(self) -> str:
646 """
647 Read-only property to return the qualified name: the names of :attr:`path` joined by :attr:`separator`.
648
649 :returns: The qualified name, e.g. ``pytest.tests.unit.Arithmetic.Addition.test_Positive``.
650 """
...
652
653 def Matches(self, name: str) -> bool:
654 """
655 Check whether a name is the qualified name or a suffix of it, which starts at an element of :attr:`path`.
656
657 :param name: The name as written in a reference, without a report ID.
658 :returns: ``True`` if the name is the qualified name or one of its suffixes.
659 """
...
661
663@export
664class ReportRoleDefinition(NamedTuple):
665 """
666 What a role of domain ``report`` refers to: a kind of object of the reports declared in a configuration value.
667 """
668
669 objectType: str #: The object type, as listed by the domain, e.g. ``testcase``.
670 configValue: str #: The configuration value declaring the reports; its first report is the default one.
671 reports: str #: The reports, as a warning names them, e.g. ``unit test reports``.
672 lineAnchors: bool = False #: Whether a target may end in ``#<line number>``, linking to the line on the page.
673
675LINE_ANCHOR = re_compile(r"#(\d+)$")
676"""The line number a target of a role with line anchors may end in, e.g. ``#12`` of ``src/Counter.vhdl#12``."""
677
678REPORT_ROLES = {
679 "tc": ReportRoleDefinition("testcase", "pyTooling_Unittest_Testsuites", "unit test reports"),
680 "ts": ReportRoleDefinition("testsuite", "pyTooling_Unittest_Testsuites", "unit test reports"),
681 "cov": ReportRoleDefinition("source", "pyTooling_CodeCoverage_Packages", "code coverage reports", True),
682 "doccov": ReportRoleDefinition("module", "pyTooling_DocCoverage_Packages", "documentation coverage reports"),
683}
684"""The roles referring to the objects of reports with pages, by role name."""
685
687@export
688class ReportRole(XRefRole):
689 """
690 A role of domain ``report`` referring to an object of a report with pages.
691
692 Role ``tc`` refers to a testcase, ``ts`` to a testsuite.
693
694 Sphinx registers a role outside a domain without one, so the reference would be resolved by nobody; this role puts
695 its domain - ``report``, or the one of a domain derived from :class:`ReportDomain` - on the reference, and uses its
696 name as the reference's type. So it works as ``:report:tc:`` and as the global ``:tc:``.
697 """
698
699 _domain: str #: Name of the domain resolving the role's references.
700
701 def __init__(self, *, domain: str = "report", **kwargs: Any) -> None:
702 """
703 Initializes a role of domain ``report``, or of a domain derived from :class:`ReportDomain`.
704
705 :param domain: Optional, name of the domain resolving the role's references. Default: ``"report"``.
706 :param kwargs: The parameters of :class:`~sphinx.roles.XRefRole`, e.g. ``innernodeclass``.
707 :raises ValueError: If parameter 'domain' is None.
708 :raises TypeError: If parameter 'domain' is not of type :class:`str`.
709 """
...
720
721 def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
722 """
723 Create the reference, or only the text if the role is written with ``!``.
724
725 :returns: The nodes and messages a role returns.
726 """
...
735
737@export
738class ReportDomain(Domain):
739 """
740 The Sphinx domain ``report``, integrating unit test, code coverage and documentation coverage reports.
741
742 Its directives are registered by :func:`setup`, and read their reports from the files declared in :file:`conf.py`.
743
744 A report with generated pages contributes an object per page - e.g. a unit test report its testsuites and
745 testcases -, which the roles of :data:`REPORT_ROLES` refer to, e.g. ``:report:tc:``, also registered as ``:tc:``. A
746 reference names an object by its qualified name, or by a suffix of it, optionally preceded by the report's
747 identifier and a colon; without one, the first report of the role's configuration value is meant.
748
749 A domain of another family of reports - e.g. a build summary of a simulation framework - derives from it: it names
750 its roles in :attr:`_ROLES`, and declares :attr:`name`, :attr:`object_types`, :attr:`initial_data`, :attr:`roles` and
751 :attr:`dangling_warnings` from them, as this domain does from :data:`REPORT_ROLES`. Its roles are
752 :class:`ReportRole` instances naming the domain.
753 """
754
755 _ROLES: ClassVar[dict[str, ReportRoleDefinition]] = REPORT_ROLES #: The domain's roles, by role name.
756
757 name = "report" #: Name of the domain, the prefix of its directives.
758 label = "rpt" #: Name of the domain, as displayed.
759 data_version = 2 #: Version of the domain data's layout; a pickled environment of another version is dropped.
760
761 object_types = {
762 definition.objectType: ObjType(definition.objectType, roleName) for roleName, definition in REPORT_ROLES.items()
763 } #: The objects: per role, the objects of the reports with generated pages.
764 initial_data: dict[str, Any] = {
765 roleName: {} for roleName in REPORT_ROLES
766 } #: The data of an empty documentation: per role, no object.
767 roles = {
768 roleName: ReportRole(innernodeclass=nodes.inline, warn_dangling=True) for roleName in REPORT_ROLES
769 } #: The roles, also registered without the domain's prefix.
770 dangling_warnings = {
771 roleName: f"{definition.objectType} '%(target)s' not found in the {definition.reports}"
772 for roleName, definition in REPORT_ROLES.items()
773 } #: The warning for a reference to an unknown object, per role.
774
775 def AddEntry(self, roleName: str, entry: ReportEntry) -> None:
776 """
777 Register an object, which has a generated page.
778
779 :param roleName: The role referring to the object, e.g. ``tc`` for a testcase.
780 :param entry: The object.
781 """
...
783
784 def FindEntries(self, roleName: str, target: str) -> list[ReportEntry]:
785 """
786 Find the objects a reference's target names.
787
788 A target is ``[<report ID>:]<name>``. If the part before the first colon isn't the identifier of a report, the
789 whole target is the name in the default report - the first one of the role's configuration value -, as e.g. a
790 parametrized testcase's name may contain a colon. A name is a qualified name or a suffix of one (see
791 :meth:`ReportEntry.Matches`); an exact qualified name wins over suffixes.
792
793 :param roleName: The role referring to the object, e.g. ``tc`` for a testcase.
794 :param target: The reference's target.
795 :returns: The matching entries: none, one, or several if the name is ambiguous.
796 """
...
812
813 def clear_doc(self, docname: str) -> None:
814 """
815 Forget the objects of a document, before it is generated again.
816
817 :param docname: Name of the document.
818 """
...
823
824 def merge_domaindata(self, docnames: Iterable[str], otherdata: dict[str, Any]) -> None:
825 """
826 Take over the objects a parallel reader collected for its documents.
827
828 :param docnames: Names of the documents the other reader read.
829 :param otherdata: The other reader's domain data.
830 """
...
838
839 def resolve_xref(
840 self,
841 env: BuildEnvironment,
842 fromdocname: str,
843 builder: Builder,
844 typ: str,
845 target: str,
846 node: pending_xref,
847 contnode: nodes.Element
848 ) -> Nullable[nodes.Element]:
849 """
850 Resolve a reference to an object of a report into a link to its page.
851
852 The link shows the object's name, or the title written in the role; in HTML, its title written for a reader - if
853 the report has one - is shown on hover. It points to the object's anchor, if it has one, and to a line, if the
854 target ends in one. An ambiguous name is warned about and shown as text.
855
856 :param env: The build environment.
857 :param fromdocname: Name of the document holding the reference.
858 :param builder: The builder writing the documents.
859 :param typ: The role's name, e.g. ``tc``.
860 :param target: The object referred to.
861 :param node: The reference.
862 :param contnode: The reference's text.
863 :returns: The link, the text if the name is ambiguous or the builder doesn't write the page, or
864 ``None`` if nothing matches.
865 """
...
897
898 def resolve_any_xref(
899 self,
900 env: BuildEnvironment,
901 fromdocname: str,
902 builder: Builder,
903 target: str,
904 node: pending_xref,
905 contnode: nodes.Element
906 ) -> list[tuple[str, nodes.reference]]:
907 """
908 Resolve a reference of role ``:any:`` to an object of a report with an unambiguous name.
909
910 :param env: The build environment.
911 :param fromdocname: Name of the document holding the reference.
912 :param builder: The builder writing the documents.
913 :param target: The text referred to.
914 :param node: The reference.
915 :param contnode: The reference's text.
916 :returns: A role and link per kind of object the text names unambiguously.
917 """
...
927
928 def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
929 """
930 Name the objects of the reports, for the search and for other documentations referring to them.
931
932 An object's name is ``<report ID>:<qualified name>``. A testcase gets a lower search priority than a testsuite,
933 as a report may have thousands of them.
934
935 :returns: A tuple per object: name, display name, type, document, anchor and search priority.
936 """
...
945
947@export
948def checkReportConfiguration(sphinx: Sphinx, config: Config) -> None:
949 """
950 Call-back for Sphinx' ``config-inited`` event, checking the reports' configuration values and loading their settings.
951
952 A mistake is logged as an error rather than stopping the build; a directive naming that report fails on its own.
953
954 :param sphinx: The Sphinx application.
955 :param config: The configuration, after :file:`conf.py` was read.
956 """
...
972
974@export
975def readReports(sphinx: Sphinx) -> None:
976 """
977 Call-back for Sphinx' ``builder-inited`` event, reading the report files, analyzing the documented packages, and
978 registering the reports' pages.
979
980 :param sphinx: The Sphinx application.
981 """
...
994
996@export
997def setup(sphinx: Sphinx) -> dict[str, Any]:
998 """
999 Register the roles, the nodes, the directives and the domain ``report`` with Sphinx.
1000
1001 The modules are imported here rather than with the package, and none of them imports an optional dependency at
1002 module level - e.g. pyEDAA.Reports is imported only when a report is read - so the extension works without them.
1003
1004 :param sphinx: The Sphinx application to register with.
1005 :returns: The extension's metadata.
1006 """
...