Skip to content

Commit

Permalink
Add detailed documentation for Pyreverse options and fix __init__ (#…
Browse files Browse the repository at this point in the history
…10045)

* Add comprehensive documentation for Pyreverse command-line options

* Add configuration section to Pyreverse documentation

* Also make sure that `Run.__init__` doesn't return `NoReturn`

Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
  • Loading branch information
Julfried and DanielNoord authored Oct 31, 2024
1 parent da0d3fc commit 15a5ac0
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 95 deletions.
169 changes: 169 additions & 0 deletions doc/additional_tools/pyreverse/configuration.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
.. This file is auto-generated. Make any changes to the associated
.. docs extension in 'doc/exts/pyreverse_configuration.py'.
Pyreverse Configuration
^^^^^^^^^^^^^^^^^^^^^^^


Filtering and Scope
-------------------

--all-ancestors
"""""""""""""""
*Show all ancestors of all classes in <projects>.*

**Default:** ``None``


--all-associated
""""""""""""""""
*Show all classes associated with the target classes, including indirect associations.*

**Default:** ``None``


--class
"""""""
*Create a class diagram with all classes related to <class>; this uses by default the options -ASmy*

**Default:** ``None``


--filter-mode
"""""""""""""
*Filter attributes and functions according to <mode>. Correct modes are:
'PUB_ONLY' filter all non public attributes [DEFAULT], equivalent to PRIVATE+SPECIAL
'ALL' no filter
'SPECIAL' filter Python special functions except constructor
'OTHER' filter protected and private attributes*

**Default:** ``PUB_ONLY``


--show-ancestors
""""""""""""""""
*Show <ancestor> generations of ancestor classes not in <projects>.*

**Default:** ``None``


--show-associated
"""""""""""""""""
*Show <association_level> levels of associated classes not in <projects>.*

**Default:** ``None``


--show-builtin
""""""""""""""
*Include builtin objects in representation of classes.*

**Default:** ``False``


--show-stdlib
"""""""""""""
*Include standard library objects in representation of classes.*

**Default:** ``False``




Display Options
---------------

--color-palette
"""""""""""""""
*Comma separated list of colors to use for the package depth coloring.*

**Default:** ``('#77AADD', '#99DDFF', '#44BB99', '#BBCC33', '#AAAA00', '#EEDD88', '#EE8866', '#FFAABB', '#DDDDDD')``


--colorized
"""""""""""
*Use colored output. Classes/modules of the same package get the same color.*

**Default:** ``False``


--max-color-depth
"""""""""""""""""
*Use separate colors up to package depth of <depth>. Higher depths will reuse colors.*

**Default:** ``2``


--module-names
""""""""""""""
*Include module name in the representation of classes.*

**Default:** ``None``


--no-standalone
"""""""""""""""
*Only show nodes with connections.*

**Default:** ``False``


--only-classnames
"""""""""""""""""
*Don't show attributes and methods in the class boxes; this disables -f values.*

**Default:** ``False``




Output Control
--------------

--output
""""""""
*Create a *.<format> output file if format is available. Available formats are: .dot, .puml, .plantuml, .mmd, .html. Any other format will be tried to be created by using the 'dot' command line tool, which requires a graphviz installation. In this case, these additional formats are available (see `Graphviz output formats <https://graphviz.org/docs/outputs/>`_).*

**Default:** ``dot``


--output-directory
""""""""""""""""""
*Set the output directory path.*

**Default:** ``""``




Project Configuration
---------------------

--ignore
""""""""
*Files or directories to be skipped. They should be base names, not paths.*

**Default:** ``('CVS',)``


--project
"""""""""
*Set the project name. This will later be appended to the output file names.*

**Default:** ``""``


--source-roots
""""""""""""""
*Add paths to the list of the source roots. Supports globbing patterns. The source root is an absolute path or a path relative to the current working directory used to determine a package namespace for modules located under the source root.*

**Default:** ``()``


--verbose
"""""""""
*Makes pyreverse more verbose/talkative. Mostly useful for debugging.*

**Default:** ``False``
13 changes: 9 additions & 4 deletions doc/pyreverse.rst → doc/additional_tools/pyreverse/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ To see a full list of the available options, run::

pyreverse -h


Example Output
''''''''''''''

Expand All @@ -31,7 +30,7 @@ Example diagrams generated with the ``.puml`` output format are shown below.
Class Diagram
.............

.. image:: media/pyreverse_example_classes.png
.. image:: ../../media/pyreverse_example_classes.png
:width: 625
:height: 589
:alt: Class diagram generated by pyreverse
Expand All @@ -41,7 +40,7 @@ Class Diagram
Package Diagram
...............

.. image:: media/pyreverse_example_packages.png
.. image:: ../../media/pyreverse_example_packages.png
:width: 344
:height: 177
:alt: Package diagram generated by pyreverse
Expand All @@ -60,8 +59,14 @@ For example, running::

will generate the full class and package diagrams for ``pylint``, but will additionally generate a file ``pylint.checkers.classes.ClassChecker.dot``:

.. image:: media/ClassChecker_diagram.png
.. image:: ../../media/ClassChecker_diagram.png
:width: 757
:height: 1452
:alt: Package diagram generated by pyreverse
:align: center

.. toctree::
:maxdepth: 1
:hidden:

configuration
File renamed without changes.
1 change: 1 addition & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"pylint_extensions",
"pylint_messages",
"pylint_options",
"pyreverse_configuration",
"sphinx.ext.autosectionlabel",
"sphinx.ext.intersphinx",
"sphinx_reredirects",
Expand Down
75 changes: 75 additions & 0 deletions doc/exts/pyreverse_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt

"""Script used to generate the pyreverse configuration page."""

from __future__ import annotations

from pathlib import Path
from typing import NamedTuple

from sphinx.application import Sphinx

from pylint.pyreverse.main import OPTIONS_GROUPS, Run
from pylint.typing import OptionDict
from pylint.utils import get_rst_title


class OptionsData(NamedTuple):
name: str
optdict: OptionDict


PYREVERSE_PATH = (
Path(__file__).resolve().parent.parent / "additional_tools" / "pyreverse"
)
"""Path to the pyreverse documentation folder."""


def _write_config_page(run: Run) -> None:
"""Create or overwrite the configuration page."""
sections: list[str] = [
".. This file is auto-generated. Make any changes to the associated\n"
".. docs extension in 'doc/exts/pyreverse_configuration.py'.\n\n",
get_rst_title("Pyreverse Configuration", "^"),
]

options: list[OptionsData] = [OptionsData(name, info) for name, info in run.options]
option_groups: dict[str, list[str]] = {g: [] for g in OPTIONS_GROUPS.values()}

for option in sorted(options, key=lambda x: x.name):
option_string = get_rst_title(f"--{option.name}", '"')
option_string += f"*{option.optdict.get('help')}*\n\n"

if option.optdict.get("default") == "":
option_string += '**Default:** ``""``\n\n\n'
else:
option_string += f"**Default:** ``{option.optdict.get('default')}``\n\n\n"

option_groups[str(option.optdict.get("group"))].append(option_string)

for group_title in OPTIONS_GROUPS.values():
sections.append(
get_rst_title(group_title, "-") + "\n" + "".join(option_groups[group_title])
)

# Join all sections and remove the final two newlines
final_page = "\n\n".join(sections)[:-2]

with open(PYREVERSE_PATH / "configuration.rst", "w", encoding="utf-8") as stream:
stream.write(final_page)


# pylint: disable-next=unused-argument
def build_options_page(app: Sphinx | None) -> None:
# Write configuration page
_write_config_page(Run([]))


def setup(app: Sphinx) -> dict[str, bool]:
"""Connects the extension to the Sphinx process."""
# Register callback at the builder-inited Sphinx event
# See https://www.sphinx-doc.org/en/master/extdev/appapi.html
app.connect("builder-inited", build_options_page)
return {"parallel_read_safe": True}
4 changes: 2 additions & 2 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
:titlesonly:
:hidden:

pyreverse
symilar
additional_tools/pyreverse/index
additional_tools/symilar/index

.. toctree::
:caption: Changelog
Expand Down
7 changes: 7 additions & 0 deletions doc/whatsnew/fragments/9689.breaking
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
`pyreverse` `Run` was changed to no longer call `sys.exit()` in its `__init__`.
You should now call `Run(args).run()` which will return the exit code instead.
Having a class that always raised a `SystemExit` exception was considered a bug.

Normal usage of pyreverse through the CLI will not be affected by this change.

Refs #9689
2 changes: 1 addition & 1 deletion pylint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def run_pyreverse(argv: Sequence[str] | None = None) -> NoReturn:
"""
from pylint.pyreverse.main import Run as PyreverseRun

PyreverseRun(argv or sys.argv[1:])
sys.exit(PyreverseRun(argv or sys.argv[1:]).run())


def run_symilar(argv: Sequence[str] | None = None) -> NoReturn:
Expand Down
4 changes: 2 additions & 2 deletions pylint/pyreverse/inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import os
import traceback
from abc import ABC, abstractmethod
from collections.abc import Callable
from collections.abc import Callable, Sequence
from typing import Optional

import astroid
Expand Down Expand Up @@ -346,7 +346,7 @@ def handle(self, node: nodes.AssignAttr, parent: nodes.ClassDef) -> None:


def project_from_files(
files: list[str],
files: Sequence[str],
func_wrapper: _WrapperFuncT = _astroid_wrapper,
project_name: str = "no name",
black_list: tuple[str, ...] = constants.DEFAULT_IGNORE_LIST,
Expand Down
Loading

0 comments on commit 15a5ac0

Please sign in to comment.