.. _DIR/DocCoverage: report:doc-coverage ################### .. grid:: 2 .. grid-item:: :columns: 6 The ``report:doc-coverage`` directive renders the documentation coverage of a Python package as a table: a row per package and module, with the number of items expected to be documented - e.g. classes, functions and fields -, the documented and the undocumented ones. The package hierarchy is shown by indentation and 📦, a module by ⚙️, and each row is coloured by its coverage level. ``report:doc-coverage-legend`` renders the coverage levels. There is no report file: the package's source directory is :ref:`analyzed ` by the Python reader of :gh:`pyEDAA.Reports ` once per build. Packages are declared in :file:`conf.py`, each with an identifier the directives name in their :rst:dir:`report:doc-coverage:reportid` option. A package can get a :ref:`page per package and module `: a module's page shows its source condensed to signatures, doc-strings, fields and variables, each marked by its documentation state. The table links to the pages, and the role :rst:role:`doccov` refers to them. The directives are part of :mod:`pyTooling.Sphinx`; they need the :ref:`extra reports `. .. grid-item:: :columns: 6 .. code-block:: ReST .. grid:: 2 .. grid-item:: :columns: 8 .. report:doc-coverage:: :reportid: example .. grid-item:: :columns: 4 .. report:doc-coverage-legend:: :reportid: example :style: vertical-table This is how the example renders, for a package with one sub-package. The package is declared with :ref:`pages `, so every package and module links to its page: .. grid:: 2 .. grid-item:: :columns: 8 .. report:doc-coverage:: :reportid: example .. grid-item:: :columns: 4 .. report:doc-coverage-legend:: :reportid: example :style: vertical-table The documentation's own :doc:`documentation coverage report <../doccoverage/index>` is rendered by these directives too. .. _DIR/DocCoverage/Configuration: Configuration ************* The packages are declared in :file:`conf.py` as a dictionary, keyed by the identifier a directive names in :rst:dir:`report:doc-coverage:reportid`. A path is relative to the documentation's source directory. ``pyTooling_DocCoverage_Packages`` |rarr| The analyzed packages, by identifier. An entry has these fields: ``name`` |rarr| The name of the Python package, shown in the first row. ``directory`` |rarr| The package's source directory. ``pages`` |rarr| The document name the :ref:`pages per package and module ` are generated below, e.g. ``doccoverage/src``. Optional; without it, the package gets no pages. ``fail_below`` |rarr| An integer in range 0..100: the coverage in percent below which the package fails. ``levels`` |rarr| The name of a palette in ``pyTooling_DocCoverage_Levels``, e.g. ``"default"``, or a palette of its own, written as there. ``pyTooling_DocCoverage_Levels`` |rarr| The palettes of coverage levels, by name. A palette maps an upper limit in percent to a CSS class and a description, and needs a level ``100`` and a level ``"error"``. Default: the palette ``default``, of 12 levels from ≤10 % to ≤100 %, coloured from blue via red, orange and yellow to green. .. code-block:: Python # doc/conf.py pyTooling_DocCoverage_Packages = { "src": { "name": "myPackage", "directory": "../myPackage", "pages": "doccoverage/src", "fail_below": 80, "levels": "default" } } The first entry is the default package of the role :rst:role:`doccov`. The configuration is checked when the build starts. A directory that doesn't exist is logged as an error, and the entries after it aren't read. The packages are analyzed once per build, before any document is read. .. _DIR/DocCoverage/Analysis: Analysis ******** A package is read from its source files - every :file:`*.py` file below its directory, each in its declared encoding - into the language-neutral documentation coverage model of :gh:`pyEDAA.Reports `, by its `Python reader `__. Every documentable item is counted - also fields, variables, and items of a protected (``_x``) or private (``__x``) name. The reader's default selection (``CountedItems.Default``) isn't configurable yet. * Packages, modules, classes, functions, methods and properties are documented by a non-empty doc-string. A comment of docstr_coverage directly above a declaration - ``# docstr-coverage: inherited`` or ``# docstr-coverage: excused `reason``` - excuses a missing doc-string. * A class' fields and a module's variables are documented where Sphinx' autodoc finds their documentation: a ``#:`` comment behind the statement or in the lines above it, or a doc-string literal following it. * A field or variable assigned in an ``if`` or ``try`` statement of a class or module is counted too, e.g. in ``if TYPE_CHECKING:``. * Ignored - not expected to be documented - are, e.g., a property's setter, an ``@overload`` stub, and a name like ``__all__``. * A package without :file:`__init__.py` - a namespace package - has nothing to document. A row of the table counts the items declared in its file: a module's, or a package's :file:`__init__.py`. The summary row counts all items of the package. A source file, which can't be read or parsed, is logged as a warning; its module is excluded from the analysis, and the analysis continues. Its row - in the table and on the pages - has the coverage level ``error`` and says *can't be read*. .. _DIR/DocCoverage/Pages: Pages per package and module **************************** A package declared with the key ``pages`` gets a page per package and per module. They are generated when the documentation is built - no source file is written - below the document name the key states, named by the package's and module's names, e.g. ``doccoverage/src/myPackage/Units/Length``. A **package's page** shows its parent package, the state of its ``__init__.py``'s doc-string, and its counters: those of its ``__init__.py``, and overall - with all its packages and modules -, each colored by its coverage level. Then a table of its packages and a table of its modules, each linked to its page and colored by its coverage level; a package's row counts it with all its packages and modules. Last, the **condensed listing** of its ``__init__.py``. A namespace package - without ``__init__.py`` - shows only its overall counters and has no listing. A **module's page** shows its parent package, the state of its doc-string, its counters, and its condensed listing. The condensed listing shows a module's source as far as documentation coverage is about it: the code of a function is of no interest, its signature and its doc-string are. The source is syntax highlighted with Pygments, in the colors of Sphinx' Pygments style, as every code block. A line is shown as written, with its line number, or elided: * The module's doc-string is shown. Imports and other statements are elided. * A class or function is shown with its decorators, its header - a signature spanning several lines too - and its doc-string. Its body follows: a class' fields and methods, a function's nested functions and classes. Anything else is elided. * A module's variables and a class' fields are shown with their ``#:`` comments - behind them or in the lines above - and a doc-string literal following them. * A statement holding classes or functions - e.g. an ``if`` choosing between two definitions -, and an ``if`` or ``try`` assigning a variable or field, is shown with the headers of its clauses - ``if ...:``, ``else:``, ``except ...:`` -; each clause's block is shown like a body. * A definition written in one line - ``def f(): pass`` - is shown as written. * Comments between statements are left out; consecutive blank lines become one. Consecutive elided statements become a single ``...`` line without a line number, at the statements' indentation, so a function's body becomes ``...``. Each line of a class or function - its decorators, header and doc-string - and of a field or variable is marked by the documentation state of its item in the :ref:`analysis `: .. list-table:: :header-rows: 1 :widths: 20 80 * - State - Line * - ``documented`` - The item is documented: a class or function by a doc-string - or an excuse comment, e.g. ``# docstr-coverage: inherited`` -, a field or variable by a ``#:`` comment or a doc-string literal. * - ``undocumented`` - The item has no documentation. * - ``ignored`` - The item isn't expected to be documented, e.g. a property's setter or ``__all__``. * - ``excluded`` - The item is excluded from the analysis. * - (none) - The line isn't counted: a blank line, a clause's header, a repeated assignment of a variable. The module's doc-string is marked by the module's state, which the page's summary states too. A header above the listing shows the module's path and a legend of these states. The :rst:dir:`report:doc-coverage` directive lists the package's page in a hidden table of contents, and a package's page lists its packages and modules, so the pages are in the navigation below the table's document. LaTeX writes the pages too, below the table's section; a listing's line numbers are colored by the documentation state, followed by a marker: ``+`` documented, ``-`` undocumented, ``o`` ignored, ``x`` excluded; a line above the listing shows the module's path and the markers' legend. Sphinx regards a module's file - a package's ``__init__.py`` - as the source of its page. .. hint:: A module is as many levels below the table's document as it is nested in packages. A theme limits how deep its navigation goes, e.g. the option ``navigation_depth`` of the *Read the Docs* theme (default 4; ``-1`` = unlimited). .. _DIR/DocCoverage/Role: Role **** .. rst:role:: doccov Refers to a package's or module's page, showing its name, or the role's title: ``:doccov:```` or ``:doccov:`title <>```. It is registered in domain ``report`` - as ``:report:doccov:`` - and without the domain's prefix. The target is ``[:]``, e.g. ``myPackage.Units.Length``. A suffix of it starting at a name - ``Units.Length`` or ``Length`` - is accepted, if it's unique. The configured name of the analyzed package is one name, also if it's dotted, e.g. ``pyTooling.Sphinx``. Without a report ID, the first package of ``pyTooling_DocCoverage_Packages`` is meant. A target matching nothing or several packages and modules is warned about. .. grid:: 2 .. grid-item:: :columns: 6 .. code-block:: ReST * :doccov:`example:Shapes` * :doccov:`example:myPackage.Units` * :doccov:`the length module ` .. grid-item:: :columns: 6 * :doccov:`example:Shapes` * :doccov:`example:myPackage.Units` * :doccov:`the length module ` The packages and modules are objects of domain ``report`` of type ``module``, named ``:`` in the documentation's inventory (:file:`objects.inv`), so another documentation refers to them with ``intersphinx``. .. _DIR/DocCoverage/Options: Options ******* .. rst:directive:: .. report:doc-coverage:: Renders the documentation coverage of a package as a table. .. rst:directive:option:: reportid: The package, as declared in ``pyTooling_DocCoverage_Packages``. Required. .. rst:directive:option:: class: Additional CSS classes on the table. .. rst:directive:: .. report:doc-coverage-legend:: Renders the coverage levels of a package as a table. .. rst:directive:option:: reportid: The package, as declared in ``pyTooling_DocCoverage_Packages``, whose palette is shown. Required. .. rst:directive:option:: style: horizontal-table | vertical-table A column per level, or a row per level. Default: ``horizontal-table``. .. rst:directive:option:: class: Additional CSS classes. Accepted, but not yet put on the table. .. _DIR/DocCoverage/Styling: Styling ******* The table carries the classes ``report-doccov-table`` and ``report-doccov-``, a legend ``report-doccov-legend``. A row carries its kind - ``report-package``, ``report-module`` or ``report-summary`` - and the CSS class of its coverage level, e.g. ``report-cov-below80``. The rules of the stylesheet and the indentation of the names are those of the :ref:`code coverage tables `. A page's tables carry ``report-doccov-table`` too, and ``report-doccov-summary`` or ``report-doccov-children``. A condensed listing is styled like a :ref:`code coverage listing `: a line carries ``report-line-documented``, ``report-line-undocumented``, ``report-line-ignored`` or ``report-line-excluded``, which share the colors of ``covered``, ``uncovered`` and ``excluded``; an elided ``...`` carries ``report-line-elided``.