Skip to content

Commit

Permalink
Add "autodocs", code documentation generated from docstrings
Browse files Browse the repository at this point in the history
Adding a new section into "Contribute" page, "Code documentation", and
besides the actual code documenation, I propose moving "Classes" page
there as well.
  • Loading branch information
happz committed Jul 21, 2023
1 parent 998e6d4 commit 7b4d444
Show file tree
Hide file tree
Showing 21 changed files with 127 additions and 68 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# tmt-specific

/tmp/
docs/autodocs/*.rst
docs/_build
docs/spec
docs/stories
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ requre:

# Build documentation, prepare man page
docs: man
cd docs && make html
make -C docs/ autodocs
make -C docs/ html
man: source
cp docs/header.txt $(TMP)/man.rst
tail -n+8 README.rst >> $(TMP)/man.rst
Expand Down
7 changes: 6 additions & 1 deletion docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext autodocs

help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " autodocs to refresh autodocs generated files"

clean:
rm -rf $(BUILDDIR)/*

autodocs:
rm -f autodocs/*.rst
pushd ../ && sphinx-apidoc --force --implicit-namespaces --no-toc -o docs/autodocs tmt && popd

html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
Expand Down
Empty file added docs/autodocs/.gitkeep
Empty file.
1 change: 1 addition & 0 deletions docs/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -434,5 +434,6 @@ Essential Classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. automodule:: tmt
:noindex:
:members:
:undoc-members:
9 changes: 9 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.autodoc.typehints',
'sphinx_rtd_theme',
]

Expand Down Expand Up @@ -128,6 +129,14 @@
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False

# Autodocs & type hints
autodoc_default_flags = ['members', 'undoc-members', 'show-inheritance', 'private-members']
autoclass_content = "both"

autodoc_typehints_format = 'short'
autodoc_typehints_description_target = 'all'
# This one works, but it's a bit uglier than the default value (`signature`).
# autodoc_typehints = 'description'

# -- Options for HTML output ----------------------------------------------

Expand Down
10 changes: 10 additions & 0 deletions docs/contribute.rst
Original file line number Diff line number Diff line change
Expand Up @@ -447,3 +447,13 @@ __ https://src.fedoraproject.org/rpms/tmt/pull-requests
__ https://copr.fedorainfracloud.org/coprs/psss/tmt/builds/
__ https://pypi.org/project/tmt/
__ https://packit.dev/docs/cli/propose-downstream/


Code documentation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. toctree::
:maxdepth: 1

Overview of important and interesting classes <classes>
Documentation generated from sources <autodocs/tmt.rst>
1 change: 0 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,4 @@ Table of Contents
Stories <stories>
Questions <questions>
Contribute <contribute>
Classes <classes>
Plugins <plugins>
9 changes: 5 additions & 4 deletions plans/install/docs.fmf
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ description:
well and there is no warning displayed during the build.
prepare:
how: install
package: python3-pip
package:
- python3-pip
- make
- python3-docutils
execute:
script: |
set -ex
set -o pipefail
pip3 install .[docs]
cd docs
python3 -m sphinx -T -E -b html -d _build/doctrees \
. _build/html 2>&1 | tee output
make docs 2>&1 | tee output
egrep 'ERROR|WARNING' output && exit 1 || exit 0
2 changes: 1 addition & 1 deletion tmt/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ def __init__(
"""
Create a ``Logger`` instance with given verbosity levels.
:param actual_logger: a :py:class:`logging.Logger` instance, the _raw logger_
:param actual_logger: a :py:class:`logging.Logger` instance, the raw logger
to use for logging.
:param base_shift: shift applied to all messages processed by this logger.
:param labels_padding: if set, rendered labels would be padded to this
Expand Down
12 changes: 6 additions & 6 deletions tmt/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
if TYPE_CHECKING:
from typing_extensions import Self

from tmt.steps.provision import Guest
import tmt.steps.provision


TaskT = TypeVar('TaskT', bound='_Task')
Expand All @@ -24,15 +24,15 @@ class TaskOutcome(Generic[TaskT]):
executed, where and what was the result.
"""

#: A :py:`_Task` instace the outcome relates to.
#: A :py:class:`_Task` instace the outcome relates to.
task: TaskT

#: A logger to use for logging events related to the outcome.
logger: Logger

#: Guest on which the phase was executed. May be unset, some tasks
#: may handle multiguest actions on their own.
guest: Optional['Guest']
guest: Optional['tmt.steps.provision.Guest']

#: If set, an exception was raised by the running task, and the exception
#: is saved in this field.
Expand All @@ -44,7 +44,7 @@ class _Task:
""" A base class for tasks to be executed on one or more guests """

#: A list of guests to execute the task on.
guests: List['Guest']
guests: List['tmt.steps.provision.Guest']

#: A logger to use for logging events related to the task. It serves as
#: a root logger for new loggers queue may spawn for each guest.
Expand Down Expand Up @@ -114,7 +114,7 @@ def go(self) -> Generator[TaskOutcome['Self'], None, None]:
class Task(_Task):
""" A task that should run on multiple guests at the same time """

def run_on_guest(self, guest: 'Guest', logger: Logger) -> None:
def run_on_guest(self, guest: 'tmt.steps.provision.Guest', logger: Logger) -> None:
raise NotImplementedError

def prepare_loggers(
Expand Down Expand Up @@ -156,7 +156,7 @@ def go(self) -> Generator[TaskOutcome['Self'], None, None]:
old_loggers: Dict[str, Logger] = {}

with ThreadPoolExecutor(max_workers=len(self.guests)) as executor:
futures: Dict[Future[None], Guest] = {}
futures: Dict[Future[None], 'tmt.steps.provision.Guest'] = {}

for guest in self.guests:
# Swap guest's logger for the one we prepared, with labels
Expand Down
31 changes: 15 additions & 16 deletions tmt/steps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@
import tmt.plugins
import tmt.steps.discover
import tmt.steps.execute
from tmt.base import Plan
from tmt.steps.provision import Guest
import tmt.steps.provision


DEFAULT_PLUGIN_METHOD_ORDER: int = 50
Expand Down Expand Up @@ -78,7 +77,7 @@ def __init__(
super().__init__(**kwargs)
self.order: int = order

def enabled_on_guest(self, guest: 'Guest') -> bool:
def enabled_on_guest(self, guest: 'tmt.steps.provision.Guest') -> bool:
""" Phases are enabled across all guests by default """
return True

Expand Down Expand Up @@ -234,7 +233,7 @@ class Step(tmt.utils.Common, tmt.export.Exportable['Step']):
def __init__(
self,
*,
plan: 'Plan',
plan: 'tmt.base.Plan',
data: Optional[RawStepDataArgument] = None,
name: Optional[str] = None,
workdir: tmt.utils.WorkdirArgumentType = None,
Expand All @@ -245,7 +244,7 @@ def __init__(
super().__init__(name=name, parent=plan, workdir=workdir, logger=logger)

# Initialize data
self.plan: 'Plan' = plan
self.plan: 'tmt.base.Plan' = plan
self._status: Optional[str] = None
self._phases: List[Phase] = []

Expand Down Expand Up @@ -1021,7 +1020,7 @@ def _emit_key(key: str) -> None:
for key in keys:
_emit_key(key)

def enabled_on_guest(self, guest: 'Guest') -> bool:
def enabled_on_guest(self, guest: 'tmt.steps.provision.Guest') -> bool:
""" Check if the plugin is enabled on the specific guest """

# FIXME: cast() - typeless "dispatcher" method
Expand Down Expand Up @@ -1151,7 +1150,7 @@ class Plugin(BasePlugin):
def go(
self,
*,
guest: 'Guest',
guest: 'tmt.steps.provision.Guest',
environment: Optional[tmt.utils.EnvironmentType] = None,
logger: tmt.log.Logger) -> None:
""" Perform actions shared among plugins when beginning their tasks """
Expand Down Expand Up @@ -1426,7 +1425,7 @@ class GuestTopology(tmt.utils.SerializableContainer):
role: Optional[str]
hostname: Optional[str]

def __init__(self, guest: 'Guest') -> None:
def __init__(self, guest: 'tmt.steps.provision.Guest') -> None:
self.name = guest.name
self.role = guest.role
self.hostname = guest.guest
Expand All @@ -1444,8 +1443,8 @@ class Topology(tmt.utils.SerializableContainer):
role_names: List[str]
roles: Dict[str, List[str]]

def __init__(self, guests: List['Guest']) -> None:
roles: DefaultDict[str, List['Guest']] = collections.defaultdict(list)
def __init__(self, guests: List['tmt.steps.provision.Guest']) -> None:
roles: DefaultDict[str, List['tmt.steps.provision.Guest']] = collections.defaultdict(list)

self.guest = None
self.guest_names: List[str] = []
Expand Down Expand Up @@ -1570,7 +1569,7 @@ def push(
self,
*,
dirpath: Path,
guest: 'Guest',
guest: 'tmt.steps.provision.Guest',
filename_base: Optional[str] = None,
logger: tmt.log.Logger) -> EnvironmentType:
"""
Expand Down Expand Up @@ -1632,7 +1631,7 @@ def run(self, logger: tmt.log.Logger) -> None:

self.phase.go()

def run_on_guest(self, guest: 'Guest', logger: tmt.log.Logger) -> None:
def run_on_guest(self, guest: 'tmt.steps.provision.Guest', logger: tmt.log.Logger) -> None:
assert isinstance(self.phase, Plugin) # narrow type

self.phase.go(
Expand All @@ -1655,7 +1654,7 @@ def enqueue(
self,
*,
phase: Union[Action, Plugin],
guests: List['Guest']) -> None:
guests: List['tmt.steps.provision.Guest']) -> None:
"""
Add a phase to queue.
Expand Down Expand Up @@ -1684,7 +1683,7 @@ class PushTask(Task):
def name(self) -> str:
return 'push'

def run_on_guest(self, guest: 'Guest', logger: tmt.log.Logger) -> None:
def run_on_guest(self, guest: 'tmt.steps.provision.Guest', logger: tmt.log.Logger) -> None:
guest.push()


Expand All @@ -1698,7 +1697,7 @@ class PullTask(Task):
def name(self) -> str:
return 'pull'

def run_on_guest(self, guest: 'Guest', logger: tmt.log.Logger) -> None:
def run_on_guest(self, guest: 'tmt.steps.provision.Guest', logger: tmt.log.Logger) -> None:
guest.pull(source=self.source)


Expand All @@ -1718,7 +1717,7 @@ def sync_with_guests(
needed, and this function handles the details.
:param step: step managing the sync operation.
:param action: ``push`` or ``pull`, used for nicer logging.
:param action: ``push`` or ``pull``, used for nicer logging.
:param task: :py:class:`PushTask` or :py:class:`PullTask` which represents
the actual operation.
:param logger: logger to use for logging.
Expand Down
8 changes: 4 additions & 4 deletions tmt/steps/discover/fmf.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,13 @@ class DiscoverFmf(tmt.steps.discover.DiscoverPlugin):
Related config options (all optional):
* dist-git-merge - set to True if you want to copy in extracted
sources to the local repo
sources to the local repo
* dist-git-init - set to True and 'fmf init' will be called inside
extracted sources (at dist-git-extract or top directory)
extracted sources (at dist-git-extract or top directory)
* dist-git-extract - directory (glob supported) to copy from
extracted sources (defaults to inner fmf-root)
extracted sources (defaults to inner fmf-root)
* dist-git-remove-fmf-root - set to True to remove fmf root from
extracted sources
extracted sources
Selecting tests containing specified link is possible using 'link'
option accepting RELATION:TARGET format of values. Regular
Expand Down
52 changes: 29 additions & 23 deletions tmt/steps/discover/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,39 +193,45 @@ class DiscoverShell(tmt.steps.discover.DiscoverPlugin):
in the plan as a list of dictionaries containing test name, actual
test script and optionally a path to the test. Example config:
discover:
how: shell
tests:
- name: /help/main
test: tmt --help
- name: /help/test
test: tmt test --help
- name: /help/smoke
test: ./smoke.sh
path: /tests/shell
.. code-block:: yaml
discover:
how: shell
tests:
- name: /help/main
test: tmt --help
- name: /help/test
test: tmt test --help
- name: /help/smoke
test: ./smoke.sh
path: /tests/shell
For DistGit repo one can extract source tarball and use its code.
It is extracted to TMT_SOURCE_DIR however no patches are applied
(only source tarball is extracted).
discover:
how: shell
dist-git-source: true
tests:
- name: /upstream
test: cd $TMT_SOURCE_DIR/*/tests && make test
.. code-block:: yaml
discover:
how: shell
dist-git-source: true
tests:
- name: /upstream
test: cd $TMT_SOURCE_DIR/*/tests && make test
To clone a remote repository and use it as a source specify `url`.
It accepts also `ref` to checkout provided reference. Dynamic
reference feature is supported as well.
discover:
how: shell
url: https://github.com/teemtee/tmt.git
ref: "1.18.0"
tests:
- name: first test
test: ./script-from-the-repo.sh
.. code-block:: yaml
discover:
how: shell
url: https://github.com/teemtee/tmt.git
ref: "1.18.0"
tests:
- name: first test
test: ./script-from-the-repo.sh
"""

_data_class = DiscoverShellData
Expand Down

0 comments on commit 7b4d444

Please sign in to comment.