tmt package

Subpackages

Submodules

tmt.ansible module

Ansible integration for tmt.

This module provides classes and utilities for managing Ansible inventory generation and configuration within tmt test plans.

class tmt.ansible.AnsibleInventory

Bases: object

Generate Ansible inventory files from provisioned guests.

Creates Ansible inventory file that can be used with playbooks to manage provisioned guests. Supports custom layouts and automatically configures host variables based on guest properties.

classmethod generate(guests: list[Guest], layout_path: Path | None = None) dict[str, Any]

Generate Ansible inventory from guests and layout.

Parameters:
  • guests – list of provisioned guests to include in the inventory.

  • layout_path – optional full path to a custom layout template.

Returns:

complete Ansible inventory dictionary.

class tmt.ansible.GuestAnsible(group: str | None = None, vars: dict[str, ~typing.Any] = <factory>)

Bases: SerializableContainer

Ansible configuration for individual guests.

classmethod from_spec(spec: _RawGuestAnsible | None) GuestAnsible

Convert a YAML mapping into GuestAnsible object.

group: str | None = None
to_spec() _RawGuestAnsible

Convert GuestAnsible object to a YAML-serializable specification.

vars: dict[str, Any]
class tmt.ansible.PlanAnsible(inventory: PlanAnsibleInventory | None = None)

Bases: SerializableContainer

Root level general Ansible configuration

classmethod from_spec(spec: Any) PlanAnsible

Convert a YAML mapping into PlanAnsible object.

inventory: PlanAnsibleInventory | None = None
to_spec() dict[str, Any]

Convert PlanAnsible object to a YAML-serializable specification.

class tmt.ansible.PlanAnsibleInventory(layout: str | None = None)

Bases: SerializableContainer

Ansible inventory configuration for the plan.

classmethod from_spec(spec: _RawPlanAnsibleInventory | None) PlanAnsibleInventory

Convert a YAML mapping into PlanAnsibleInventory object.

layout: str | None = None
to_spec() _RawPlanAnsibleInventory

Convert PlanAnsibleInventory object to a YAML-serializable specification.

tmt.ansible.normalize_guest_ansible(key_address: str, raw_ansible: Any, logger: Logger) GuestAnsible

Normalize a ansible key value from provision guest data.

Parameters:
  • key_address – location of the key being that’s being normalized.

  • logger – logger to use for logging.

  • raw_ansible – input from either command line or fmf node.

tmt.ansible.normalize_plan_ansible(key_address: str, raw_ansible: Any, logger: Logger) PlanAnsible

Normalize a ansible key value.

Parameters:
  • key_address – location of the key being that’s being normalized.

  • logger – logger to use for logging.

  • raw_ansible – input from either command line or fmf node.

tmt.convert module

Convert metadata into the new format

Add relevant link into data under the ‘link’ key

tmt.convert.adjust_runtest(path: Path) None

Adjust runtest.sh content and permission

tmt.convert.extract_relevancy(notes: str, field: StructuredField) str | list[str] | None

Get relevancy from testcase, respecting sf priority

tmt.convert.filter_common_data(common_data: dict[str, Any], individual_data: list[dict[str, Any]]) None

Filter common data out from individual data

tmt.convert.html_to_markdown(html: str) str

Convert html to markdown

tmt.convert.read(path: Path, makefile: bool, restraint: bool, nitrate: bool, polarion: bool, polarion_case_id: list[str], link_polarion: bool, purpose: bool, disabled: bool, types: list[str], general: bool, dry_run: bool, logger: Logger) tuple[dict[str, Any], list[dict[str, Any]]]

Read old metadata from various sources

Returns tuple (common_data, individual_data) where ‘common_data’ are metadata which belong to main.fmf and ‘individual_data’ contains data for individual testcases (if multiple nitrate testcases found).

tmt.convert.read_datafile(path: Path, filename: str, datafile: str, types: list[str], testinfo: str | None = None) tuple[str, dict[str, Any]]

Read data values from supplied Makefile or metadata file. Returns task name and a dictionary of the collected values.

tmt.convert.read_manual(plan_id: int, case_id: int, disabled: bool, with_script: bool, logger: Logger) None

Reads metadata of manual test cases from Nitrate

tmt.convert.read_manual_data(testcase: TestCase) dict[str, str]

Read test data from manual fields

tmt.convert.read_nitrate(beaker_task: str, common_data: dict[str, Any], disabled: bool, general: bool, dry_run: bool, logger: Logger) tuple[dict[str, Any], list[dict[str, Any]]]

Read old metadata from nitrate test cases

tmt.convert.read_nitrate_case(*, testcase: TestCase, makefile_data: dict[str, Any] | None = None, general: bool = False, logger: Logger) dict[str, Any]

Read old metadata from nitrate test case

tmt.convert.read_polarion(common_data: dict[str, Any], individual_data: list[dict[str, Any]], polarion_case_id: list[str], link_polarion: bool, filenames: list[str], dry_run: bool) None

Read data from Polarion

tmt.convert.read_polarion_case(data: dict[str, Any] | list[dict[str, Any]], polarion_case_id: str | None, link_polarion: bool, dry_run: bool) None

Read data of specific case from Polarion

tmt.convert.read_tier(tag: str, data: dict[str, Any]) None

Extract tier level from tag

Check for the tier attribute, if there are multiple TierX tags, pick the one with the lowest index.

tmt.convert.relevancy_to_adjust(relevancy: str | list[str], logger: Logger) list[dict[str, Any]]

Convert the old test case relevancy into adjust rules

Expects a string or list of strings with relevancy rules. Returns a list of dictionaries with adjust rules.

tmt.convert.write(path: Path, data: dict[str, Any], quiet: bool = False) None

Write gathered metadata in the fmf format

tmt.convert.write_markdown(path: Path, content: dict[str, str]) None

Write gathered metadata in the markdown format

tmt.identifier module

exception tmt.identifier.IdError

Bases: Exception

General Identifier Error

exception tmt.identifier.IdLeafError

Bases: IdError

Identifier not stored in a leaf

tmt.identifier.add_uuid_if_not_defined(node: Tree, dry: bool, logger: Logger) str | None

Add UUID into node and return it unless already defined

tmt.identifier.generate_uuid() str

Generate and return a new UUID

tmt.identifier.get_id(node: Tree, leaf_only: bool = True) str | None

Get identifier if defined, optionally ensure leaf node

Return identifier for provided node. If ‘leaf_only’ is True, an additional check is performed to ensure that the identifier is defined in the node itself. The ‘IdLeafError’ exception is raised when the key is inherited from parent.

tmt.identifier.id_command(context: tmt.cli.Context, node: Tree, node_type: str, dry: bool) None

Command line interfacing with output to terminal

Show a brief summary when adding UUIDs to nodes.

tmt.lint module

Metadata linting.

Internal APIs, classes, shared functionality and helpers for test, plan and story metadata linting.

A mixin class, Lintable, provides the required functionality for base classes. Namely, it takes care of linter discovery and provides Lintable.lint() method to run them.

Classes spiced with Lintable define their sets of linters. Consider the following examples:

# Methods whose names start with ``lint_*`` prefix are considered *linters*,
# and linters perform one or more *checks* users can enable or disable.
def lint_path_exists(self) -> LinterReturn:
    # A linter must have a docstring which is then used to generate documentation,
    # e.g. when ``lint --list-checks`` is called. The docstring must begin with
    # a linter *id*. The id should match ``[CTPSG]\d\d\d`` regular expression:
    # ``C``ommon, ``T``est, ``P``lan, ``S``tory, ``G``roup, plus a three-digit
    # serial number of the check among its peers.
    ''' T004: test directory path must exist '''

    # Linter implements a generator (see :py:member:`LinterReturn`) yielding
    # two item tuples of :py:class:`LinterOutcome` and string messages.

    if not self.path:
        yield LinterOutcome.FAIL, 'directory path is not set'
        return

    test_path = os.path.join(self.node.root, os.path.relpath(self.path.strip(), '/'))

    if not os.path.exists(test_path):
        yield LinterOutcome.FAIL, f'test path "{test_path}" does not exist'
        return

    yield LinterOutcome.PASS, f'test path "{test_path}" does exist'

def lint_manual_valid_markdown(self) -> LinterReturn:
    ''' T008: manual test should be valid markdown '''

    # Linter should yield `SKIP` outcome when it does not apply, to announce
    # it did inspect the object but realized the object is out of scope of
    # the linter, and checks do not apply.
    if not self.manual:
         yield LinterOutcome.SKIP, 'not a manual test'
         return

    manual_test = os.path.join(self.node.root, self.path.strip())

    warnings = tmt.export.check_md_file_respects_spec(manual_test)

    if warnings:
        # Linter may yield as many tuples as it deems necessary. This allows
        # for linters iterating over more granular aspects of metadata,
        # providing more specific hints.
        for warning in warnings:
           yield LinterOutcome.WARN, warning

    ...
class tmt.lint.Lintable(*args: Any, **kwargs: Any)

Bases: Generic[LintableT]

Mixin class adding support for linting of class instances

classmethod discover_linters() None

Discover and register all linters implemented by this class.

A linter is a method whose name starts with lint_ prefix. It must have a docstring which serves as a hint for --list-checks output.

classmethod format_linters() str

Format registered linters for printing or logging.

Returns:

a string description of registered linters, suitable for logging or help texts.

classmethod get_linter_registry() list[Linter]

Return - or initialize - linter registry

lint(enable_checks: list[str] | None = None, disable_checks: list[str] | None = None, enforce_checks: list[str] | None = None, linters: list[Linter] | None = None) tuple[bool, list[tuple[Linter, LinterOutcome, LinterOutcome, str]]]

Check the instance against a battery of linters and report results.

Parameters:
  • enable_checks – if set, only linters providing the listed checks would be applied.

  • disable_checks – if set, linters providing the listed checks would not be applied.

  • enforce_checks – if set, listed checks would be marked as failed if their outcome is not pass, i.e. even a warning would become a fail.

  • linters – if set, only these linters would be applied. Providing linters makes enable_checks and disable_checks ignored.

Returns:

a tuple of two items: a boolean reporting whether the instance passed the test, and a list of LinterRuling items, each describing one linter outcome. Note that linters may produce none or more than one outcome.

classmethod resolve_enabled_linters(enable_checks: list[str] | None = None, disable_checks: list[str] | None = None) list[Linter]

Produce a list of enabled linters from all registered ones.

Method combines three inputs:

  • registered linters, acquired from the class registry,

  • list of checks to enable, and

  • list of checks to disable

into a single list of linters that are considered as enabled.

Parameters:
  • enable_checks – if set, only linters providing the listed checks would be included in the output.

  • disable_checks – if set, linters providing the listed checks would be removed from the output.

Returns:

list of linters that were registered, and whose checks were enabled and not disabled.

class tmt.lint.Linter(callback: Callable[[Lintable], Iterator[tuple[LinterOutcome, str]]])

Bases: object

A single linter

callback: Callable[[Lintable], Iterator[tuple[LinterOutcome, str]]]
description: str | None = None
format() list[str]

Format the linter for printing or logging.

Returns:

a string description of the linter, suitable for logging or help texts, in the form of lines of text.

help: str
id: str
class tmt.lint.LinterOutcome(*values)

Bases: Enum

FAIL = 'fail'
FIXED = 'fixed'
PASS = 'pass'
SKIP = 'skip'
WARN = 'warn'
tmt.lint.LinterReturn

A return value type of a single linter.

alias of Iterator[tuple[LinterOutcome, str]]

tmt.lint.LinterRuling

Info on how a linter decided: linter itself, its outcome & the message.

alias of tuple[Linter, LinterOutcome, LinterOutcome, str]

tmt.lint.filter_allowed_checks(rulings: Iterable[tuple[Linter, LinterOutcome, LinterOutcome, str]], outcomes: list[LinterOutcome] | None = None) Iterator[tuple[Linter, LinterOutcome, LinterOutcome, str]]

Filter only rulings whose outcomes are allowed.

Parameters:
  • rulings – rulings to process.

  • outcomes – a list of allowed ruling outcomes. If not set, all outcomes are allowed.

Yields:

rulings with allowed outcomes.

tmt.lint.format_rulings(rulings: Iterable[tuple[Linter, LinterOutcome, LinterOutcome, str]], config: Config) Iterator[str]

Format rulings for printing or logging.

Parameters:

rulings – rulings to format.

Yields:

rulings formatted as separate strings.

tmt.log module

tmt’s logging subsystem.

Adds a layer on top of Python’s own logging subsystem. This layer implements the desired verbosity and debug levels, colorization, formatting, verbosity inheritance and other features used by tmt commands and code.

The main workhorses are Logger instances. Each instance wraps a particular logging.Logger instance - usually there’s a chain of such instances, with the root one having console and logfile handlers attached. tmt’s log verbosity/debug/quiet features are handled on our side, with the use of logging.Filter classes.

Logger instances can be cloned and modified, to match various levels of tmt’s runtime class tree - tmt spawns a “root logger” from which a new one is cloned - and indented by one extra level - for Run instance, and so on. This way, every object in tmt’s hierarchy uses a given logger, which may have its own specific settings, and, in the future, possibly also handlers for special output channels.

While tmt recognizes several levels of verbosity (-v) and debugging (-d), all messages emitted by Logger.verbose() and Logger.debug() use a single logging level, INFO or DEBUG, respectively. The level of verbosity and debugging is then handled by a special logging.Filter` classes. This allows different levels when logging to console but all-capturing log files while keeping implementation simple - the other option would be managing handlers themselves, which would be very messy given the propagation of messages.

class tmt.log.ConsoleFormatter(apply_colors: bool = True, show_timestamps: bool = False)

Bases: _Formatter

Initialize the formatter with specified format strings.

Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.

Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to use one of %-formatting, str.format() ({}) formatting or string.Template formatting in your format string.

Changed in version 3.2: Added the style parameter.

class tmt.log.ConsoleHandler(stream=None)

Bases: StreamHandler

Initialize the handler.

If stream is not specified, sys.stderr is used.

class tmt.log.DebugLevelFilter(name='')

Bases: Filter

Initialize a filter.

Initialize with the name of the logger which, together with its children, will have its events allowed through the filter. If no name is specified, allow every event.

filter(record: LogRecord) bool

Determine if the specified record is to be logged.

Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.

class tmt.log.LogRecordDetails(key: str, value: str | dict[str, ~typing.Any] | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: tmt.utils.themes.Style = None, shift: int = 0, logger_labels: list[str] = <factory>, logger_labels_padding: int = 0, logger_verbosity_level: int = 0, message_verbosity_level: int | None = None, logger_debug_level: int = 0, message_debug_level: int | None = None, logger_quiet: bool = False, ignore_quietness: bool = False, logger_topics: set[~tmt.log.Topic] = <factory>, message_topic: ~tmt.log.Topic | None = None, source: str | None = None, reason: str | None = None)

Bases: object

tmt’s log message components attached to log records

color: tmt.utils.themes.Style = None
ignore_quietness: bool = False
key: str
logger_debug_level: int = 0
logger_labels: list[str]
logger_labels_padding: int = 0
logger_quiet: bool = False
logger_topics: set[Topic]
logger_verbosity_level: int = 0
message_debug_level: int | None = None
message_topic: Topic | None = None
message_verbosity_level: int | None = None
reason: str | None = None

The reason for triggering the log.

shift: int = 0
source: str | None = None

The source related to the log message. This is different from the stacktrace which is automatically handled. This is meant to track sources such as those from fmf file

value: str | dict[str, Any] | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None
class tmt.log.LogfileFormatter

Bases: _Formatter

Initialize the formatter with specified format strings.

Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.

Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to use one of %-formatting, str.format() ({}) formatting or string.Template formatting in your format string.

Changed in version 3.2: Added the style parameter.

class tmt.log.LogfileHandler(filepath: tmt.utils.Path)

Bases: FileHandler

Open the specified file and use it as the stream for logging.

emitting_to: list[Path] = []

Paths of all log files to which LogfileHandler was attached.

class tmt.log.Logger(actual_logger: Logger, base_shift: int = 0, labels: list[str] | None = None, labels_padding: int = 0, verbosity_level: int = 0, debug_level: int = 0, quiet: bool = False, topics: set[Topic] | None = None, apply_colors_output: bool = True, apply_colors_logging: bool = True)

Bases: object

A logging entry point, representing a certain level of verbosity and handlers.

Provides actual logging methods plus methods for managing verbosity levels and handlers.

Create a Logger instance with given verbosity levels.

Parameters:
  • actual_logger – a logging.Logger instance, the raw logger to use for logging.

  • base_shift – shift applied to all messages processed by this logger.

  • labels_padding – if set, rendered labels would be padded to this length.

  • verbosity_level – desired verbosity level, usually derived from -v command-line option.

  • debug_level – desired debugging level, usually derived from -d command-line option.

  • quiet – if set, all messages would be suppressed, with the exception of warnings (warn()), errors (fail()) and messages emitted with print().

add_console_handler(show_timestamps: bool = False) None

Attach console handler to this logger.

Parameters:

show_timestamps – when set, emitted messages would include the time.

add_logfile_handler(filepath: tmt.utils.Path) None

Attach a log file handler to this logger

add_runwarnings_handler(filepath: Path) None
property apply_colors_output: bool
apply_verbosity_options(cli_invocation: tmt.cli.CliInvocation | None = None, **kwargs: Any) Logger

Update logger’s settings to match given CLI options.

Use this method to update logger’s settings after Logger.descend() call, to reflect options given to a tmt subcommand.

clone() Logger

Create a copy of this logger instance.

All its settings are propagated to new instance. Settings are not shared, and may be freely modified after cloning without affecting the other logger.

classmethod create(actual_logger: Logger | None = None, apply_colors_output: bool = True, apply_colors_logging: bool = True, **verbosity_options: Any) Logger

Create a (root) tmt logger.

This method has a very limited set of use cases:

  • CLI bootstrapping right after tmt started.

  • Unit tests of code that requires logger as one of its inputs.

  • 3rd party apps treating tmt as a library, i.e. when they wish tmt to use their logger instead of tmt’s default one.

Parameters:

actual_logger – a logging.Logger instance to wrap. If not set, a default logger named tmt is created.

debug(key: str, value: str | dict[str, Any] | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: tmt.utils.themes.Style = None, shift: int = 0, level: int = 1, topic: Topic | None = None, stacklevel: int = 1) None
descend(logger_name: str | None = None, extra_shift: int = 1) Logger

Create a copy of this logger instance, but with a new raw logger.

New logging.Logger instance is created from our raw logger, forming a parent/child relationship between them, and it’s then wrapped with Logger instance. Settings of this logger are copied to new one, with the exception of base_shift which is increased by one, effectively indenting all messages passing through new logger.

Parameters:
  • logger_name – optional name for the underlying logging.Logger instance. Useful for debugging. If not set, a generic one is created.

  • extra_shift – by how many extra levels should messages be indented by new logger.

fail(message: str, shift: int = 0, stacklevel: int = 1) None
classmethod get_bootstrap_logger() Logger

Create a logger designed for tmt startup time.

Warning

This logger has a very limited use case span, i.e. before tmt can digest its command-line options and create a proper logger. This happens inside tmt.cli._root.main() function, but there are some actions taken by tmt code before this function is called by Click, actions that need to emit logging messages. Using it anywhere outside of this brief time in tmt’s runtime should be ruled out.

info(key: str, value: str | dict[str, Any] | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: tmt.utils.themes.Style = None, shift: int = 0, topic: Topic | None = None, stacklevel: int = 1) None
property labels_span: int

Length of rendered labels

print(text: str | None = None, color: tmt.utils.themes.Style = None, file: TextIO | None = None, nl: bool = True) None
print_format(text: str, color: tmt.utils.themes.Style = None) str

Format the given text in a way suitable for print()

verbose(key: str, value: str | dict[str, Any] | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: tmt.utils.themes.Style = None, shift: int = 0, level: int = 1, topic: Topic | None = None, stacklevel: int = 1) None
warn(message: str, shift: int, stacklevel: int = 1) None
warning(message: str, shift: int = 0, stacklevel: int = 1, source: str | None = None, reason: str | None = None) None
class tmt.log.LoggingFunction(*args, **kwargs)

Bases: Protocol

class tmt.log.Print(*args, **kwargs)

Bases: Protocol

class tmt.log.QuietnessFilter(name='')

Bases: Filter

Initialize a filter.

Initialize with the name of the logger which, together with its children, will have its events allowed through the filter. If no name is specified, allow every event.

filter(record: LogRecord) bool

Determine if the specified record is to be logged.

Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.

class tmt.log.RunWarningEntry(msg: str, logger: str, trace: str, source: str | None, reason: str | None)

Bases: SpecBasedContainer[dict[str, Any], dict[str, Any]]

classmethod from_spec(spec: dict[str, Any]) Self

Convert from a specification file or from a CLI option

See https://tmt.readthedocs.io/en/stable/code/classes.html#class-conversions for more details.

See to_spec() for its counterpart.

logger: str
msg: str
reason: str | None
source: str | None
trace: str
class tmt.log.RunWarningsFilter(name='')

Bases: Filter

Initialize a filter.

Initialize with the name of the logger which, together with its children, will have its events allowed through the filter. If no name is specified, allow every event.

filter(record: LogRecord) bool

Determine if the specified record is to be logged.

Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.

class tmt.log.RunWarningsFormatter

Bases: Formatter

Initialize the formatter with specified format strings.

Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.

Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to use one of %-formatting, str.format() ({}) formatting or string.Template formatting in your format string.

Changed in version 3.2: Added the style parameter.

format(record: LogRecord) str

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

class tmt.log.RunWarningsHandler(filepath: Path)

Bases: FileHandler

Open the specified file and use it as the stream for logging.

class tmt.log.Topic(*values)

Bases: Enum

ADJUST_DECISIONS = 'adjust-decisions'
CLI_INVOCATIONS = 'cli-invocations'
COMMAND_EVENTS = 'command-events'
HELP_RENDERING = 'help-rendering'
KEY_NORMALIZATION = 'key-normalization'
POLICY = 'policy'
class tmt.log.TopicFilter(name='')

Bases: Filter

Initialize a filter.

Initialize with the name of the logger which, together with its children, will have its events allowed through the filter. If no name is specified, allow every event.

filter(record: LogRecord) bool

Determine if the specified record is to be logged.

Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.

class tmt.log.VerbosityLevelFilter(name='')

Bases: Filter

Initialize a filter.

Initialize with the name of the logger which, together with its children, will have its events allowed through the filter. If no name is specified, allow every event.

filter(record: LogRecord) bool

Determine if the specified record is to be logged.

Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.

tmt.log.create_decolorizer(apply_colors: bool) Callable[[str], str]
tmt.log.decide_colorization(no_color: bool, force_color: bool) tuple[bool, bool]

Decide whether the output and logging should be colorized.

Based on values of CLI options, environment variables and output stream properties, a colorization setup is decided. The following inputs are evaluated, in this order:

  • if either of the --no-color CLI option, NO_COLOR or

    TMT_NO_COLOR environment variables are set, colorization would be disabled.

  • if either of the --force-color CLI option or TMT_FORCE_COLOR

    environment variable are set, colorization would be forcefully enabled.

If none of the situations above happened, colorization would be enabled for output and logging based on their respective stream TTY status. Output is sent to standard output, logging then to standard error output, colorization would then be the outcome of stream’s file.isatty() method.

Note

Be aware that “forced enable” is stronger than “forced disable”. If --force-color or TMT_FORCE_COLOR are set, colors will be enabled despite any disabling options or environment variables.

Note

All inputs with the exception of isatty result control both types of output, regular output and logging, and applies to both of them. Only isatty outcome is specific for each type, and may result in one output type dropping colors while the other would be colorized.

Parameters:
  • no_color – value of the --no-color CLI option.

  • force_color – value of the –force-color` CLI option.

Returns:

a tuple of two booleans, one for output colorization, the other for logging colorization.

tmt.log.indent(key: str, value: str | dict[str, Any] | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: tmt.utils.themes.Style = None, level: int = 0, labels: list[str] | None = None, labels_padding: int = 0) str

Indent a key/value message.

If both key and value are specified, {key}: {value} message is rendered. Otherwise, just key is used alone. If value contains multiple lines, each but the very first line is indented by one extra level.

Parameters:
  • value – optional value to print at right side of key.

  • color – optional color to apply on key.

  • level – number of indentation levels. Each level is indented by INDENT spaces.

  • labels – optional list of strings to prepend to each message. Each item would be wrapped within square brackets ([foo] message...).

  • labels_padding – if set, rendered labels would be padded to this length.

tmt.log.render_labels(labels: list[str]) str

tmt.options module

Common options and the MethodCommand class

class tmt.options.Deprecated(since: str, hint: str | None = None)

Bases: object

Version information and hint for obsolete options

hint: str | None = None
property rendered: str
since: str
class tmt.options.Path

Bases: ParamType

convert(value: Any, param: Parameter | None, ctx: Context | None) Path | None

Convert the value to the correct type. This is not called if the value is None (the missing value).

This must accept string values from the command line, as well as values that are already the correct type. It may also convert other compatible types.

The param and ctx arguments may be None in certain situations, such as when converting prompt input.

If the value cannot be converted, call fail() with a descriptive message.

Parameters:
  • value – The value to convert.

  • param – The parameter that is using this type to convert its value. May be None.

  • ctx – The current context that arrived at this value. May be None.

name: str = 'path'

the descriptive name of this type

tmt.options.create_method_class(methods: dict[str, Command]) type[Command]

Create special class to handle different options for each method

Accepts dictionary with method names and corresponding commands: For example: {‘fmf’, <click.core.Command object at 0x7f3fe04fded0>} Methods should be already sorted according to their priority.

tmt.options.create_options_decorator(options: list[Callable[[Any], Any]]) Callable[[FC], FC]
tmt.options.option(*param_decls: str, show_default: bool = False, is_flag: bool = False, multiple: bool = False, count: bool = False, type: Choice | Any | None = None, help: str | None = None, required: bool = False, default: Any | None = None, nargs: int | None = None, metavar: str | None = None, prompt: str | None = None, envvar: str | None = None, hidden: bool = False, choices: Sequence[str] | None = None, deprecated: Deprecated | None = None) Callable[[Any], Any]

Attaches an option to the command.

This is a wrapper for click.option(), its parameters have the same meaning as those of click.option(), and are passed to click.option(), with the exception of deprecated parameter.

Parameters:
  • choices – if set, it sets type of the option to click.Choices, and limits option values to those listed in choices.

  • deprecated – if set, it is rendered and appended to help. This parameter is not passed to click.option().

tmt.policy module

class tmt.policy.Instruction(**extra_data: Any)

Bases: MetadataContainer

A single instruction describing changes to test, plan or story keys.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

apply(obj: Core, logger: Logger) None

Apply the instruction to a given object.

Parameters:
  • obj – object to modify - a test, plan, or story.

  • logger – used for logging.

model_config: ClassVar[ConfigDict] = {'alias_generator': <function key_to_option>, 'extra': 'allow', 'validate_assignment': True, 'validate_default': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tmt.policy.KEY_DIFF_TEMPLATE = "\n{{ OLD_VALUE | to_yaml | prefix('- ') | style(fg='red') | trim }}\n{{ NEW_VALUE | to_yaml | prefix('+ ') | style(fg='green') | trim }}\n\nField value source changed from {{ OLD_VALUE_SOURCE.value | style(fg='red') }} to {{ NEW_VALUE_SOURCE.value | style(fg='green') }}\n"

A template showing changes made by an instruction.

class tmt.policy.PlanInstruction(**extra_data: Any)

Bases: Instruction

A single instruction describing changes to plan keys.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

apply(obj: Core, logger: Logger) None

Apply the instruction to a given object.

Parameters:
  • obj – a plan to modify.

  • logger – used for logging.

model_config: ClassVar[ConfigDict] = {'alias_generator': <function key_to_option>, 'extra': 'allow', 'validate_assignment': True, 'validate_default': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class tmt.policy.Policy(*, name: str = 'unknown', test_policy: list[~tmt.policy.Instruction] = <factory>, plan_policy: list[~tmt.policy.PlanInstruction] = <factory>)

Bases: MetadataContainer

A tmt run policy.

A collection of instructions telling tmt how to modify test keys. See Policy for more details.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

apply_to_plans(*, plans: Iterable[Plan], logger: Logger) None

Apply policy to given plans.

Parameters:
  • plans – plans to modify.

  • policy_name – if set, record this name in logging.

  • logger – used for logging.

apply_to_tests(*, tests: Iterable[Test], logger: Logger) None

Apply policy to given tests.

Parameters:
  • tests – tests to modify.

  • policy_name – if set, record this name in logging.

  • logger – used for logging.

classmethod load_by_filepath(*, path: Path, root: Path | None = None) Policy

Load a policy from a given file.

Parameters:
  • path – a path to the policy file.

  • root – directory under which policy file must reside.

classmethod load_by_name(*, name: str, root: Path) Policy

Load a policy from a given directory.

Parameters:
  • name – suffix-less name of a file under the root path.

  • root – directory under which policy file must reside.

model_config: ClassVar[ConfigDict] = {'alias_generator': <function key_to_option>, 'extra': 'forbid', 'validate_assignment': True, 'validate_default': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
plan_policy: list[PlanInstruction]

Instructions for modifications of plans.

test_policy: list[Instruction]

Instructions for modifications of tests.

tmt.queue module

class tmt.queue.GuestlessTask(logger: Logger)

Bases: Task[TaskResultT]

A task not assigned to a particular set of guests.

An extension of the Task class, provides a starting point for tasks that do not need to run on any guest.

go() Iterator[Self]

Perform the task.

Called by Queue machinery to accomplish the task.

Invokes run() method to perform the task itself, and derived classes therefore must provide implementation of run method.

Yields:

instances of the same class, describing invocations of the task and their outcome. The task might be executed multiple times, depending on how exactly it was queued, and method would yield corresponding results.

abstractmethod run(logger: Logger) TaskResultT

Perform the task.

Called once from go(). Subclasses of must implement their logic in this method rather than in go() which is already provided.

class tmt.queue.MultiGuestTask(guests: list[Guest], logger: Logger)

Bases: Task[TaskResultT]

A task assigned to a particular set of guests.

An extension of the Task class, provides a starting point for tasks that do need to run on a set of guests.

go() Iterator[Self]

Perform the task.

Called by Queue machinery to accomplish the task.

Invokes run_on_guest() method to perform the task itself, and derived classes therefore must provide implementation of run_on_guest method.

Yields:

instances of the same class, describing invocations of the task and their outcome. The task might be executed multiple times, depending on how exactly it was queued, and method would yield corresponding results.

guest: Guest | None = None

Guest on which the phase was executed.

property guest_ids: list[str]
guests: list[Guest]

List of guests to run the task on.

abstractmethod run_on_guest(guest: Guest, logger: Logger) TaskResultT

Perform the task.

Called once from go(). Subclasses of must implement their logic in this method rather than in go() which is already provided.

class tmt.queue.Queue(name: str, logger: Logger)

Bases: list[TaskT]

Queue class for running tasks.

enqueue_task(task: TaskT) bool

Put new task into a queue.

Returns:

True if the queue was reordered because of the new task, False otherwise.

is_running: bool

If set, the queue is running and invoking tasks.

reset() None

Reset queue content and properties as if it was just created.

run() Iterator[TaskT]

Start crunching the queued tasks.

Tasks are executed in the order, for each invoked task new instance of this class is yielded.

show_tasks(label: str, logger: Logger) None
stop() Iterable[TaskT]

Stop crunching the queue tasks.

Returns:

remaining tasks.

class tmt.queue.Task(logger: Logger)

Bases: ABC, Generic[TaskResultT]

A base class for queueable actions.

Note

The class provides both the implementation of the action, but also serves as a container for outcome of the action: every time the task is invoked by <Queue>, the queue yields an instance of the same class, but filled with information related to the result of its action.

exc: Exception | None = None

If set, an exception was raised by the running task, and said exception is saved in this field.

abstractmethod go() Iterator[Self]

Perform the task.

Called by Queue machinery to accomplish the task.

Yields:

instances of the same class, describing invocations of the task and their outcome. The task might be executed multiple times, depending on how exactly it was queued, and method would yield corresponding results.

logger: Logger

A logger to use for logging events related to the outcome.

abstract property name: str

A name of this task.

Left for child classes to implement, because the name depends on the actual task.

order: int | None = None

Order of this task. Follow the semantics of the /spec/test/order key, the lower the number, the earlier the task runs. Tasks with order left unset will be invoked last, in no guaranteed order.

requested_exit: SystemExit | None = None

If set, the task raised SystemExit exception, and wants to terminate the run completely. Original exception is assigned to this field.

result: TaskResultT | None = None

Result returned by the task when executed.

tmt.queue.prepare_loggers(logger: Logger, labels: list[str]) dict[str, Logger]

Create loggers for a set of labels.

Guests are assumed to be a group a phase would be executed on, and therefore their labels need to be set, to provide context, plus their labels need to be properly aligned for more readable output.

tmt.recipe module

class tmt.recipe.Recipe(run: tmt.recipe._RecipeRun, plans: list[tmt.recipe._RecipePlan])

Bases: SpecBasedContainer[_RawRecipe, _RawRecipe], SerializableContainer

classmethod from_spec(spec: _RawRecipe, logger: Logger) Recipe

Convert from a specification file or from a CLI option

See https://tmt.readthedocs.io/en/stable/code/classes.html#class-conversions for more details.

See to_spec() for its counterpart.

plans: list[_RecipePlan]
run: _RecipeRun
to_spec() _RawRecipe

Convert to a form suitable for saving in a specification file

See https://tmt.readthedocs.io/en/stable/code/classes.html#class-conversions for more details.

See from_spec() for its counterpart.

class tmt.recipe.RecipeManager(logger: Logger)

Bases: Common

Initialize name and relation with the parent object

Prepare the workdir for provided id / directory path or generate a new workdir name if workdir=True given. Store command line context and options for future use if context is provided.

cli_invocation: 'tmt.cli.CliInvocation' | None = None
load(run: Run, recipe_path: Path) Recipe
save(run: Run) None
tests(recipe: Recipe, plan_name: str) list[TestOrigin]

Return the list of tests for the given plan name in the recipe.

tmt.result module

class tmt.result.BaseResult(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, original_result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: list[str] = <factory>, log: list[~tmt._compat.pathlib.Path] = <factory>, start_time: str | None = None, end_time: str | None = None, duration: str | None = None)

Bases: SerializableContainer

Describes what tmt knows about a result

duration: str | None = None
end_time: str | None = None
property failure_logs: list[Path]

Return paths to all failure logs from the result

log: list[Path]
name: str
note: list[str]
original_result: ResultOutcome = 'pass'
property printable_note: str
result: ResultOutcome = 'pass'
show() str

Return a nicely colored result with test name (and note)

start_time: str | None = None
class tmt.result.CheckResult(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, original_result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: list[str] = <factory>, log: list[~tmt._compat.pathlib.Path] = <factory>, start_time: str | None = None, end_time: str | None = None, duration: str | None = None, event: ~tmt.checks.CheckEvent = CheckEvent.BEFORE_TEST)

Bases: BaseResult

Describes what tmt knows about a single test check result

event: CheckEvent = 'before-test'
to_subcheck() SubCheckResult

Convert check to a tmt SubCheckResult

class tmt.result.PhaseResult(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, original_result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: list[str] = <factory>, log: list[~tmt._compat.pathlib.Path] = <factory>, start_time: str | None = None, end_time: str | None = None, duration: str | None = None, guest: ~tmt.result.ResultGuestData = <factory>)

Bases: BaseResult

Describes what tmt knows about result of individual phases, e.g. prepare ansible

guest: ResultGuestData
tmt.result.RawResult

Raw result as written in a YAML file. A dictionary, but for now the actual keys are not important.

class tmt.result.Result(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, original_result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: list[str] = <factory>, log: list[~tmt._compat.pathlib.Path] = <factory>, start_time: str | None = None, end_time: str | None = None, duration: str | None = None, serial_number: int = 0, web_link: str | None = None, fmf_id: ~tmt.base.core.FmfId | None = None, context: ~tmt.utils.FmfContext = <factory>, ids: dict[str, str | None] = <factory>, guest: ~tmt.result.ResultGuestData = <factory>, subresult: list[~tmt.result.SubResult] = <factory>, check: list[~tmt.result.CheckResult] = <factory>, data_path: ~tmt._compat.pathlib.Path | None = None)

Bases: BaseResult

Describes what tmt knows about a single test result

check: list[CheckResult]
context: FmfContext
data_path: Path | None = None
property failure_logs: list[Path]

Return paths to all failure logs from the result

fmf_id: FmfId | None = None
classmethod from_test_invocation(*, invocation: TestInvocation, result: ResultOutcome, note: list[str] | None = None, ids: dict[str, str | None] | None = None, log: list[Path] | None = None, subresult: list[SubResult] | None = None) Result

Create a result from a test invocation.

A helper for extracting interesting data from a given test invocation. While it’s perfectly possible to go directly through Result(...), most of the time a result stems from a particular test invocation captured by a TestInvocation instance.

Parameters:
  • invocation – a test invocation capturing the test run and results.

  • result – actual test outcome. It will be interpreted according to Test.result key (see https://tmt.readthedocs.io/en/stable/spec/tests.html#result).

  • note – optional result notes.

  • ids – additional test IDs. They will be added to IDs extracted from the test.

  • log – optional list of test logs.

guest: ResultGuestData
ids: dict[str, str | None]
interpret_check_result(check_name: str, interpret_checks: dict[str, CheckResultInterpret]) ResultOutcome

Aggregate all checks of given name and interpret the outcome

Parameters:
  • check_name – name of the check to be aggregated

  • interpret_checks – mapping of check:how and its result interpret

Returns:

ResultOutcome instance with the interpreted result

interpret_result(interpret: ResultInterpret, interpret_checks: dict[str, CheckResultInterpret]) Result

Interpret result according to a given interpretation instruction.

Inspect and possibly modify result and note attributes, following the interpret value.

Parameters:
  • interpret – how to interpret current result.

  • interpret_checks – mapping of check:how and its result interpret

Returns:

Result instance containing the updated result.

serial_number: int = 0
show(display_guest: bool = True) str

Return a nicely colored result with test name (and note)

subresult: list[SubResult]
static summary(results: list[Result]) str

Prepare a nice human summary of provided results

to_subresult() SubResult

Convert result to tmt subresult

static total(results: list[Result]) dict[ResultOutcome, int]

Return dictionary with total stats for given results

class tmt.result.ResultGuestData(name: str = 'default-0', role: str | None = None, primary_address: str | None = None)

Bases: SerializableContainer

Describes what tmt knows about a guest the result was produced on

classmethod from_guest(*, guest: Guest) ResultGuestData

Create a guest data for a result from a Guest instance.

A helper for extracting interesting guest data from a given guest.

Parameters:

guest – a guest instance to describe.

classmethod from_test_invocation(*, invocation: TestInvocation) ResultGuestData

Create a guest data for a result from a test invocation.

A helper for extracting interesting guest data from a given test invocation.

Parameters:

invocation – a test invocation capturing the test run and results.

name: str = 'default-0'
primary_address: str | None = None
role: str | None = None
tmt.result.ResultIds

A type of collection IDs tracked for a single result.

alias of dict[str, str | None]

class tmt.result.ResultInterpret(*values)

Bases: Enum

CUSTOM = 'custom'
ERROR = 'error'
FAIL = 'fail'
INFO = 'info'
PASS = 'pass'
RESPECT = 'respect'
RESTRAINT = 'restraint'
WARN = 'warn'
XFAIL = 'xfail'
classmethod from_spec(spec: str) ResultInterpret
classmethod is_result_outcome(value: ResultInterpret) bool
classmethod normalize(key_address: str, value: Any, logger: Logger) ResultInterpret
class tmt.result.ResultOutcome(*values)

Bases: Enum

ERROR = 'error'
FAIL = 'fail'
INFO = 'info'
PASS = 'pass'
PENDING = 'pending'
SKIP = 'skip'
WARN = 'warn'
classmethod from_spec(spec: str) ResultOutcome
static reduce(outcomes: list[ResultOutcome]) ResultOutcome

Reduce several result outcomes into a single outcome

Convert multiple outcomes into a single one by picking the worst. This is used when aggregating several test or check results to present a single value to the user.

class tmt.result.SubCheckResult(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, original_result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: list[str] = <factory>, log: list[~tmt._compat.pathlib.Path] = <factory>, start_time: str | None = None, end_time: str | None = None, duration: str | None = None, event: ~tmt.checks.CheckEvent = CheckEvent.BEFORE_TEST)

Bases: CheckResult

Describes what tmt knows about a single subtest check result.

It does not contain any additional fields; it simply defines a type to easily differentiate between a tmt.result.CheckResult and a CheckResult located within a result phase.

class tmt.result.SubResult(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, original_result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: list[str] = <factory>, log: list[~tmt._compat.pathlib.Path] = <factory>, start_time: str | None = None, end_time: str | None = None, duration: str | None = None, check: list[~tmt.result.SubCheckResult] = <factory>)

Bases: BaseResult

Describes what tmt knows about a single test subresult

check: list[SubCheckResult]
property failure_logs: list[Path]

Return paths to all failure logs from the result

tmt.result.results_to_exit_code(results: list[Result], execute_enabled: bool = True) int

Map results to a tmt exit code

tmt.result.save_failures(invocation: TestInvocation, directory: Path, failures: list[str]) Path

Save test failures to a file.

Parameters:
  • invocation – test invocation.

  • directory – directory to save the file in.

  • failures – list of failures to save.

tmt.trying module

Easily try tests and experiment with guests

class tmt.trying.Action(command: str, shortcut: str | None = None, order: int = 0, group: int = 0, exit_loop: bool = False, hidden: bool = False, prompt_function: Callable[[Try], None] | None = None)

Bases: object

Represents an registered action

command: str
property command_length: int

Calculate the command length in the menu including possible separate shortcut, e.g. ‘command [shortcut]’ in case the shortcut not matched in the command

exit_loop: bool
classmethod find(command: str) Action
func: Callable[[Try, Plan], None]
classmethod get_sorted_actions() list[Action]

Get unique actions sorted by group and order

group: int
help_text: str
hidden: bool
property longest_command_length: int

Calculate longest command in the menu including possible separate shortcut. Do not count the actions hidden in the menu.

property menu_item: str

Show menu with the keyboard shortcut highlighted if present. If the shortcut does not match string in the command, display it next to the command in square brackets.

order: int
prompt_function: Callable[[Try], None] | None
class tmt.trying.ActionMeta(name: str, supers: tuple[type, ...], attrdict: dict[str, Any])

Bases: type

Helper meta class to allow enum-like indexing

class tmt.trying.Try(*, tree: Tree, logger: Logger, **kwargs: Any)

Bases: Common

Just store the tree

action_cleanup(plan: Plan) None

Clean up guests and prune the workdir

action_debug(plan: Plan) None

Choose a different debugging level

action_discover(plan: Plan) None

Gather information about tests to be executed

action_execute(plan: Plan) None

Run tests using the specified executor

action_finish(plan: Plan) None

Perform the user defined finishing tasks

action_host(plan: Plan) None

Run command on the host

action_keep(plan: Plan) None

Exit the session but keep the run for later use

action_local_change_directory(plan: Plan) None

Change directory on the local host, discover tests there Use case(s): 1. Run the test you’re currently in

Raises:
action_login(plan: Plan) None

Log into the guest for experimenting

action_prepare(plan: Plan) None

Prepare the environment for testing

action_quit(plan: Plan) None

Clean up the run and quit the session

action_report(plan: Plan) None

Provide test results overview and send reports

action_start(plan: Plan) None

Common start actions

action_start_ask(plan: Plan) None

Ask what to do

action_start_login(plan: Plan) None

Start with login

action_start_test(plan: Plan) None

Start with testing

action_test(plan: Plan) None

Rediscover tests and execute them again

action_verbose(plan: Plan) None

Set the desired level of verbosity.

check_plans(run: Run) None

Check for plans to be used for testing

check_tests(directory: Path | None = None) None

Check for available tests

check_tree() None

Make sure there is a sane metadata tree

choose_action() Action

Print menu, get next action

cli_invocation: 'tmt.cli.CliInvocation' | None = None
get_default_plans(run: Run) list[Plan]

Get default plan from user config or the standard template

go() None

Run the interactive session

handle_epel(plan: Plan) None

Enable EPEL repository

handle_fips(plan: Plan) None

Enable FIPS mode

handle_install(plan: Plan) None

Install local rpm package on the guest.

handle_options(plan: Plan) None

Choose requested cli option

prompt_debug() None

Prompt for debug level.

prompt_verbose() None

Prompt for verbosity level.

save() None

Save list of selected plans and enabled steps

welcome() None

Welcome message with summary of what we’re going to try

Module contents

Test Management Tool