tmt package

Subpackages

Submodules

tmt.base module

Base Metadata Classes

class tmt.base.Clean(*, parent: Common | None = None, name: str | None = None, workdir: Literal[True] | Path | None = None, cli_invocation: tmt.cli.CliInvocation | None = None, logger: Logger)

Bases: Common

A class for cleaning up workdirs, guests or images

Initialize name and relation with the parent object

Always skip to initialize the work tree.

cli_invocation: 'tmt.cli.CliInvocation' | None = None
guests() bool

Clean guests of runs

images() bool

Clean images of provision plugins

runs() bool

Clean workdirs of runs

class tmt.base.Core(*, node: Tree, tree: Tree | None = None, parent: Common | None = None, logger: Logger, **kwargs: Any)

Bases: ValidateFmfMixin, LoadFmfKeysMixin, Common

General node object

Corresponds to given fmf.Tree node. Implements common Test, Plan and Story methods. Also defines L0 metadata and its manipulation.

Initialize the node

adjust: list[tmt.base._RawAdjustRule] | None
cli_invocation: 'tmt.cli.CliInvocation' | None = None
contact: list[str]
description: str | None = None
enabled: bool = True
property fmf_id: FmfId

Return full fmf identifier of the node

property fmf_root: Path
fmf_sources
classmethod from_tree(tree: Tree) list[T]

Gather list of instances of this class in a given tree.

Helpful when looking for objects of a class derived from Core in a given tree, encapsulating the mapping between core classes and tree search methods.

Parameters:

tree – tree to search for objects.

property git_root: Path | None

Whether object contains specified link

id: str | None = None
lint_summary_exists() Iterator[tuple[tmt.lint.LinterOutcome, str]]

C001: summary key should be set and should be reasonably long

lint_validate() Iterator[tuple[tmt.lint.LinterOutcome, str]]

C000: fmf node should pass the schema validation

ls(summary: bool = False) None

List node

name_and_summary() str

Node name and optional summary

order: int = 50
classmethod store_cli_invocation(context: tmt.cli.Context | None, options: dict[str, Any] | None = None) tmt.cli.CliInvocation

Save provided command line context for future use

summary: str | None = None
tag: list[str]
tier: str | None = None

Return a clickable web link to the fmf metadata location

class tmt.base.DependencyFile(type: str = 'file', pattern: list[str] = <factory>)

Bases: SpecBasedContainer[_RawDependencyFile, _RawDependencyFile], SerializableContainer, Exportable[DependencyFile]

VALID_KEYS: ClassVar[list[str]] = ['type', 'pattern']
classmethod from_spec(raw: _RawDependencyFile) DependencyFile

Convert from a specification file or from a CLI option

pattern: list[str]
to_dict() _RawDependencyFile

Return keys and values in the form of a dictionary

to_minimal_dict() _RawDependencyFile

Convert to a mapping with unset keys omitted

type: str = 'file'
static validate() tuple[bool, str]

Validate file dependency and return a human readable error

There is no way to check validity of type or pattern string at this time. Return a tuple (boolean, message) as the result of validation. The boolean specifies the validation result and the message the validation error. In case the file dependency is valid, return an empty string as the message.

class tmt.base.DependencyFmfId(fmf_root: Path | None = None, git_root: Path | None = None, default_branch: str | None = None, url: str | None = None, ref: str | None = None, path: Path | None = None, name: str | None = None, destination: Path | None = None, nick: str | None = None, type: str = 'library')

Bases: FmfId, SpecBasedContainer[_RawDependencyFmfId, _RawDependencyFmfId]

A fmf ID as a dependency.

Not a pure fmf ID though, the form accepted by require & co. allows several extra keys.

VALID_KEYS: ClassVar[list[str]] = ['url', 'ref', 'path', 'name', 'destination', 'nick', 'type']
destination: Path | None = None
classmethod from_spec(raw: _RawDependencyFmfId) DependencyFmfId

Convert from a specification file or from a CLI option

nick: str | None = None
to_dict() _RawDependencyFmfId

Return keys and values in the form of a dictionary

to_minimal_dict() _RawDependencyFmfId

Convert to a mapping with unset keys omitted

to_minimal_spec() _RawDependencyFmfId

Convert to specification, skip default values

to_spec() _RawDependencyFmfId

Convert to a form suitable for saving in a specification file

type: str = 'library'
class tmt.base.DependencySimple

Bases: str

A basic, simple dependency, usually a package

classmethod from_spec(spec: str) DependencySimple
to_minimal_spec() str
to_spec() str
class tmt.base.FmfId(fmf_root: tmt.utils.Path | None = None, git_root: tmt.utils.Path | None = None, default_branch: str | None = None, url: str | None = None, ref: str | None = None, path: tmt.utils.Path | None = None, name: str | None = None)

Bases: SpecBasedContainer[_RawFmfId, _RawFmfId], SerializableContainer, Exportable[FmfId]

NONEXPORTABLE_KEYS: ClassVar[list[str]] = ['fmf_root', 'git_root', 'default_branch']

Keys that are present, might be set, but shall not be exported.

VALID_KEYS: ClassVar[list[str]] = ['url', 'ref', 'path', 'name']
default_branch: str | None = None
fmf_root: Path | None = None
classmethod from_spec(raw: _RawFmfId) FmfId

Convert from a specification file or from a CLI option

git_root: Path | None = None
name: str | None = None
path: Path | None = None
ref: str | None = None
to_dict() _RawFmfId

Return keys and values in the form of a dictionary

to_minimal_dict() _RawFmfId

Convert to a mapping with unset keys omitted

to_minimal_spec() _RawFmfId

Convert to specification, skip default values

to_spec() _RawFmfId

Convert to a form suitable for saving in a specification file

url: str | None = None
validate() tuple[bool, str]

Validate fmf id and return a human readable error

Return a tuple (boolean, message) as the result of validation. The boolean specifies the validation result and the message the validation error. In case the FMF id is valid, return an empty string as the message.

Bases: SpecBasedContainer[Any, dict[Literal[‘verifies’, ‘verified-by’, ‘implements’, ‘implemented-by’, ‘documents’, ‘documented-by’, ‘blocks’, ‘blocked-by’, ‘duplicates’, ‘duplicated-by’, ‘parent’, ‘child’, ‘relates’, ‘test-script’, ‘note’], Union[str, _RawFmfId]]]

An internal “link” as defined by tmt specification.

All links, after entering tmt internals, are converted from their raw representation into instances of this class.

[1] https://tmt.readthedocs.io/en/stable/spec/core.html#link

DEFAULT_RELATIONSHIP: ClassVar[Literal['verifies', 'verified-by', 'implements', 'implemented-by', 'documents', 'documented-by', 'blocks', 'blocked-by', 'duplicates', 'duplicated-by', 'parent', 'child', 'relates', 'test-script', 'note']] = 'relates'
classmethod from_spec(spec: str | _RawFmfId | dict[Literal['verifies', 'verified-by', 'implements', 'implemented-by', 'documents', 'documented-by', 'blocks', 'blocked-by', 'duplicates', 'duplicated-by', 'parent', 'child', 'relates', 'test-script', 'note'], Union[str, tmt.base._RawFmfId]]) Link

Convert from a specification file or from a CLI option

Specification is described in [1], this constructor takes care of parsing it into a corresponding Link instance.

[1] https://tmt.readthedocs.io/en/stable/spec/core.html#link

note: str | None = None
relation: Literal['verifies', 'verified-by', 'implements', 'implemented-by', 'documents', 'documented-by', 'blocks', 'blocked-by', 'duplicates', 'duplicated-by', 'parent', 'child', 'relates', 'test-script', 'note']
target: str | FmfId
to_spec() dict[Literal['verifies', 'verified-by', 'implements', 'implemented-by', 'documents', 'documented-by', 'blocks', 'blocked-by', 'duplicates', 'duplicated-by', 'parent', 'child', 'relates', 'test-script', 'note'], Union[str, tmt.base._RawFmfId]]

Convert to a form suitable for saving in a specification file

No matter what the original specification was, every link will generate the very same type of specification, the relation: target one.

Output of this method is fully compatible with specification, and when given to from_spec(), it shall create a Link instance with the same properties as the original one.

[1] https://tmt.readthedocs.io/en/stable/spec/core.html#link

class tmt.base.LinkNeedle(relation: str = '.*', target: str = '.*')

Bases: object

A container to use for searching links.

relation and target fields hold regular expressions that are to be searched for in the corresponding fields of Link instances.

classmethod from_spec(value: str) LinkNeedle

Convert from a specification file or from a CLI option

Specification is described in [1], this constructor takes care of parsing it into a corresponding LinkNeedle instance.

[1] https://tmt.readthedocs.io/en/stable/spec/plans.html#fmf

matches(link: Link) bool

Find out whether a given link matches this needle

relation: str = '.*'
target: str = '.*'

Bases: SpecBasedContainer[Any, list[dict[Literal[‘verifies’, ‘verified-by’, ‘implements’, ‘implemented-by’, ‘documents’, ‘documented-by’, ‘blocks’, ‘blocked-by’, ‘duplicates’, ‘duplicated-by’, ‘parent’, ‘child’, ‘relates’, ‘test-script’, ‘note’], Union[str, _RawFmfId]]]]

Collection of links in tests, plans and stories.

Provides abstraction over the whole collection of object’s links.

[1] https://tmt.readthedocs.io/en/stable/spec/core.html#link

Create a collection from raw link data

get(relation: Literal['verifies', 'verified-by', 'implements', 'implemented-by', 'documents', 'documented-by', 'blocks', 'blocked-by', 'duplicates', 'duplicated-by', 'parent', 'child', 'relates', 'test-script', 'note'] | None = None) list[tmt.base.Link]

Get links with given relation, all by default

Check whether this set of links contains a matching link.

If needle is left unspecified, method would take all links into account, as if the needle was match all possible links (.*:.*). Method would then answer the question “are there any links at all?”

Parameters:

needle – if set, only links matching needle are considered. If not set, method considers all present links.

Returns:

True if there are matching links, False otherwise.

show() None

Format a list of links with their relations

to_spec() list[dict[Literal['verifies', 'verified-by', 'implements', 'implemented-by', 'documents', 'documented-by', 'blocks', 'blocked-by', 'duplicates', 'duplicated-by', 'parent', 'child', 'relates', 'test-script', 'note'], Union[str, tmt.base._RawFmfId]]]

Convert to a form suitable for saving in a specification file

No matter what the original specification was, every link will generate the very same type of specification, the relation: target one.

Output of this method is fully compatible with specification, and when used to instantiate Link() object, it shall create a collection of links with the same properties as the original one.

[1] https://tmt.readthedocs.io/en/stable/spec/core.html#link

tmt.base.Node

alias of Core

class tmt.base.Plan(*, node: Tree, tree: Tree | None = None, run: Run | None = None, skip_validation: bool = False, raise_on_validation_error: bool = False, logger: Logger, **kwargs: Any)

Bases: Core, Exportable[Plan], Lintable[Plan]

Plan object (L2 Metadata)

Initialize the plan

cli_invocation: 'tmt.cli.CliInvocation' | None = None
context: FmfContext
static create(*, names: list[str], template: str, path: Path, force: bool = False, dry: bool | None = None, logger: Logger) None

Create a new plan

draw_test_serial_number(test: Test) int
static edit_template(raw_content: str) str

Edit the default template with custom values

property environment: Environment

Return combined environment from plan data, command line and original plan

gate: list[str]
go() None

Execute the plan

header() None

Show plan name and summary

Include one blank line to separate plans

import_plan() Plan | None

Import plan from a remote repository, return a Plan instance

property is_remote_plan_reference: bool

Check whether the plan is a remote plan reference

lint_discover_unknown_method() Iterator[tuple[tmt.lint.LinterOutcome, str]]

P004: discover step methods must be known

lint_execute_not_defined() Iterator[tuple[tmt.lint.LinterOutcome, str]]

P002: execute step must be defined with “how”

lint_execute_unknown_method() Iterator[tuple[tmt.lint.LinterOutcome, str]]

P003: execute step methods must be known

lint_fmf_remote_ids_valid() Iterator[tuple[tmt.lint.LinterOutcome, str]]

P005: remote fmf ids must be valid

lint_phases_have_guests() Iterator[tuple[tmt.lint.LinterOutcome, str]]

P007: step phases require existing guests and roles

lint_unique_names() Iterator[tuple[tmt.lint.LinterOutcome, str]]

P006: phases must have unique names

lint_unknown_keys() Iterator[tuple[tmt.lint.LinterOutcome, str]]

P001: all keys are known

login: Login | None = None
static overview(tree: Tree) None

Show overview of available plans

plan_environment_file
prune() None

Remove all uninteresting files from the plan workdir

show() None

Show plan details

step_names(enabled_only: bool = True, skip: list[str] | None = None) Iterator[str]

Iterate over step names.

Parameters:
  • enabled_only – if set, only enabled steps would be listed.

  • skip – if step name is in this list, it would be skipped.

Yields:

step names.

steps(enabled_only: bool = True, skip: list[str] | None = None) Iterator[Step]

Iterate over steps.

Parameters:
  • enabled_only – if set, only enabled steps would be listed.

  • skip – if step name is in this list, it would be skipped.

Yields:

instance of tmt.step.Step, representing each step.

wake() None

Wake up all steps

class tmt.base.Run(*, id_: Path | None = None, tree: Tree | None = None, cli_invocation: tmt.cli.CliInvocation | None = None, parent: Common | None = None, logger: Logger)

Bases: Common

Test run, a container of plans

Initialize tree, workdir and plans

cli_invocation: 'tmt.cli.CliInvocation' | None = None
property environment: Environment

Return environment combined from wake up and command line

finish() None

Check overall results, return appropriate exit code

follow() None

Periodically check for new lines in the log.

go() None

Go and do test steps for selected plans

load() None

Load list of selected plans and enabled steps

load_from_workdir() None

Load the run from its workdir, do not require the root in run.yaml to exist. Doest not load the fmf tree.

Use only when the data in workdir is sufficient (e.g. tmt clean and status only require the steps to be loaded and their status).

property plans: list[tmt.base.Plan]

Test plans for execution

prepare_for_try(tree: Tree) None

Prepare the run for the try command

runner
save() None

Save list of selected plans and enabled steps

show_runner(logger: Logger) None

Log facts about the machine on which tmt runs

tree: Tree | None
class tmt.base.RunData(root: Optional[str], plans: Optional[list[str]], steps: list[str], remove: bool, environment: tmt.utils.Environment = <factory>)

Bases: SerializableContainer

environment: Environment
plans: list[str] | None
remove: bool
root: str | None
steps: list[str]
class tmt.base.Status(*, parent: CommonDerivedType | None = None, name: str | None = None, workdir: Literal[True] | Path | None = None, relative_indent: int = 1, cli_invocation: tmt.cli.CliInvocation | None = None, logger: Logger, **kwargs: Any)

Bases: Common

Status of tmt work directories.

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.

FIRST_COL_LEN = 11
LONGEST_STEP = 'provision'
cli_invocation: 'tmt.cli.CliInvocation' | None = None
static colorize_column(content: str) str

Add color to a status column

static get_overall_plan_status(plan: Plan) str

Examines the plan status (find the last done step)

classmethod pad_with_spaces(string: str) str

Append spaces to string to properly align the first column

plan_matches_filters(plan: Plan) bool

Check if the given plan matches filters from the command line

print_header() None

Print the header of the status table based on verbosity

print_plans_status(run: Run) None

Display the status of each plan of the given run

print_run_status(run: Run) None

Display the overall status of the run

print_verbose_status(run: Run) None

Display the status of each step of the given run

process_run(run: Run) None

Display the status of the given run based on verbosity

run_matches_filters(run: Run) bool

Check if the given run matches filters from the command line

show() None

Display the current status

class tmt.base.Story(*, node: Tree, tree: Tree | None = None, skip_validation: bool = False, raise_on_validation_error: bool = False, logger: Logger, **kwargs: Any)

Bases: Core, Exportable[Story], Lintable[Story]

User story object

Initialize the story

cli_invocation: 'tmt.cli.CliInvocation' | None = None
coverage(code: bool, test: bool, docs: bool) tuple[bool, bool, bool]

Show story coverage

static create(*, names: list[str], template: str, path: Path, force: bool = False, dry: bool | None = None, logger: Logger) None

Create a new story

property documented: list[tmt.base.Link]

Return links to relevant documentation

example: list[str]
classmethod from_tree(tree: Tree) list[tmt.base.Story]

Gather list of instances of this class in a given tree.

Helpful when looking for objects of a class derived from Core in a given tree, encapsulating the mapping between core classes and tree search methods.

Parameters:

tree – tree to search for objects.

property implemented: list[tmt.base.Link]

Return links to relevant source code

lint_story() Iterator[tuple[tmt.lint.LinterOutcome, str]]

S002: story key must be defined

lint_unknown_keys() Iterator[tuple[tmt.lint.LinterOutcome, str]]

S001: all keys are known

static overview(tree: Tree) None

Show overview of available stories

priority: StoryPriority | None = None
show() None

Show story details

property status: list[str]

Aggregate story status from implemented-, verified- and documented-by links

story: str | None = None
title: str | None = None
property verified: list[tmt.base.Link]

Return links to relevant test coverage

class tmt.base.StoryPriority(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

COULD_HAVE = 'could have'
MUST_HAVE = 'must have'
SHOULD_HAVE = 'should have'
WILL_NOT_HAVE = 'will not have'
class tmt.base.Test(*, node: Tree, tree: Tree | None = None, skip_validation: bool = False, raise_on_validation_error: bool = False, logger: Logger, **kwargs: Any)

Bases: Core, Exportable[Test], Lintable[Test]

Test object (L1 Metadata)

Initialize test data from an fmf node or a dictionary

The following two methods are supported:

Test(node)

check: list[tmt.checks.Check]
cli_invocation: 'tmt.cli.CliInvocation' | None = None
component: list[str]
static create(*, names: list[str], template: str, path: Path, script: str | None = None, force: bool = False, dry: bool | None = None, logger: Logger) None

Create a new test

duration: str = '5m'
enabled_on_guest(guest: Guest) bool

Check if the test is enabled on the specific guest

environment: Environment
framework: str = 'shell'
classmethod from_dict(*, mapping: dict[str, Any], name: str, skip_validation: bool = False, raise_on_validation_error: bool = False, logger: Logger, **kwargs: Any) Test

Initialize test data from a dictionary.

Useful when data describing a test are stored in a mapping instead of an fmf node.

lint_absolute_path() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T003: test directory path must be absolute

lint_defined_test() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T002: test script must be defined

lint_legacy_coverage_key() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T006: coverage has been obsoleted by link

lint_legacy_relevancy_rules() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T005: relevancy has been obsoleted by adjust

lint_manual_test_path_exists() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T007: manual test path is not an actual path

lint_manual_valid_markdown() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T008: manual test should be valid markdown

lint_path_exists() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T004: test directory path must exist

lint_require_type_field() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T009: require fields should have type field

lint_unknown_keys() Iterator[tuple[tmt.lint.LinterOutcome, str]]

T001: all keys are known

manual: bool = False
property manual_test_path: Path
static overview(tree: Tree) None

Show overview of available tests

path: Path | None = None
recommend: list[Union[tmt.base.DependencySimple, tmt.base.DependencyFmfId, tmt.base.DependencyFile]]
require: list[Union[tmt.base.DependencySimple, tmt.base.DependencyFmfId, tmt.base.DependencyFile]]
result: str = 'respect'
serial_number: int = 0
show() None

Show test details

test: ShellScript | None = None
property test_framework: type['TestFramework']
tty: bool = False
where: list[str]
class tmt.base.Tree(*, path: Path | None = None, tree: Tree | None = None, fmf_context: FmfContext | None = None, logger: Logger)

Bases: Common

Test Metadata Tree

Initialize tmt tree from directory path or given fmf tree

cli_invocation: 'tmt.cli.CliInvocation' | None = None
classmethod grow(*, path: Path | None = None, tree: Tree | None = None, fmf_context: FmfContext | None = None, logger: Logger | None = None) Tree

Initialize tmt tree from directory path or given fmf tree.

This method serves as an entry point for interactive use of tmt-as-a-library, providing sane defaults.

Warning

This method has a very limited use case, i.e. to help bootstrapping interactive tmt sessions. Using it anywhere outside of this scope should be ruled out.

static init(*, path: Path, template: str, force: bool, logger: Logger) None

Initialize a new tmt tree, optionally with a template

plans(logger: Logger | None = None, keys: list[str] | None = None, names: list[str] | None = None, filters: list[str] | None = None, conditions: list[str] | None = None, run: Run | None = None, links: list[tmt.base.LinkNeedle] | None = None, excludes: list[str] | None = None) list[tmt.base.Plan]

Search available plans

property root: Path | None

Metadata root

sanitize_cli_names(names: list[str]) list[str]

Sanitize CLI names in case name includes control character

stories(logger: Logger | None = None, keys: list[str] | None = None, names: list[str] | None = None, filters: list[str] | None = None, conditions: list[str] | None = None, whole: bool = False, links: list[tmt.base.LinkNeedle] | None = None, excludes: list[str] | None = None) list[tmt.base.Story]

Search available stories

tests(logger: Logger | None = None, keys: list[str] | None = None, names: list[str] | None = None, filters: list[str] | None = None, conditions: list[str] | None = None, unique: bool = True, links: list[tmt.base.LinkNeedle] | None = None, excludes: list[str] | None = None) list[tmt.base.Test]

Search available tests

property tree: Tree

Initialize tree only when accessed

tmt.base.assert_simple_dependencies(dependencies: list[Union[tmt.base.DependencySimple, tmt.base.DependencyFmfId, tmt.base.DependencyFile]], error_message: str, logger: Logger) list[tmt.base.DependencySimple]

Make sure the list of dependencies consists of simple ones.

Parameters:
  • dependencies – the list of requires.

  • error_message – used for a raised exception.

  • logger – used for logging.

Raises:

GeneralError – when there is a dependency on the list which is not a subclass of tmt.base.DependencySimple.

tmt.base.create_adjust_callback(logger: Logger) AdjustCallback

Create a custom callback for fmf’s adjust.

Given the adjust rules are applied on many places, for proper logging they need their own specific logger. Create a callback closure with the given logger.

tmt.base.dependency_factory(raw_dependency: str | _RawDependencyFmfId | _RawDependencyFile | None) DependencySimple | DependencyFmfId | DependencyFile

Select the correct require class

tmt.base.expand_node_data(data: T, fmf_context: FmfContext) T

Recursively expand variables in node data

tmt.base.normalize_require(key_address: str, raw_require: str | _RawDependencyFmfId | _RawDependencyFile | list[Union[str, tmt.base._RawDependencyFmfId, tmt.base._RawDependencyFile]] | None, logger: Logger) list[Union[tmt.base.DependencySimple, tmt.base.DependencyFmfId, tmt.base.DependencyFile]]

Normalize content of require key.

The requirements may be defined as either string or a special fmf id flavor, or a mixed list of these types. The goal here is to reduce the space of possibilities to a list, with fmf ids being converted to their internal representation.

tmt.base.resolve_dynamic_ref(*, workdir: Path, ref: str | None, plan: Plan | None = None, logger: Logger) str | None

Get the final value for the dynamic reference

Returns original ref if the dynamic referencing isn’t used. Plan is used for context and environment expansion to process reference. Common instance is used for appropriate logging.

tmt.cli module

Command line interface for the Test Management Tool

class tmt.cli.CliInvocation(context: Context | None, options: dict[str, Any])

Bases: object

A single CLI invocation of a tmt subcommand.

Bundles together the Click context and options derived from it. A context alone might be good enough, but sometimes tmt needs to modify saved options. For custom command line options injected manually ‘sources’ is used to keep the parameter source.

Serves as a clear boundary between invocations of classes representing various tmt subcommands and groups.

context: Context | None
classmethod from_context(context: Context) CliInvocation
classmethod from_options(options: dict[str, Any]) CliInvocation

Inject custom options coming from the command line

option_sources
options: dict[str, Any]
class tmt.cli.Context(command: Command, parent: Context | None = None, info_name: str | None = None, obj: Any | None = None, auto_envvar_prefix: str | None = None, default_map: MutableMapping[str, Any] | None = None, terminal_width: int | None = None, max_content_width: int | None = None, resilient_parsing: bool = False, allow_extra_args: bool | None = None, allow_interspersed_args: bool | None = None, ignore_unknown_options: bool | None = None, help_option_names: List[str] | None = None, token_normalize_func: Callable[[str], str] | None = None, color: bool | None = None, show_default: bool | None = None)

Bases: Context

Custom click.Context-like class for typing purposes.

Objects of this class are never instantiated, it serves only as a type stub in commands below, to simplify handling and static analysis of context.obj. There is no added functionality, the only change is a much narrower type of obj attribute.

This class shall be used instead of the original click.Context. Click is obviously not aware of our type annotations, and context objects managed by Click would always be of type click.Context, we would just convince mypy their obj attribute is no longer Any.

max_content_width: int | None

The maximum width of formatted content (None implies a sensible default which is 80 for most things).

obj: ContextObject

the user object stored.

class tmt.cli.ContextObject(cli_context: ~tmt.cli.Context, logger: ~tmt.log.Logger, common: ~tmt.utils.Common, fmf_context: ~tmt.utils.FmfContext, tree: ~tmt.base.Tree, steps: set[str] = <factory>, clean: ~tmt.base.Clean | None = None, clean_logger: ~tmt.log.Logger | None = None, clean_partials: ~collections.defaultdict[str, list[typing.Callable[[], bool]]] = <factory>, run: ~tmt.base.Run | None = None)

Bases: object

Click Context Object container.

In Click terms, this is “an arbitrary object of user data.” In this container, tmt CLI code stores all structures relevant for the command execution. The container itself is then attached to click.Context object Click manages across commands.

clean: Clean | None = None
clean_logger: Logger | None = None
clean_partials: defaultdict[str, list[Callable[[], bool]]]
cli_context: Context
common: Common
fmf_context: FmfContext
logger: Logger
run: Run | None = None
steps: set[str]
tree: Tree
class tmt.cli.CustomGroup(name: str | None = None, commands: MutableMapping[str, Command] | Sequence[Command] | None = None, **attrs: Any)

Bases: Group

Custom Click Group

get_command(context: Context, cmd_name: str) Command | None

Allow command shortening

list_commands(context: Context) list[str]

Prevent alphabetical sorting

class tmt.cli.HelpFormatter(indent_increment: int = 2, width: int | None = None, max_width: int | None = None)

Bases: HelpFormatter

Custom help formatter capable of rendering ReST syntax

write_dl(rows: Sequence[tuple[str, str]], col_max: int = 30, col_spacing: int = 2) None

Writes a definition list into the buffer. This is how options and commands are usually formatted.

Parameters:
  • rows – a list of two item tuples for the terms and values.

  • col_max – the maximum width of the first column.

  • col_spacing – the number of spaces between the first and second column.

class tmt.cli.TmtExitCode(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: IntEnum

ALL_TESTS_SKIPPED = 4

Tests were executed, and all reported the skip result.

ERROR = 2

Errors occured during test execution.

FAIL = 1

There was a fail or warn identified, but no error.

NO_RESULTS_FOUND = 3

No test results found.

SUCCESS = 0

At least one test passed, there was no fail, warn or error.

tmt.cli.do_lint(context: Context, klasses: list[Union[type[tmt.base.Test], type[tmt.base.Plan], type[tmt.base.Story]]], list_checks: bool, failed_only: bool, enable_checks: list[str], disable_checks: list[str], enforce_checks: list[str], outcomes: list[tmt.lint.LinterOutcome], **kwargs: Any) int

Core of all lint commands

tmt.cli.finito(click_context: Context, commands: Any, *args: Any, **kwargs: Any) None

Run tests if run defined

tmt.cli.pass_context(fn: Callable[Concatenate[Context, P], R]) Callable[P, R]

Custom click.pass_context()-like decorator.

Complementing the Context, the goal of this decorator to announce the correct type of the context parameter. The original decorator annotates the parameter as click.Context, but that is not what our command callables accept. So, on this boundary between tmt code and click API, we trick type checkers by isolating the necessary type: ignore[arg-type].

tmt.cli.perform_clean(click_context: Context, commands: Any, *args: Any, **kwargs: Any) None

Perform clean actions in the correct order.

We need to ensure that guests are always cleaned before the run workdirs even if the user specified them in reverse order.

tmt.cli.setup_completion(shell: str, install: bool) None

Setup completion based on the shell

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.hardware module

Guest hardware requirements specification and helpers.

tmt metadata allow to describe various HW requirements a guest needs to satisfy. This package provides useful functions and classes for core functionality and shared across provision plugins.

Parsing of HW requirements

Set of HW requirements, as given by test or plan metadata, is represented by Python structures - lists, mappings, primitive types - when loaded from fmf files. Part of the code below converts this representation to a tree of objects that provide helpful operations for easier evaluation and processing of HW requirements.

Each HW requirement “rule” in original metadata is a constraint, a condition the eventual guest HW must satisfy. Each node of the tree created from HW requirements is therefore called “a constraint”, and represents either a single condition (“trivial” constraints), or a set of such conditions plus a function reducing their individual outcomes to one final answer for the whole set (think any() and all() built-in functions) (“compound” constraints). Components of each constraint - dimension, operator, value, units - are decoupled from the rest, and made available for inspection.

[1] https://tmt.readthedocs.io/en/latest/spec/plans.html#hardware

class tmt.hardware.And(constraints: list[tmt.hardware.BaseConstraint] | None = None)

Bases: CompoundConstraint

Represents constraints that are grouped in and fashion.

Hold constraints that are grouped in and fashion.

Parameters:

constraints – list of constraints to group.

variants(members: list[tmt.hardware.Constraint[Any]] | None = None) Iterator[list[tmt.hardware.Constraint[Any]]]

Generate all distinct variants of constraints covered by this one.

Since the and reducer demands all child constraints must be satisfied, and some of these constraints can also be compound constraints, we need to construct a cartesian product of variants yielded by child constraints to include all possible combinations.

Parameters:

members – if specified, each variant generated by this method is prepended with this list.

Yields:

iterator over all variants.

class tmt.hardware.BaseConstraint

Bases: SpecBasedContainer[Any, Any]

Base class for all classes representing one or more constraints.

classmethod from_spec(spec: Any) BaseConstraint

Convert from a specification file or from a CLI option

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

See to_spec() for its counterpart.

to_minimal_spec() Any

Convert to specification, skip default values

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

See from_spec() for its counterpart.

to_spec() Any

Convert to a form suitable for saving in a specification file

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

See from_spec() for its counterpart.

uses_constraint(constraint_name: str, logger: Logger) bool

Inspect constraint whether the constraint or one of its children use a constraint of a given name.

Parameters:
  • constraint_name – constraint name to look for.

  • logger – logger to use for logging.

Raises:

NotImplementedError – method is left for child classes to implement.

variant() list[tmt.hardware.Constraint[Any]]

Pick one of the available variants of this contraints.

As the contraint can yield many variants, often there’s an interest in just one. There can be many different ways for picking the best one, whatever that may mean depending on the context, as a starting point this method is provided. In the future, provision plugins would probably use their own guessing to pick the most suitable variant.

variants(members: list[tmt.hardware.Constraint[Any]] | None = None) Iterator[list[tmt.hardware.Constraint[Any]]]

Generate all distinct variants of constraints covered by this one.

For a trivial constraint, there is only one variant, and that is the constraint itself. In the case of compound constraints, the number of variants would be bigger, depending on the constraint’s reducer.

Parameters:

members – if specified, each variant generated by this method is prepended with this list.

Yields:

iterator over all variants.

tmt.hardware.CONSTRAINT_COMPONENTS_PATTERN = re.compile('\n    ^                                   # must match the whole string\n    (?P<name>[a-z_+]+)                  # constraint name is mandatory\n    (?:\\[(?P<peer_index>[+-]?\\d+)\\])?   # index is , re.VERBOSE)

Regular expression to match and split a HW constraint into its components. The input consists of a constraint name, (optional) index of the constraint among its peers, (optional) child constraint name, (optional) operator, and value.

  • memory 10 GiB => memory, None, None, None, 10 GiB

  • cpu.processors != 4 => cpu, None, processors, !=, 4

  • disk[1].size <= 1 TiB => disk, 1, size, <=, 1 TiB

tmt.hardware.CONSTRAINT_NAME_PATTERN = re.compile("\n    (?P<name>[a-z_+]+)                   # constraint name is mandatory\n    (?:\\[(?P<peer_index>[+-]?\\d+)\\])?    # index is optional\n    (?:\\.(?P<child_name>[a-z_]+))?       # child constrain, re.VERBOSE)

Regular expression to match and split a HW constraint name into its components. The input consists of a constraint name, (optional) index of the constraint among its peers, and (optional) child constraint name:

  • memory => memory, None, None

  • cpu.processors => cpu, None, processors

  • disk[1].size => disk, 1, size

tmt.hardware.CONSTRAINT_VALUE_PATTERN = re.compile('\n    ^                                   # must match the whole string\n    (?P<operator>==|!=|~|!~|=~|=|>=|>|<=|<)?  # optional operator\n    \\s*                                 # operator might b, re.VERBOSE)

Regular expression to match and split the value part of a key:value pair. The input consists of an (optional) operator, the actual value of the constraint, and (optional) units. As a result, pattern yields two groups, operator and value, the latter containing both the value and units.

class tmt.hardware.CompoundConstraint(reducer: ~typing.Callable[[~collections.abc.Iterable[bool]], bool] = <built-in function any>, constraints: list[tmt.hardware.BaseConstraint] | None = None)

Bases: BaseConstraint

Base class for all compound constraints.

Construct a compound constraint, constraint imposed to more than one dimension.

Parameters:
  • reducer – a callable reducing a list of results from child constraints into the final answer.

  • constraints – child contraints.

property size: int
to_spec() Any

Convert to a form suitable for saving in a specification file

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

See from_spec() for its counterpart.

uses_constraint(constraint_name: str, logger: Logger) bool

Inspect constraint whether it or its children use a constraint of a given name.

Parameters:
  • constraint_name – constraint name to look for.

  • logger – logger to use for logging.

Returns:

True if the given constraint or its children use given constraint name.

variants(members: list[tmt.hardware.Constraint[Any]] | None = None) Iterator[list[tmt.hardware.Constraint[Any]]]

Generate all distinct variants of constraints covered by this one.

Since the and reducer demands all child constraints must be satisfied, and some of these constraints can also be compound constraints, we need to construct a cartesian product of variants yielded by child constraints to include all possible combinations.

Parameters:

members – if specified, each variant generated by this method is prepended with this list.

Yields:

iterator over all variants.

Raises:

NotImplementedError – default implementation is left undefined for compound constraints.

class tmt.hardware.Constraint(name: str, operator: Operator, operator_handler: Callable[[Any, Any], bool], value: ConstraintValueT, raw_value: str, unit: str | None = None, original_constraint: Constraint[Any] | None = None)

Bases: BaseConstraint, Generic[ConstraintValueT]

A constraint imposing a particular limit to one of the guest properties.

change_operator(operator: Operator) None

Change operator of this constraint to a given one.

Parameters:

operator – new operator.

expand_name() ConstraintNameComponents

Expand constraint name into its components.

Returns:

tuple consisting of constraint name components: name, optional indices, child properties, etc.

name: str
operator: Operator
operator_handler: Callable[[Any, Any], bool]
original_constraint: Constraint[Any] | None = None
property printable_name: str
raw_value: str
to_spec() Any

Convert to a form suitable for saving in a specification file

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

See from_spec() for its counterpart.

unit: str | None = None
uses_constraint(constraint_name: str, logger: Logger) bool

Inspect constraint whether it or its children use a constraint of a given name.

Parameters:
  • constraint_name – constraint name to look for.

  • logger – logger to use for logging.

Returns:

True if the given constraint or its children use given constraint name.

value: ConstraintValueT
variants(members: list[tmt.hardware.Constraint[ConstraintValueT]] | None = None) Iterator[list[tmt.hardware.Constraint[ConstraintValueT]]]

Generate all distinct variants of constraints covered by this one.

For a trivial constraint, there is only one variant, and that is the constraint itself. In the case of compound constraints, the number of variants would be bigger, depending on the constraint’s reducer.

Parameters:

members – if specified, each variant generated by this method is prepended with this list.

Yields:

iterator over all variants.

class tmt.hardware.ConstraintComponents(name: str, peer_index: int | None, child_name: str | None, operator: str | None, value: str)

Bases: object

Components of a constraint.

child_name: str | None
classmethod from_spec(spec: str) ConstraintComponents
name: str
operator: str | None
peer_index: int | None
value: str
class tmt.hardware.ConstraintNameComponents(name: str, peer_index: int | None, child_name: str | None)

Bases: NamedTuple

Components of a constraint name.

Create new instance of ConstraintNameComponents(name, peer_index, child_name)

child_name: str | None

size of disk[1].size

name: str

disk of disk[1].size

peer_index: int | None

1 of disk[1].size

tmt.hardware.ConstraintValue

A type of constraint values.

alias of Union[int, Size, str, bool]

class tmt.hardware.FlagConstraint(name: str, operator: Operator, operator_handler: Callable[[Any, Any], bool], value: ConstraintValueT, raw_value: str, unit: str | None = None, original_constraint: Constraint[Any] | None = None)

Bases: Constraint[bool]

A constraint representing a boolean flag, enabled/disabled, has/has not, etc.

classmethod from_specification(name: str, raw_value: bool, original_constraint: Constraint[Any] | None = None, allowed_operators: list[tmt.hardware.Operator] | None = None) T
class tmt.hardware.Hardware(constraint: tmt.hardware.BaseConstraint | None, spec: Any)

Bases: SpecBasedContainer[Any, Any]

and_(constraint: BaseConstraint) None
constraint: BaseConstraint | None
format_variants() Iterator[str]

Format variants of constraints.

Yields:

for each variant, which is nothing but a list of constraints, method yields a string variant’s serial number and formatted constraints.

classmethod from_spec(spec: Any) Hardware

Convert from a specification file or from a CLI option

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

See to_spec() for its counterpart.

report_support(*, names: list[str] | None = None, check: Callable[[Constraint[Any]], bool] | None = None, logger: Logger) None

Report all unsupported constraints.

A helper method for plugins: plugin provides a callback which checks whether a given constraint is or is not supported by the plugin, and method calls the callback for each constraint stored in this container.

Both names and check are optional, and both can be used and combined. First, the names list is checked, if a constraint is not found, check is called if it’s defined.

Parameters:
  • names – a list of constraint names. If a constraint name is on this list, it is considered to be supported by the report_support caller. Caller may list both full constraint name, e.g. cpu.cores, or just the subsystem name, cpu, indicating all child constraints are supported.

  • check – a callback to call for each constraint in this container. Accepts a single parameter, a constraint to check, and if its return value is true-ish, the constraint is considered to be supported by the report_support caller.

spec: Any
to_minimal_spec() Any

Convert to specification, skip default values

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

See from_spec() for its counterpart.

to_spec() Any

Convert to a form suitable for saving in a specification file

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

See from_spec() for its counterpart.

class tmt.hardware.NumberConstraint(name: str, operator: Operator, operator_handler: Callable[[Any, Any], bool], value: ConstraintValueT, raw_value: str, unit: str | None = None, original_constraint: Constraint[Any] | None = None)

Bases: Constraint[int]

A constraint representing a dimension-less number

classmethod from_specification(name: str, raw_value: str, original_constraint: Constraint[Any] | None = None, allowed_operators: list[tmt.hardware.Operator] | None = None) T
class tmt.hardware.Operator(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

Binary operators defined by specification.

CONTAINS = 'contains'
EQ = '=='
GT = '>'
GTE = '>='
LT = '<'
LTE = '<='
MATCH = '~'
NEQ = '!='
NOTCONTAINS = 'not contains'
NOTMATCH = '!~'
class tmt.hardware.Or(constraints: list[tmt.hardware.BaseConstraint] | None = None)

Bases: CompoundConstraint

Represents constraints that are grouped in or fashion.

Hold constraints that are grouped in or fashion.

Parameters:

constraints – list of constraints to group.

variants(members: list[tmt.hardware.Constraint[Any]] | None = None) Iterator[list[tmt.hardware.Constraint[Any]]]

Generate all distinct variants of constraints covered by this one.

Since the any reducer allows any child constraints to be satisfied for the whole group to evaluate as True, it is trivial to generate variants - each child constraint shall provide its own “branch”, and there is no need for products or joins of any kind.

Parameters:

members – if specified, each variant generated by this method is prepended with this list.

Yields:

iterator over all variants.

exception tmt.hardware.ParseError(constraint_name: str, raw_value: str, message: str | None = None)

Bases: MetadataError

Raised when HW requirement parsing fails.

Raise when HW requirement parsing fails.

Parameters:
  • constraint_name – name of the constraint that caused issues.

  • raw_value – original raw value.

  • message – optional error message.

tmt.hardware.ReducerType

A callable reducing a sequence of booleans to a single one. Think any() or all().

alias of Callable[[Iterable[bool]], bool]

class tmt.hardware.SizeConstraint(name: str, operator: Operator, operator_handler: Callable[[Any, Any], bool], value: ConstraintValueT, raw_value: str, unit: str | None = None, original_constraint: Constraint[Any] | None = None)

Bases: Constraint[Size]

A constraint representing a size of resource, usually a storage

classmethod from_specification(name: str, raw_value: str, original_constraint: Constraint[Any] | None = None, allowed_operators: list[tmt.hardware.Operator] | None = None) T
class tmt.hardware.TextConstraint(name: str, operator: Operator, operator_handler: Callable[[Any, Any], bool], value: ConstraintValueT, raw_value: str, unit: str | None = None, original_constraint: Constraint[Any] | None = None)

Bases: Constraint[str]

A constraint representing a string, e.g. a name

classmethod from_specification(name: str, raw_value: str, original_constraint: Constraint[Any] | None = None, allowed_operators: list[tmt.hardware.Operator] | None = None) T
tmt.hardware.UNITS = <pint.registry.UnitRegistry object>

Unit registry, used and shared by all code.

tmt.hardware.match(text: str, pattern: str) bool

Match a text against a given regular expression.

Parameters:
  • text – string to examine.

  • pattern – regular expression.

Returns:

True if pattern matches the string.

tmt.hardware.not_contains(haystack: list[str], needle: str) bool

Find out whether an item is in the given list.

Note

Opposite of operator.contains().

Parameters:
  • haystack – container to examine.

  • needle – item to look for in haystack.

Returns:

True if needle is not in haystack.

tmt.hardware.not_match(text: str, pattern: str) bool

Match a text against a given regular expression.

Parameters:
  • text – string to examine.

  • pattern – regular expression.

Returns:

True if pattern does not matche the string.

tmt.hardware.parse_hw_requirements(spec: Any) BaseConstraint

Convert raw specification of HW constraints to our internal representation.

Parameters:

spec – raw constraints specification as stored in an environment.

Returns:

root of HW constraints tree.

tmt.hardware.ungroupify(fn: Callable[[Any], BaseConstraint]) Callable[[Any], BaseConstraint]

Swap returned single-child compound constraint and that child.

Helps reduce the number of levels in the contraint tree: if the return value is a compound constraint which contains just a single child, return the child instead of the compound constraint.

Meant for constraints that do not have an index, e.g. memory or cpu. For indexable constraints, see ungroupify_indexed().

tmt.hardware.ungroupify_indexed(fn: Callable[[Any, int], BaseConstraint]) Callable[[Any, int], BaseConstraint]

Swap returned single-child compound constraint and that child.

Helps reduce the number of levels in the contraint tree: if the return value is a compound constraint which contains just a single child, return the child instead of the compound constraint.

Meant for constraints that have an index, e.g. disk or network. For non-indexable constraints, see ungroupify().

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.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 ``[CTPS]\d\d\d`` regular expression:
    # ``C``ommon, ``T``est, ``P``lan, ``S``tory, 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[tmt.lint.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[tmt.lint.Linter] | None = None) tuple[bool, list[tuple[tmt.lint.Linter, tmt.lint.LinterOutcome, tmt.lint.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[tmt.lint.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[tmt.lint.LinterOutcome, str]]])

Bases: object

A single linter

callback: Callable[[Lintable], Iterator[tuple[tmt.lint.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(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

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[tmt.lint.Linter, tmt.lint.LinterOutcome, tmt.lint.LinterOutcome, str]], outcomes: list[tmt.lint.LinterOutcome] | None = None) Iterator[tuple[tmt.lint.Linter, tmt.lint.LinterOutcome, tmt.lint.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[tmt.lint.Linter, tmt.lint.LinterOutcome, tmt.lint.LinterOutcome, str]]) 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 | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: str | None = 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)

Bases: object

tmt’s log message components attached to log records

color: str | None = 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[tmt.log.Topic]
logger_verbosity_level: int = 0
message_debug_level: int | None = None
message_topic: Topic | None = None
message_verbosity_level: int | None = None
shift: int = 0
value: str | 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.

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[tmt.log.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 supressed, 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

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 | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: str | None = None, shift: int = 0, level: int = 1, topic: Topic | None = None) 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 betwen 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) 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.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 | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: str | None = None, shift: int = 0) None
property labels_span: int

Length of rendered labels

print(text: str, color: str | None = None, shift: int = 0) None
verbose(key: str, value: str | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: str | None = None, shift: int = 0, level: int = 1, topic: Topic | None = None) None
warn(message: str, shift: int = 0) None
class tmt.log.LoggingFunction(*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.Topic(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

ADJUST_DECISIONS = 'adjust-decisions'
CLI_INVOCATIONS = 'cli-invocations'
COMMAND_EVENTS = 'command-events'
HELP_RENDERING = 'help-rendering'
KEY_NORMALIZATION = 'key-normalization'
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 | int | bool | float | tmt.utils.Environment | tmt.utils.FmfContext | tmt.utils.Path | tmt.utils.Command | tmt.utils.ShellScript | None = None, color: str | None = 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
tmt.options.create_method_class(methods: dict[str, click.core.Command]) type[click.core.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, 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.options.show_step_method_hints(step_name: str, how: str, logger: Logger) None

Show hints about available step methods’ installation

The logger will be used to output the hints to the terminal, hence it must be an instance of a subclass of tmt.utils.Common (info method must be available).

tmt.queue module

class tmt.queue.GuestlessTask(logger: Logger, **kwargs: Any)

Bases: Task[TaskResultT]

A task not assigned to a particular set of guests.

An extension of the Task class, provides a quite generic wrapper for the actual task which takes care of catching exceptions and proper reporting.

go() Iterator[Self]

Perform the task.

Called by Queue machinery to accomplish the task. It expects the child class would implement run(), with go taking care of task/queue interaction.

Yields:

since the task is not expected to run on multiple guests, only a single instance of the class is yielded to describe the task and its outcome.

run(logger: Logger) TaskResultT

Perform the task.

Called once from go(). Subclasses of GuestlessTask should implement their logic in this method rather than in go() which is already provided. If your task requires different handling in go, it might be better derived directly from Task.

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

Bases: Task[TaskResultT]

A task assigned to a particular set of guests.

An extension of the Task class, provides a quite generic wrapper for the actual task which takes care of catching exceptions and proper reporting.

go() Iterator[Self]

Perform the task.

Called by Queue machinery to accomplish the task. It expects the child class would implement run(), with go taking care of task/queue interaction.

Yields:

instances of the same class, describing invocations of the task and their outcome. For each guest, one instance would be yielded.

guest_ids
guests: list['Guest']
run_on_guest(guest: Guest, logger: Logger) None

Perform the task.

Called from go() once for every guest to run on. Subclasses of GuestlessTask should implement their logic in this method rather than in go() which is already provided. If your task requires different handling in go, it might be better derived directly from Task.

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

Bases: list[TaskT]

Queue class for running tasks

enqueue_task(task: TaskT) None

Put new task into a queue

run() Iterator[TaskT]

Start crunching the queued tasks.

Tasks are executed in the order, for each task/guest combination a Task instance is yielded.

class tmt.queue.Task(logger: Logger, **kwargs: Any)

Bases: Generic[TaskResultT]

A base class for queueable actions.

The class provides not just the tracking, but the implementation of the said action as well. Child classes must implement their action functionality in go().

Note

This class and its subclasses must provide their own __init__ methods, and cannot rely on dataclasses generating one. This is caused by subclasses often adding fields without default values, and dataclasses module does not allow non-default fields to be specified after those with default values. Therefore initialize fields to their defaults “manually”.

exc: Exception | None

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

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.

guest: Guest | None

Guest on which the phase was executed. May be unset, some tasks may handle multiguest actions on their own.

logger: Logger

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

property name: str

A name of this task.

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

requested_exit: SystemExit | None

If set, the task raised SystemExit exception, and wants to terminate the run completely.

result: TaskResultT | None
tmt.queue.prepare_loggers(logger: Logger, labels: list[str]) dict[str, tmt.log.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.result module

class tmt.result.BaseResult(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: str | None = None, log: list[tmt.utils.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
log: list[tmt.utils.Path]
name: str
note: str | None = None
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, note: str | None = None, log: list[tmt.utils.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'
class tmt.result.Result(name: str, result: ~tmt.result.ResultOutcome = ResultOutcome.PASS, note: str | None = None, log: list[tmt.utils.Path] = <factory>, start_time: str | None = None, end_time: str | None = None, duration: str | None = None, serial_number: int = 0, fmf_id: ~tmt.base.FmfId | None = None, context: ~tmt.utils.FmfContext = <factory>, ids: dict[str, typing.Optional[str]] = <factory>, guest: ~tmt.result.ResultGuestData = <factory>, check: list[tmt.result.CheckResult] = <factory>, data_path: ~tmt.utils.Path | None = None)

Bases: BaseResult

Describes what tmt knows about a single test result

check: list[tmt.result.CheckResult]
context: FmfContext
data_path: Path | None = None
static failures(log: str | None, msg_type: str = 'FAIL') str

Filter stdout and get only messages with certain type

fmf_id: FmfId | None = None
classmethod from_test_invocation(*, invocation: TestInvocation, result: ResultOutcome, note: str | None = None, ids: dict[str, Optional[str]] | None = None, log: list[tmt.utils.Path] | 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, Optional[str]]
interpret_result(interpret: ResultInterpret) 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.

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)

static summary(results: list[tmt.result.Result]) str

Prepare a nice human summary of provided results

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

Return dictionary with total stats for given results

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

Bases: SerializableContainer

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

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

A type of collection IDs tracked for a single result.

alias of dict[str, Optional[str]]

class tmt.result.ResultInterpret(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

CUSTOM = 'custom'
ERROR = 'error'
FAIL = 'fail'
INFO = 'info'
PASS = 'pass'
RESPECT = 'respect'
SKIP = 'skip'
WARN = 'warn'
XFAIL = 'xfail'
classmethod is_result_outcome(value: ResultInterpret) bool
class tmt.result.ResultOutcome(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

ERROR = 'error'
FAIL = 'fail'
INFO = 'info'
PASS = 'pass'
SKIP = 'skip'
WARN = 'warn'
classmethod from_spec(spec: str) ResultOutcome
tmt.result.results_to_exit_code(results: list[tmt.result.Result]) int

Map results to a tmt exit code

tmt.trying module

Easily try tests and experiment with guests

class tmt.trying.Action(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

Available actions and their keyboard shortcuts

DEBUG = ('b', 'choose a different debugging level')
DISCOVER = ('d', 'gather information about tests to be executed')
EXECUTE = ('e', 'run tests using the specified executor')
FINISH = ('f', 'perform the finishing tasks, clean up guests')
KEEP = ('k', 'exit the session but keep the run for later use')
LOGIN = ('l', 'log into the guest for experimenting')
PREPARE = ('p', 'prepare the environment for testing')
QUIT = ('q', 'clean up the run and quit the session')
REPORT = ('r', 'provide test results overview and send reports')
START_ASK = ('-', 'do nothing without first asking the user')
START_LOGIN = ('-', 'jump directly to login after start')
START_TEST = ('-', 'start directly with executing detected tests')
TEST = ('t', 'rediscover tests and execute them again')
VERBOSE = ('v', 'set the desired level of verbosity')
property action: str

Action name in lower case

property description: str

Action description

classmethod find(key: str) Action

Return action for given keyboard shortcut

property key: str

Keyboard shortcut

property menu: str

Show menu with the keyboard shortcut highlighted

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

Bases: Common

Just store the tree

action_debug(plan: Plan) None

Set verbosity level of all loggers in given plan

action_discover(plan: Plan) None

Discover tests

action_execute(plan: Plan) None

Execute tests

action_finish(plan: Plan) None

Clean up guests and finish

action_keep(plan: Plan) None

Keep run and exit the session

action_login(plan: Plan) None

Log into the guest

action_prepare(plan: Plan) None

Prepare the guest

action_quit(plan: Plan) None

Clean up the run and quit the session

action_report(plan: Plan) None

Report results

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

Test again

action_verbose(plan: Plan) None

Set verbosity level of all loggers in given plan

check_plans(run: Run) None

Check for plans to be used for testing

check_tests() 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[tmt.base.Plan]

Get default plan from user config or the standard template

go() None

Run the interactive session

prompt_debug() None

Choose the right debug level

prompt_verbose() None

Ask for the desired verbosity level

welcome() None

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

tmt.utils module

Test Metadata Utilities

exception tmt.utils.BackwardIncompatibleDataError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

A backward incompatible data cannot be processed

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.CentOSDistGit

Bases: DistGitHandler

CentOS Handler

lookaside_server: str = 'https://sources.stream.centos.org/sources'
re_source: Pattern[str] = re.compile('^(\\w+) \\(([^)]+)\\) = ([0-9a-fA-F]+)$')
remote_substring: Pattern[str] = re.compile('redhat/centos')
usage_name: str = 'centos'
class tmt.utils.Command(*elements: str | Path)

Bases: object

A command with its arguments.

run(*, cwd: Path | None, shell: bool = False, env: Environment | None = None, dry: bool = False, join: bool = False, interactive: bool = False, timeout: int | None = None, on_process_start: Callable[[Command, Popen[bytes], Logger], None] | None = None, message: str | None = None, friendly_command: str | None = None, log: LoggingFunction | None = None, silent: bool = False, stream_output: bool = True, caller: Common | None = None, logger: Logger) CommandOutput

Run command, give message, handle errors.

Parameters:
  • cwd – if set, command would be executed in the given directory, otherwise the current working directory is used.

  • shell – if set, the command would be executed in a shell.

  • env – environment variables to combine with the current environment before running the command.

  • dry – if set, the command would not be actually executed.

  • join – if set, stdout and stderr of the command would be merged into a single output text.

  • interactive – if set, the command would be executed in an interactive manner, i.e. with stdout and stdout connected to terminal for live interaction with user.

  • timeout – if set, command would be interrupted, if still running, after this many seconds.

  • on_process_start – if set, this callable would be called after the command process started.

  • message – if set, it would be logged for more friendly logging.

  • friendly_command – if set, it would be logged instead of the command itself, to improve visibility of the command in logging output.

  • log – a logging function to use for logging of command output. By default, logger.debug is used.

  • silent – if set, logging of steps taken by this function would be reduced.

  • stream_output – if set, command output would be streamed live into the log. When unset, the output would be logged only when the command fails.

  • caller – optional “parent” of the command execution, used for better linked exceptions.

  • logger – logger to use for logging.

Returns:

command output, bundled in a CommandOutput tuple.

to_element() str

Convert a command to a shell command line element.

Use when a command or just a list of command options should become a part of another command. Common examples of such “higher level” commands would be would be rsync -e or ansible-playbook --ssh-common-args.

to_popen() list[str]

Convert a command to form accepted by subprocess.Popen

to_script() ShellScript

Convert a command to a shell script.

Use when a command is supposed to become a part of a shell script.

class tmt.utils.CommandOutput(stdout: str | None, stderr: str | None)

Bases: object

stderr: str | None
stdout: str | None
class tmt.utils.Common(*, parent: CommonDerivedType | None = None, name: str | None = None, workdir: Literal[True] | Path | None = None, relative_indent: int = 1, cli_invocation: CliInvocation | None = None, logger: Logger, **kwargs: Any)

Bases: _CommonBase

Common shared stuff

Takes care of command line context, options and workdir handling. Provides logging functions info(), verbose() and debug(). Implements read() and write() for comfortable file access. Provides the run() method for easy command execution.

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: CliInvocation | None = None
property clone_dirpath: Path

Path for cloning into

Used internally for picking specific libraries (or anything else) from cloned repos for filtering purposes, it is removed at the end of relevant step.

debug(key: str, value: str | int | bool | float | Environment | FmfContext | Path | Command | ShellScript | None = None, color: str | None = None, shift: int = 0, level: int = 1, topic: Topic | None = None) None

Show message if in requested debug mode level

In quiet mode debug messages are not displayed.

property debug_level: int

The current debug level applied to this object

fail(message: str, shift: int = 0) None

Show a red failure message on info level, send to stderr

ignore_class_options: bool = False
info(key: str, value: str | int | bool | float | Environment | FmfContext | Path | Command | ShellScript | None = None, color: str | None = None, shift: int = 0) None

Show a message unless in quiet mode

inject_logger(logger: Logger) None
property is_dry_run: bool

Whether the current run is a dry-run

property is_feeling_safe: bool

Whether the current run is allowed to run unsafe actions

property is_forced_run: bool

Whether the current run is allowed to overwrite files and data

property name: str
opt(option: str, default: Any | None = None) Any

Get an option from the command line options

Checks also parent options. For flags (boolean values) parent’s True wins over child’s False (e.g. run –quiet enables quiet mode for all included plans and steps).

For options that can be used multiple times, the child overrides the parent if it was defined (e.g. run -av provision -vvv runs all steps except for provision in mildly verbose mode, provision is run with the most verbosity).

Environment variables override command line options.

parent: Common | None = None
print(text: str, color: str | None = None, shift: int = 0) None

Print out an output.

This method is supposed to be used for emitting a command output. Not to be mistaken with logging - errors, warnings, general command progress, and so on.

print() emits even when --quiet is used, as the option suppresses logging but not the actual command output.

property quietness: bool

The current quietness level applied to this object

read(path: Path, level: int = 2) str

Read a file from the workdir

run(command: Command, friendly_command: str | None = None, silent: bool = False, message: str | None = None, cwd: Path | None = None, ignore_dry: bool = False, shell: bool = False, env: Environment | None = None, interactive: bool = False, join: bool = False, log: LoggingFunction | None = None, timeout: int | None = None, on_process_start: Callable[[Command, Popen[bytes], Logger], None] | None = None) CommandOutput

Run command, give message, handle errors

Command is run in the workdir be default. In dry mode commands are not executed unless ignore_dry=True. Environment is updated with variables from the ‘env’ dictionary.

Output is logged using self.debug() or custom ‘log’ function. A user friendly command string ‘friendly_command’ will be shown, if provided, at the beginning of the command output.

Returns named tuple CommandOutput.

safe_name

A safe variant of the name which does not contain special characters.

Spaces and other special characters are removed to prevent problems with tools which do not expect them (e.g. in directory names).

property should_run_again: bool

Whether selected step or the whole run should be run again

classmethod store_cli_invocation(context: Context | None, options: dict[str, Any] | None = None) CliInvocation

Record a CLI invocation and options it carries for later use.

Warning

The given context is saved into a class variable, therefore it will function as a “default” context for instances on which store_cli_invocation() has not been called.

Parameters:
  • context – CLI context representing the invocation.

  • options – Optional dictionary with custom options. If provided, context is ignored.

Raises:

GeneralError – when there was a previously saved invocation already. Multiple invocations are not allowed.

verbose(key: str, value: str | int | bool | float | Environment | FmfContext | Path | Command | ShellScript | None = None, color: str | None = None, shift: int = 0, level: int = 1, topic: Topic | None = None) None

Show message if in requested verbose mode level

In quiet mode verbose messages are not displayed.

property verbosity_level: int

The current verbosity level applied to this object

warn(message: str, shift: int = 0) None

Show a yellow warning message on info level, send to stderr

property workdir: Path | None

Get the workdir, create if does not exist

write(path: Path, data: str, mode: str = 'w', level: int = 2) None

Write a file to the workdir

class tmt.utils.Config

Bases: object

User configuration

Initialize config directory path

fmf_tree

Return the configuration tree

property last_run: Path | None

Get the last run workdir path

tmt.utils.ContainerClass

Types for generic “data container” classes and instances. In tmt code, this reduces to data classes and data class instances. Our DataContainer are perfectly compatible data classes, but some helper methods may be used on raw data classes, not just on DataContainer instances.

alias of type[DataclassInstance]

exception tmt.utils.ConvertError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: MetadataError

Metadata conversion error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

tmt.utils.DEFAULT_OUTPUT_WIDTH: int = 79

How wide should the output be at maximum. This is the default value tmt would use unless told otherwise.

class tmt.utils.DataContainer

Bases: object

A base class for objects that have keys and values

property is_bare: bool

Check whether all keys are either unset or have their default value.

Returns:

True if all keys either hold their default value or are not set at all, False otherwise.

items() Iterator[tuple[str, Any]]

Iterate over key/value pairs

classmethod keys() Iterator[str]

Iterate over key names

to_dict() dict[str, Any]

Convert to a mapping.

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

to_minimal_dict() dict[str, Any]

Convert to a mapping with unset keys omitted.

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

values() Iterator[Any]

Iterate over key values

exception tmt.utils.DiscoverError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Discover step error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.DistGitHandler

Bases: object

Common functionality for DistGit handlers

its_me(remotes: list[str]) bool

True if self can work with remotes

lookaside_server: str
re_source: Pattern[str]
re_supported_extensions: Pattern[str] = re.compile('\\.((tar\\.(gz|Z|bz2|lz|lzma|lzo|xz|zst))|tgz|taz|taZ|tz2|tbz2|tbz|tlz|tzst)$')
remote_substring: Pattern[str]
sources_file_name = 'sources'
uri = '/rpms/{name}/{filename}/{hashtype}/{hash}/{filename}'
url_and_name(cwd: Path | None = None) list[tuple[str, str]]

Return list of urls and basenames of the used source

The ‘cwd’ parameter has to be a DistGit directory.

usage_name: str
tmt.utils.EnvVarName

A type of environment variable name.

class tmt.utils.EnvVarValue(raw_value: Any)

Bases: str

A type of environment variable value

class tmt.utils.Environment(data: dict[str, tmt.utils.EnvVarValue] | None = None)

Bases: dict[str, EnvVarValue]

Represents a set of environment variables.

See https://tmt.readthedocs.io/en/latest/spec/tests.html#environment, https://tmt.readthedocs.io/en/latest/spec/plans.html#environment and https://tmt.readthedocs.io/en/latest/spec/plans.html#environment-file.

as_environ() Iterator[None]

A context manager replacing os.environ with this environment.

When left, the original content of os.environ is restored.

Warning

This method is not thread safe! Beware of using it in code that runs in multiple threads, e.g. from provision/prepare/execute/finish phases.

copy() a shallow copy of D
classmethod from_dict(data: dict[str, Any] | None = None) Environment

Create environment variables from a dictionary

classmethod from_dotenv(content: str) Environment

Construct environment from a .env format.

Parameters:

content – string containing variables defined in the “dotenv” format, https://hexdocs.pm/dotenvy/dotenv-file-format.html.

classmethod from_environ() Environment

Extract environment variables from the live environment

classmethod from_file(*, filename: str, root: Path | None = None, logger: Logger) Environment

Construct environment from a file.

YAML files - recognized by .yaml or .yml suffixes - or .env-like files are supported.

dotenv file example
A=B
C=D
YAML file example
A: B
C: D

Note

For loading environment variables from multiple files, see Environment.from_files().

classmethod from_files(*, filenames: Iterable[str], root: Path | None = None, logger: Logger) Environment

Read environment variables from the given list of files.

Files should be in YAML format (.yaml or .yml suffixes), or in dotenv format.

dotenv file example
A=B
C=D
YAML file example
A: B
C: D

Path to each file should be relative to the metadata tree root.

Note

For loading environment variables from a single file, see Environment.from_file(), which is a method called for each file, accumulating data from all input files.

classmethod from_fmf_context(fmf_context: FmfContext) Environment

Create environment variables from an fmf context

classmethod from_fmf_spec(data: dict[str, Any] | None = None) Environment

Create environment from an fmf specification

classmethod from_inputs(*, raw_fmf_environment: Any = None, raw_fmf_environment_files: Any = None, raw_cli_environment: Any = None, raw_cli_environment_files: Any = None, file_root: Path | None = None, key_address: str | None = None, logger: Logger) Environment

Extract environment variables from various sources.

Combines various raw sources into a set of environment variables. Calls necessary functions to process environment files, dictionaries and CLI inputs.

All inputs are optional, and there is a clear order of preference, which is, from the most prefered:

  • --environment CLI option (raw_cli_environment)

  • --environment-file CLI option (raw_cli_environment_files)

  • environment fmf key (raw_fmf_environment)

  • environment-file fmf key (raw_fmf_environment_files)

Parameters:
  • raw_fmf_environment – content of environment fmf key. None and a dictionary are accepted.

  • raw_fmf_environment_files – content of environment-file fmf key. None and a list of paths are accepted.

  • raw_cli_environment – content of --environment CLI option. None, a tuple or a list are accepted.

  • raw_cli_environment_files – content of –environment-file` CLI option. None, a tuple or a list are accepted.

Raises:

NormalizationError – when an input is of a type which is not allowed for that particular source.

classmethod from_sequence(variables: str | list[str], logger: Logger) Environment

Construct environment from a sequence of variables.

Variables may be specified in two ways:

  • NAME=VALUE pairs, or

  • @foo.yaml signaling variables to be read from a file.

If a “variable” starts with @, it is treated as a path to a YAML file that contains key/value pairs which are then transparently loaded and added to the final environment.

Parameters:

variables

string or a sequence of strings containing variables. The acceptable formats are:

  • 'X=1'

  • 'X=1 Y=2 Z=3'

  • ['X=1', 'Y=2', 'Z=3']

  • ['X=1 Y=2 Z=3', 'A=1 B=2 C=3']

  • 'TXT="Some text with spaces in it"'

  • @foo.yaml

  • @../../bar.yaml

classmethod from_yaml(content: str) Environment

Construct environment from a YAML format.

Parameters:

content – string containing variables defined in a YAML dictionary, i.e. key: value entries.

classmethod from_yaml_file(filepath: Path, logger: Logger) Environment

Construct environment from a YAML file.

File is expected to contain variables in a YAML dictionary, i.e. key: value entries. Only primitive types - strings, numbers, booleans - are allowed as values.

Parameters:
  • path – path to the file with variables.

  • logger – used for logging.

classmethod normalize(key_address: str, value: Any, logger: Logger) Environment

Normalize value of environment key

to_environ() dict[str, str]

Convert to a form compatible with os.environ

to_fmf_spec() dict[str, str]

Convert to an fmf specification

to_popen() dict[str, str]

Convert to a form accepted by subprocess.Popen

exception tmt.utils.ExecuteError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Execute step error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.FedoraDistGit

Bases: DistGitHandler

Fedora Handler

lookaside_server: str = 'https://src.fedoraproject.org/repo/pkgs'
re_source: Pattern[str] = re.compile('^(\\w+) \\(([^)]+)\\) = ([0-9a-fA-F]+)$')
remote_substring: Pattern[str] = re.compile('fedoraproject\\.org')
usage_name: str = 'fedora'
tmt.utils.FieldCLIOption

Type of field’s CLI option specification.

alias of Union[str, Sequence[str]]

tmt.utils.FieldExporter

Type of field’s exporter callback.

alias of Callable[[T], Any]

class tmt.utils.FieldMetadata(internal: bool = False, help: str | None = None, _metavar: str | None = None, default: ~tmt.utils.T | None = None, default_factory: ~typing.Callable[[], ~tmt.utils.T] | None = None, is_flag: bool = False, multiple: bool = False, show_default: bool = False, _choices: None | ~collections.abc.Sequence[str] | ~typing.Callable[[], ~collections.abc.Sequence[str]] = None, envvar: str | None = None, deprecated: ~tmt.options.Deprecated | None = None, cli_option: str | ~collections.abc.Sequence[str] | None = None, normalize_callback: ~typing.Callable[[str, ~typing.Any, ~tmt.log.Logger], ~tmt.utils.T] | None = None, serialize_callback: ~typing.Callable[[~tmt.utils.T], ~typing.Any] | None = None, unserialize_callback: ~typing.Callable[[~tmt.utils.T], ~typing.Any] | None = None, export_callback: ~typing.Callable[[~tmt.utils.T], ~typing.Any] | None = None, _option_args: str | ~collections.abc.Sequence[str] | None = None, _option_kwargs: dict[str, typing.Any] = <factory>, _option: ~typing.Callable[[~typing.Any], ~typing.Any] | None = None)

Bases: Generic[T]

A dataclass metadata container used by our custom dataclass field management.

Attached to fields defined with field()

choices

A list of allowed values the field can take

cli_option: str | Sequence[str] | None = None

One or more command-line option names.

default: T | None = None

The default value for the field.

default_factory: Callable[[], T] | None = None

A zero-argument callable that will be called when a default value is needed for the field.

deprecated: Deprecated | None = None

Mark the option as deprecated. Instance of Deprecated describes the version in which the field was deprecated plus an optional hint with the recommended alternative. Documentation and help texts would contain this info.

envvar: str | None = None

Environment variable providing value for the field.

export_callback: Callable[[T], Any] | None = None

An export callback to call when exporting the field (performed by tmt.export.Exportable).

property has_default: bool

Whether the field has a default value

help: str | None = None

Help text documenting the field.

internal: bool = False
is_flag: bool = False

Marks the fields as a flag.

property materialized_default: T | None

Returns the actual default value of the field

metavar

Placeholder for field’s value in documentation and help

multiple: bool = False

Marks the field as accepting multiple values. When used on command line, the option could be used multiple times, accumulating values.

normalize_callback: Callable[[str, Any, Logger], T] | None = None

A normalization callback to call when loading the value from key source (performed by NormalizeKeysMixin).

property option: Callable[[Any], Any] | None
serialize_callback: Callable[[T], Any] | None = None
show_default: bool = False

If set, show the default value in command line help.

unserialize_callback: Callable[[T], Any] | None = None
exception tmt.utils.FileError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

File operation error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

exception tmt.utils.FinishError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Finish step error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.FmfContext(data: dict[str, list[str]] | None = None)

Bases: dict[str, list[str]]

Represents an fmf context.

See https://tmt.readthedocs.io/en/latest/spec/context.html and https://fmf.readthedocs.io/en/latest/context.html.

classmethod from_spec(key_address: str, spec: Any, logger: Logger) FmfContext

Convert from a specification file or from a CLI option.

See https://tmt.readthedocs.io/en/stable/spec/context.html for details on context.

to_spec() dict[str, Any]

Convert to a form suitable for saving in a specification file

exception tmt.utils.GeneralError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: Exception

General error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

exception tmt.utils.GitUrlError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Remote git url is not reachable

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

tmt.utils.KeySource

A type representing compatible sources of keys and values.

alias of Union[dict[str, Any], Tree]

class tmt.utils.ListFormat(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

How to format lists

LISTED = 1

Use fmf.utils.listed().

LONG = 3

One list item per line.

SHORT = 2

Produce comma-separated list.

class tmt.utils.LoadFmfKeysMixin(*, node: Tree, logger: Logger, **kwargs: Any)

Bases: NormalizeKeysMixin

exception tmt.utils.MetadataError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

General metadata error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.MultiInvokableCommon(**kwargs: Any)

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: CliInvocation | None = None
cli_invocations: list[tmt.cli.CliInvocation] = []
classmethod store_cli_invocation(context: Context | None, options: dict[str, Any] | None = None) CliInvocation

Save a CLI context and options it carries for later use.

Warning

The given context is saved into a class variable, therefore it will function as a “default” context for instances on which _save_cli_context_to_instance() has not been called.

Warning

The given context will overwrite any previously saved context.

Parameters:
  • context – CLI context to save.

  • options – Optional dictionary with custom options. If provided, context is ignored.

exception tmt.utils.NormalizationError(key_address: str, raw_value: Any, expected_type: str, *args: Any, **kwargs: Any)

Bases: SpecificationError

Raised when a key normalization fails

Raised when a key normalization fails.

A subclass of SpecificationError, but describing errors that appear in a very specific point of key loading in a unified manner.

Parameters:
  • key_address – the key in question, preferrably with detailed location, e.g. /plans/foo:discover[0].tests.

  • raw_value – input value, the one that failed the normalization.

  • expected_type – string description of expected, allowed types, as a hint in the error message.

tmt.utils.NormalizeCallback

Type of field’s normalization callback.

alias of Callable[[str, Any, Logger], T]

class tmt.utils.NormalizeKeysMixin(**kwargs: Any)

Bases: _CommonBase

Mixin adding support for loading fmf keys into object attributes.

When invoked, annotated class-level variables are searched for in a given source container - a mapping, an fmf node, etc. - and if the key of the same name as the variable exists, its value is “promoted” to instance variable.

If a method named _normalize_<variable name> exists, it is called with the fmf key value as its single argument, and its return value is assigned to instance variable. This gives class chance to modify or transform the original value when needed, e.g. to convert the original value to a type more suitable for internal processing.

items() Iterator[tuple[str, Any]]

Iterate over keys and their values.

Keys are yielded in the order: keys declared by parent classes first, then keys declared by the class itself, all following the order in which keys were defined in their respective classes.

Yields:

pairs of key name and its value.

classmethod keys() Iterator[str]

Iterate over key names.

Keys are yielded in the order: keys declared by parent classes first, then keys declared by the class itself, all following the order in which keys were defined in their respective classes.

Yields:

key names.

tmt.utils.OUTPUT_WIDTH: int = 79

How wide should the output be at maximum. This is the effective value, combining the default and optional envvar, TMT_OUTPUT_WIDTH.

tmt.utils.OnProcessStartCallback

Type of a callable to be called by Command.run() after starting the child process.

alias of Callable[[Command, Popen[bytes], Logger], None]

class tmt.utils.Path(*args, **kwargs)

Bases: PosixPath

Construct a PurePath from one or several strings and or existing PurePath objects. The strings and path objects are combined so as to yield a canonicalized path, which is incorporated into the new PurePath object.

is_relative_to(other: Path) bool

Return True if the path is relative to another path or False.

relative_to(other: str | Path) Path

Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError.

The walk_up parameter controls whether .. may be used to resolve the path.

unrooted() Path

Return the path as if it was not starting in file system root

exception tmt.utils.PrepareError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Prepare step error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.ProcessExitCodes(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: IntEnum

TEST_PIDFILE_LOCK_FAILED = 122
TEST_PIDFILE_UNLOCK_FAILED = 123
TIMEOUT = 124
classmethod is_pidfile(exit_code: int | None) bool
exception tmt.utils.ProvisionError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Provision step error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

tmt.utils.RawCommand

A raw command line form, a list of elements.

alias of list[Union[str, Path]]

tmt.utils.RawCommandElement

A single element of raw command line in its list form.

alias of Union[str, Path]

exception tmt.utils.RebootTimeoutError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: ExecuteError

Reboot failed due to a timeout

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.RedHatGitlab

Bases: DistGitHandler

Red Hat on Gitlab

lookaside_server: str = 'http://pkgs.devel.redhat.com/repo'
re_source: Pattern[str] = re.compile('^(\\w+) \\(([^)]+)\\) = ([0-9a-fA-F]+)$')
remote_substring: Pattern[str] = re.compile('redhat/rhel/')
usage_name: str = 'redhatgitlab'
exception tmt.utils.ReportError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Report step error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.RestVisitor(document: document, logger: Logger)

Bases: NodeVisitor

Custom renderer of docutils nodes.

See docutils.nodes.NodeVisitor for details, but the functionality is fairly simple: for each node type, a pair of methods is expected, visit_$NODE_TYPE and depart_$NODE_TYPE. As the visitor class iterates over nodes in the document, corresponding methods are called. These methods render the given node, filling “rendered paragraphs” list with rendered strings.

depart_Text(node: Node) None
depart_bullet_list(node: bullet_list) None
depart_document(node: document) None
depart_inline(node: Node) None
depart_list_item(node: list_item) None
depart_literal(node: Node) None
depart_literal_block(node: literal_block) None
depart_note(node: note) None
depart_paragraph(node: paragraph) None
depart_reference(node: Node) None
depart_warning(node: warning) None
flush() None

Finalize rendering of the current paragraph

nl() None

Render a new, empty line

property rendered: str

Return the rendered document as a single string

unknown_departure(node: Node) None

Called before exiting unknown Node types.

Raise exception unless overridden.

unknown_visit(node: Node) None

Called when entering unknown Node types.

Raise an exception unless overridden.

visit_Text(node: Text) None
visit_bullet_list(node: bullet_list) None
visit_document(node: Node) None
visit_inline(node: Node) None
visit_list_item(node: list_item) None
visit_literal(node: literal) None
visit_literal_block(node: literal_block) None
visit_note(node: note) None
visit_paragraph(node: paragraph) None
visit_reference(node: Node) None
visit_warning(node: warning) None
exception tmt.utils.RetryError(label: str, causes: list[Exception])

Bases: GeneralError

Retries unsuccessful

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.RetryStrategy(total: bool | int | None = 10, connect: int | None = None, read: int | None = None, redirect: bool | int | None = None, status: int | None = None, other: int | None = None, allowed_methods: Collection[str] | None = frozenset({'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT', 'TRACE'}), status_forcelist: Collection[int] | None = None, backoff_factor: float = 0, backoff_max: float = 120, raise_on_redirect: bool = True, raise_on_status: bool = True, history: tuple[urllib3.util.retry.RequestHistory, ...] | None = None, respect_retry_after_header: bool = True, remove_headers_on_redirect: Collection[str] = frozenset({'Authorization', 'Cookie'}), backoff_jitter: float = 0.0)

Bases: Retry

increment(*args: Any, **kwargs: Any) Retry

Return a new Retry object with incremented retry counters.

Parameters:
  • response (BaseHTTPResponse) – A response object, or None, if the server did not return a response.

  • error (Exception) – An error encountered during the request, or None if the response was received successfully.

Returns:

A new Retry object.

exception tmt.utils.RunError(message: str, command: Command, returncode: int, stdout: str | None = None, stderr: str | None = None, caller: Common | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

Command execution error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.SerializableContainer

Bases: DataContainer

A mixin class for saving and loading objects

classmethod default(key: str, default: Any = None) Any
classmethod extract_from(obj: Any) SerializableContainerDerivedType

Extract keys from given object, and save them in a container

classmethod from_serialized(serialized: dict[str, Any]) SerializableContainerDerivedType

Convert from a serialized form loaded from a file.

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

See to_serialized() for its counterpart.

inject_to(obj: Any) None

Inject keys from this container into attributes of a given object

to_serialized() dict[str, Any]

Convert to a form suitable for saving in a file.

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

See from_serialized() for its counterpart.

static unserialize(serialized: dict[str, Any], logger: Logger) SerializableContainerDerivedType

Convert from a serialized form loaded from a file.

Similar to from_serialized(), but this method knows nothing about container’s class, and will locate the correct module and class by inspecting serialized data. Discovered class’ from_serialized() is then used to create the container.

Used to transform data read from a YAML file into original containers when their classes are not know to the code. Restoring such containers requires inspection of serialized data and dynamic imports of modules as needed.

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

See to_serialized() for its counterpart.

tmt.utils.SerializeCallback

Type of field’s serialization callback.

alias of Callable[[T], Any]

class tmt.utils.ShellScript(script: str)

Bases: object

A shell script, a free-form blob of text understood by a shell.

A shell script, a free-form blob of text understood by a shell.

Parameters:

script – the actual script to be encapsulated by ShellScript wrapper.

classmethod from_scripts(scripts: list[tmt.utils.ShellScript]) ShellScript

Create a single script from many shorter ones.

Scripts are merged into a single ShellScript instance, joined together with ; character.

Parameters:

scripts – scripts to merge into one.

to_element() str

Convert a shell script to a command element

to_shell_command() Command

Convert a shell script into a shell-driven command.

Turns a shell script into a full-fledged command one might pass to the OS. Basically what would run(script, shell=True) do.

class tmt.utils.SpecBasedContainer

Bases: Generic[SpecInT, SpecOutT], DataContainer

classmethod from_spec(spec: SpecInT) SpecBasedContainerT

Convert from a specification file or from a CLI option

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

See to_spec() for its counterpart.

to_minimal_spec() SpecOutT

Convert to specification, skip default values

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

See from_spec() for its counterpart.

to_spec() SpecOutT

Convert to a form suitable for saving in a specification file

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

See from_spec() for its counterpart.

class tmt.utils.SpecBasedContainerT

A typevar bound to spec-based container base class. A stand-in for all classes derived from SpecBasedContainer.

alias of TypeVar(‘SpecBasedContainerT’, bound=SpecBasedContainer)

class tmt.utils.SpecInT

A typevar representing an input specification consumed by SpecBasedContainer.

alias of TypeVar(‘SpecInT’)

class tmt.utils.SpecOutT

A typevar representing an output specification produced by SpecBasedContainer.

alias of TypeVar(‘SpecOutT’)

exception tmt.utils.SpecificationError(message: str, validation_errors: list[tuple[jsonschema.exceptions.ValidationError, str]] | None = None, *args: Any, **kwargs: Any)

Bases: MetadataError

Metadata specification error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.Stopwatch

Bases: AbstractContextManager[Stopwatch]

property duration: timedelta
end_time: datetime
start_time: datetime
class tmt.utils.StreamLogger(log_header: str, *, stream: IO[bytes] | None = None, logger: LoggingFunction | None = None, click_context: Context | None = None, stream_output: bool = True)

Bases: Thread

Reading pipes of running process in threads.

Code based on: https://github.com/packit/packit/blob/main/packit/utils/logging.py#L10

This constructor should always be called with keyword arguments. Arguments are:

group should be None; reserved for future extension when a ThreadGroup class is implemented.

target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.

name is the thread name. By default, a unique name is constructed of the form “Thread-N” where N is a small decimal number.

args is a list or tuple of arguments for the target invocation. Defaults to ().

kwargs is a dictionary of keyword arguments for the target invocation. Defaults to {}.

If a subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.

get_output() str | None
run() None

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

class tmt.utils.StructuredField(text: str | None = None, version: int = 1, multi: bool = False)

Bases: object

Handling multiple text data in a single text field

The StructuredField allows you to easily store and extract several sections of text data to/from a single text field. The sections are separated by section names in square brackets and can be hosted in other text as well.

The section names have to be provided on a separate line and there must be no leading/trailing white space before/after the brackets. The StructuredField supports two versions of the format:

Version 0: Simple, concise, useful when neither the surrounding text or the section data can contain lines which could resemble section names. Here’s an example of a simple StructuredField:

Note written by human.

[section-one]
Section one content.

[section-two]
Section two content.

[section-three]
Section three content.

[end]

Another note written by human.

Version 1: Includes unique header to prevent collisions with the surrounding text and escapes any section-like lines in the content:

Note written by human.

[structured-field-start]
This is StructuredField version 1. Please, edit with care.

[section-one]
Section one content.

[section-two]
Section two content.
[structured-field-escape][something-resembling-section-name]

[section-three]
Section three content.

[structured-field-end]

Another note written by human.

Note that an additional empty line is added at the end of each section to improve the readability. This line is not considered to be part of the section content.

Besides handling the whole section content it’s also possible to store several key-value pairs in a single section, similarly as in the ini config format:

[section]
key1 = value1
key2 = value2
key3 = value3

Provide the key name as the optional argument ‘item’ when accessing these single-line items. Note that the section cannot contain both plain text data and key-value pairs.

Example:

field = qe.StructuredField()
field.set("project", "Project Name")
field.set("details", "somebody", "owner")
field.set("details", "2013-05-27", "started")
field.set("description", "This is a description.\n"
        "It spans across multiple lines.\n")
print field.save()

    [structured-field-start]
    This is StructuredField version 1. Please, edit with care.

    [project]
    Project Name

    [details]
    owner = somebody
    started = 2013-05-27

    [description]
    This is a description.
    It spans across multiple lines.

    [structured-field-end]

field.version(0)
print field.save()

    [project]
    Project Name

    [details]
    owner = somebody
    started = 2013-05-27

    [description]
    This is a description.
    It spans across multiple lines.

    [end]

Multiple values for the same key are supported as well. Enable this feature with ‘multi=True’ when initializing the structured field. If multiple values are present their list will be returned instead of a single string. Similarly use list for setting multiple values:

field = qe.StructuredField(multi=True)
requirements = ['hypervisor=', 'labcontroller=lab.example.com']
field.set("hardware", requirements, "hostrequire")
print field.save()

    [structured-field-start]
    This is StructuredField version 1. Please, edit with care.

    [hardware]
    hostrequire = hypervisor=
    hostrequire = labcontroller=lab.example.com

    [structured-field-end]

print field.get("hardware", "hostrequire")

    ['hypervisor=', 'labcontroller=lab.example.com']

Initialize the structured field

footer(content: str | None = None) str

Get or set the footer content

get(section: str, item: str | None = None) str | list[str]

Return content of given section or section item

header(content: str | None = None) str

Get or set the header content

iterate() Iterator[tuple[str, str]]

Return (section, content) tuples for all sections

load(text: str, version: int | None = None) None

Load the StructuredField from a string

remove(section: str, item: str | None = None) None

Remove given section or section item

save() str

Convert the StructuredField into a string

sections() list[str]

Get the list of available sections

set(section: str, content: Any, item: str | None = None) None

Update content of given section or section item

version(version: int | None = None) int

Get or set the StructuredField version

exception tmt.utils.StructuredFieldError(message: str, causes: list[Exception] | None = None, *args: Any, **kwargs: Any)

Bases: GeneralError

StructuredField parsing error

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

class tmt.utils.TimeoutHTTPAdapter(*args: Any, **kwargs: Any)

Bases: HTTPAdapter

Spice up request’s session with custom timeout.

send(request: PreparedRequest, **kwargs: Any) Response

Send request.

All arguments are passed to superclass after enforcing the timeout.

Parameters:

request – the request to send.

tmt.utils.UnserializeCallback

Type of field’s unserialization callback.

alias of Callable[[Any], T]

class tmt.utils.UnusedStreamLogger(log_header: str)

Bases: StreamLogger

Special variant of StreamLogger that records no data.

It is designed to make the implementation of merged streams easier in Command.run(). Instance of this class is created to log stderr when, in fact, stderr is merged into stdout. This class returns values compatible with CommandOutput notion of “no output”.

This constructor should always be called with keyword arguments. Arguments are:

group should be None; reserved for future extension when a ThreadGroup class is implemented.

target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.

name is the thread name. By default, a unique name is constructed of the form “Thread-N” where N is a small decimal number.

args is a list or tuple of arguments for the target invocation. Defaults to ().

kwargs is a dictionary of keyword arguments for the target invocation. Defaults to {}.

If a subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.

get_output() str | None
run() None

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

class tmt.utils.UpdatableMessage(key: str, enabled: bool = True, indent_level: int = 0, key_color: str | None = None, default_value_color: str | None = None, clear_on_exit: bool = False)

Bases: AbstractContextManager

Updatable message suitable for progress-bar-like reporting

Updatable message suitable for progress-bar-like reporting.

with UpdatableMessage('foo') as message:
    while ...:
        ...

        # check state of remote request, and update message
        state = remote_api.check()
        message.update(state)
Parameters:
  • key – a string to use as the left-hand part of logged message.

  • enabled – if unset, no output would be performed.

  • indent_level – desired indentation level.

  • key_color – optional color to apply to key.

  • default_color – optional color to apply to value when update() is called with color left out.

  • clear_on_exit – if set, the message area would be cleared when leaving the progress bar when used as a context manager.

clear() None

Clear the message area

update(value: str, color: str | None = None) None

Update progress message.

Parameters:
  • value – new message to update message area with.

  • color – optional message color.

class tmt.utils.ValidateFmfMixin(*, node: Tree, skip_validation: bool = False, raise_on_validation_error: bool = False, logger: Logger, **kwargs: Any)

Bases: _CommonBase

Mixin adding validation of an fmf node.

Loads a schema whose name is derived from class name, and uses fmf’s validate() method to perform the validation.

tmt.utils.ValueFormatter

A type describing a per-type formatting helper.

alias of Callable[[Any, Optional[int], Optional[str], ListFormat, Literal[True, False, ‘auto’]], Iterator[str]]

exception tmt.utils.WaitingIncompleteError

Bases: GeneralError

Waiting incomplete

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

exception tmt.utils.WaitingTimedOutError(check: Callable[[], T], timeout: timedelta, check_success: bool = False)

Bases: GeneralError

Waiting ran out of time

General error.

Parameters:
  • message – error message.

  • causes – optional list of exceptions that caused this one. Since raise ... from ... allows only for a single cause, and some of our workflows may raise exceptions triggered by more than one exception, we need a mechanism for storing them. Our reporting will honor this field, and report causes the same way as __cause__.

tmt.utils.ascii(text: Any) bytes

Transliterate special unicode characters into pure ascii

tmt.utils.assert_window_size(window_size: int | None) None

Raise an exception if window size is zero or a negative integer.

Protects possible underflows in formatters employed by format_value().

class tmt.utils.cached_property(fn: Callable[[Any], T])

Bases: Generic[T]

tmt.utils.check_git_url(url: str) str

Check that a remote git url is accessible

tmt.utils.clonable_git_url(url: str) str

Modify the git repo url so it can be cloned

tmt.utils.configure_constant(default: int, envvar: str) int

Deduce the actual value of global constant.

Parameters:
  • default – the default value of the constant.

  • envvar – name of the optional environment variable which would override the default value.

Returns:

value extracted from the environment variable, or the given default value if the variable did not exist.

tmt.utils.configure_optional_constant(default: int | None, envvar: str) int | None

Deduce the actual value of a global constant which may be left unset.

Parameters:
  • default – the default value of the constant.

  • envvar – name of the optional environment variable which would override the default value.

Returns:

value extracted from the environment variable, or the given default value if the variable did not exist.

tmt.utils.container_field(container: ContainerClass, key: str) tuple[str, str, dataclasses.Field[Any], tmt.utils.FieldMetadata[Any]]
tmt.utils.container_field(container: ContainerInstance, key: str) tuple[str, str, Any, dataclasses.Field[Any], tmt.utils.FieldMetadata[Any]]

Return a dataclass/data container field info by the field’s name.

Surprisingly, dataclasses package does not have a helper for this. One can iterate over fields, but there’s no public API for retrieving a field when one knows its name.

Parameters:
  • cls – a dataclass/data container class whose fields to search.

  • key – field name to retrieve.

Raises:

GeneralError – when the field does not exist.

tmt.utils.container_fields(container: type['DataclassInstance'] | DataclassInstance) Iterator[Field[Any]]
tmt.utils.container_items(container: DataclassInstance) Iterator[tuple[str, Any]]

Iterate over key/value pairs in a container

tmt.utils.container_keys(container: type['DataclassInstance'] | DataclassInstance) Iterator[str]

Iterate over key names in a container

tmt.utils.container_values(container: DataclassInstance) Iterator[Any]

Iterate over values in a container

tmt.utils.create_directory(*, path: Path, name: str, dry: bool = False, quiet: bool = False, logger: Logger) None

Create a new directory.

Before creating the directory, function checks whether it exists already - the existing directory is not removed and re-created.

The outcome of the operation will be logged in a debug log, but may also be sent to console with quiet=False.

Parameters:
  • path – a path to be created.

  • name – a “label” of the path, used for logging.

  • dry – if set, directory would not be created. Still, the existence check will happen.

  • quiet – if set, an outcome of the operation would not be logged to console.

  • logger – logger to use for logging.

Raises:

FileError – when function tried to create the directory, but failed.

tmt.utils.create_file(*, path: Path, content: str, name: str, dry: bool = False, force: bool = False, mode: int = 436, quiet: bool = False, logger: Logger) None

Create a new file.

Before creating the file, function checks whether it exists already - the existing file is not removed and re-created, unless force is set.

The outcome of the operation will be logged in a debug log, but may also be sent to console with quiet=False.

Parameters:
  • path – a path to be created.

  • content – content to save into the file

  • name – a “label” of the path, used for logging.

  • dry – if set, the file would not be created or overwritten. Still, the existence check will happen.

  • force – if set, the file would be overwritten if it already exists.

  • mode – permissions to set for the file.

  • quiet – if set, an outcome of the operation would not be logged to console.

  • logger – logger to use for logging.

Raises:

FileError – when function tried to create the file, but failed.

tmt.utils.dataclass_normalize_field(container: Any, key_address: str, keyname: str, raw_value: Any, logger: Logger) Any

Normalize and assign a value to container field.

If there is a normalization callback defined for the field via normalize parameter of field(), the callback is called to coerce raw_value, and the return value is assigned to container field instead of value.

tmt.utils.default_branch(*, repository: Path, remote: str = 'origin', logger: Logger) str | None

Detect default branch from given local git repository

tmt.utils.default_template_environment() Environment

Create a Jinja2 environment with default settings.

Adds common filters, and enables block trimming and left strip.

tmt.utils.dict_to_yaml(data: dict[str, Any] | list[Any] | _RawFmfId, width: int | None = None, sort: bool = False, start: bool = False) str

Convert dictionary into yaml

tmt.utils.distgit_download(*, distgit_dir: Path, target_dir: Path, handler_name: str | None = None, caller: Common | None = None, logger: Logger) None

Download sources to the target_dir

distgit_dir is path to the DistGit repository

tmt.utils.duplicates(values: Iterable[T | None]) Iterator[T]

Iterate over all duplicate values in values

tmt.utils.duration_to_seconds(duration: str) int

Convert sleep time format into seconds

tmt.utils.effective_workdir_root() Path

Find out what the actual workdir root is.

If TMT_WORKDIR_ROOT variable is set, it is used as the workdir root. Otherwise, the default of WORKDIR_ROOT is used.

tmt.utils.field(*, default: bool, option: str | Sequence[str] | None = None, is_flag: bool = True, choices: None | Sequence[str] | Callable[[], Sequence[str]] = None, multiple: bool = False, metavar: str | None = None, envvar: str | None = None, deprecated: Deprecated | None = None, help: str | None = None, show_default: bool = False, internal: bool = False) bool
tmt.utils.field(*, default: T, option: str | Sequence[str] | None = None, is_flag: bool = False, choices: None | Sequence[str] | Callable[[], Sequence[str]] = None, multiple: bool = False, metavar: str | None = None, envvar: str | None = None, deprecated: Deprecated | None = None, help: str | None = None, show_default: bool = False, internal: bool = False, normalize: Callable[[str, Any, Logger], T] | None = None, serialize: Callable[[T], Any] | None = None, unserialize: Callable[[Any], T] | None = None, exporter: Callable[[T], Any] | None = None) T
tmt.utils.field(*, default_factory: Callable[[], T], option: str | Sequence[str] | None = None, is_flag: bool = False, choices: None | Sequence[str] | Callable[[], Sequence[str]] = None, multiple: bool = False, metavar: str | None = None, envvar: str | None = None, deprecated: Deprecated | None = None, help: str | None = None, show_default: bool = False, internal: bool = False, normalize: Callable[[str, Any, Logger], T] | None = None, serialize: Callable[[T], Any] | None = None, unserialize: Callable[[Any], T] | None = None, exporter: Callable[[T], Any] | None = None) T
tmt.utils.field(*, option: str | Sequence[str] | None = None, is_flag: bool = False, choices: None | Sequence[str] | Callable[[], Sequence[str]] = None, multiple: bool = False, metavar: str | None = None, envvar: str | None = None, deprecated: Deprecated | None = None, help: str | None = None, show_default: bool = False, internal: bool = False, normalize: Callable[[str, Any, Logger], T] | None = None, serialize: Callable[[T], Any] | None = None, unserialize: Callable[[Any], T] | None = None, exporter: Callable[[T], Any] | None = None) T

Define a DataContainer field.

Effectively a fancy wrapper over dataclasses.field(), tailored for tmt code needs and simplification of various common tasks.

Parameters:
  • default – if provided, this will be the default value for this field. Passed directly to dataclass.field(). It is an error to specify both default and default_factory.

  • default_factory – if provided, it must be a zero-argument callable that will be called when a default value is needed for this field. Passed directly to dataclass.field(). It is an error to specify both default and default_factory.

  • option – one or more command-line option names. Passed directly to click.option().

  • is_flag – marks this option as a flag. Passed directly to click.option().

  • choices – if provided, the command-line option would accept only the listed input values. Passed to click.option() as a click.Choice instance.

  • multiple – accept multiple arguments of the same name. Passed directly to click.option().

  • metavar – how the input value is represented in the help page. Passed directly to click.option().

  • envvar – environment variable used for this option. Passed directly to click.option().

  • deprecated – mark the option as deprecated Provide an instance of Deprecated() with version in which the option was obsoleted and an optional hint with the recommended alternative. A warning message will be added to the option help.

  • help – the help string for the command-line option. Multiline strings can be used, textwrap.dedent() is applied before passing help to click.option().

  • show_default – show default value Passed directly to click.option().

  • internal – if set, the field is treated as internal-only, and will not appear when showing objects via show() method, or in export created by Core._export().

  • normalize – a callback for normalizing the input value. Consumed by NormalizeKeysMixin.

  • serialize – a callback for custom serialization of the field value. Consumed by SerializableKeysMixin.

  • unserialize – a callback for custom unserialization of the field value. Consumed by SerializableKeysMixin.

  • exporter – a callback for custom export of the field value. Consumed by tmt.export.Exportable.

tmt.utils.filter_paths(directory: Path, searching: list[str], files_only: bool = False) list[tmt.utils.Path]

Filter files for specific paths we are searching for inside a directory

Returns list of matching paths.

tmt.utils.find_fmf_root(path: Path, ignore_paths: list[tmt.utils.Path] | None = None) list[tmt.utils.Path]

Search trough path and return all fmf roots that exist there

Returned list is ordered by path length, shortest one first.

Raise MetadataError if no fmf root is found.

tmt.utils.flatten(lists: Iterable[list[T]], unique: bool = False) list[T]

“Flatten” a list of lists into a single-level list.

Parameters:
  • lists – an iterable of lists to flatten.

  • unique – if set, duplicate items would be removed, leaving only a single instance in the final list.

Returns:

list of items from all given lists.

tmt.utils.fmf_id(*, name: str, fmf_root: Path, always_get_ref: bool = False, logger: Logger) FmfId

Return full fmf identifier of the node

tmt.utils.format(key: str, value: None | int | float | bool | str | list[Any] | dict[Any, Any] = None, indent: int = 24, window_size: int = 79, wrap: Literal[True, False, 'auto'] = 'auto', key_color: str | None = 'green', value_color: str | None = 'black', list_format: ListFormat = ListFormat.LISTED) str

Nicely format and indent a key-value pair

Parameters:
  • key – a key introducing the value.

  • value – an object to format.

  • indent – the key would be right-justified to this column.

  • window_size – rendering will try to fit produce lines whose length would exceed window_size. A window not wide enough may result into not using fmf.utils.listed() for lists, or wrapping lines in a text paragraph.

  • wrap – if set to True, always reformat text and wrap long lines; if set to False, preserve text formatting and make no changes; the default, auto, tries to rewrap lines as needed to obey window_size.

  • key_color – if set, dictionary keys would be colorized by this color.

  • list_format – preferred list formatting. It may be ignored if window_size is set and not wide enough to hold the desired formatting; ListFormat.LONG would be the fallback choice.

Returns:

a formatted string representation of value.

tmt.utils.format_value(value: Any, window_size: int | None = None, key_color: str | None = None, list_format: ListFormat = ListFormat.LISTED, wrap: Literal[True, False, 'auto'] = 'auto') str

Render a nicely-formatted string representation of a value.

Parameters:
  • value – an object to format.

  • window_size – if set, rendering will try to produce lines whose length would not exceed window_size. A window not wide enough may result into not using fmf.utils.listed(), or wrapping lines in a text paragraph.

  • key_color – if set, dictionary keys would be colorized by this color.

  • list_format – preferred list formatting. It may be ignored if window_size is set and not wide enough to hold the desired formatting; ListFormat.LONG would be the fallback choice.

Returns:

a formatted string representation of value.

tmt.utils.generate_runs(path: Path, id_: str | None = None) Iterator[Path]

Generate absolute paths to runs from path

tmt.utils.get_distgit_handler(remotes: list[str] | None = None, usage_name: str | None = None) DistGitHandler

Return the right DistGitHandler

Pick the DistGitHandler class which understands specified remotes or by usage_name.

tmt.utils.get_distgit_handler_names() list[str]

All known distgit handlers

tmt.utils.get_full_metadata(fmf_tree_path: Path, node_path: str) Any

Get full metadata for a node in any fmf tree

Go through fmf tree nodes using given relative node path and return full data as dictionary.

tmt.utils.get_url_content(url: str) str

Get content of a given URL as a string.

tmt.utils.git_add(*, path: Path, logger: Logger) None

Add path to the git index.

Parameters:
  • path – path to add to the git index.

  • logger – used for logging.

tmt.utils.git_clone(*, url: str, destination: Path, shallow: bool = False, can_change: bool = True, env: Environment | None = None, attempts: int | None = None, interval: int | None = None, timeout: int | None = None, logger: Logger) CommandOutput

Clone git repository from provided url to the destination directory

Parameters:
  • url – Source URL of the git repository.

  • destination – Full path to the destination directory.

  • shallow – For shallow=True first try to clone repository using --depth=1 option. If not successful clone repo with the whole history.

  • can_change – URL can be modified with hardcoded rules. Use can_change=False to disable rewrite rules.

  • env – Environment provided to the git clone process.

  • attempts – Number of tries to call the function.

  • interval – Amount of seconds to wait before a new try.

  • timeout – Overall maximum time in seconds to clone the repo.

  • logger – A Logger instance to be used for logging.

Returns:

Command output, bundled in a CommandOutput tuple.

tmt.utils.git_root(*, fmf_root: Path, logger: Logger) Path | None

Find a path to the root of git repository containing an fmf root.

Parameters:
  • fmf_root – path to an fmf root that is supposedly in a git repository.

  • logger – used for logging.

Returns:

path to the git repository root, if fmf root lies in one, or None.

tmt.utils.inject_auth_git_url(url: str) str

Inject username or token to the git url

Parameters:

url – original git repo url

Returns:

URL with injected authentification based on pattern from the environment or unmodified URL

tmt.utils.is_key_origin(node: Tree, key: str) bool

Find out whether the given key is defined in the given node.

Parameters:
  • node – node to check.

  • key – key to check.

Returns:

True if the key is defined in node, not by one of its parents, False otherwise.

tmt.utils.is_selinux_supported() bool

Returns true if SELinux filesystem is supported by the kernel, false otherwise.

For detection /proc/filesystems is used, see man 5 filesystems for details.

tmt.utils.is_url(url: str) bool

Check if the given string is a valid URL.

tmt.utils.json_to_list(data: Any) list[Any]

Convert json into list

tmt.utils.key_to_option(key: str) str

Convert a key name to corresponding option name

tmt.utils.load_run(run: Run) tuple[bool, Optional[Exception]]

Load a run and its steps from the workdir

tmt.utils.load_schema(schema_filepath: Path) dict[str, Any]

Load a JSON schema from a given filepath.

Recommended for general use, the method may apply some post-loading touches to the given schema, and unless caller is interested in the raw content of the file, this functions should be used instead of the real workhorse of schema loading, _load_schema().

tmt.utils.load_schema_store() dict[str, dict[str, Any]]

Load all available JSON schemas, and put them into a “store”.

Schema store is a simple mapping between schema IDs and schemas.

tmt.utils.locate_key_origin(node: Tree, key: str) Tree | None

Find an fmf node where the given key is defined.

Parameters:
  • node – node to begin with.

  • key – key to look for.

Returns:

first node in which the key is defined, None if node nor any of its parents define it.

tmt.utils.markdown_to_html(filename: Path) str

Convert markdown to html

Expects: Markdown document as a file. Returns: An HTML document as a string.

tmt.utils.normalize_int(key_address: str, value: Any, logger: Logger) int

Normalize an integer.

For a field that takes an integer input. The field might be also left out, but it does have a default value.

tmt.utils.normalize_optional_int(key_address: str, value: Any, logger: Logger) int | None

Normalize an integer that may be unset as well.

For a field that takes an integer input, but might be also left out, and has no default value.

tmt.utils.normalize_path(key_address: str, value: Any, logger: Logger) Path | None

Normalize content of the test path key

tmt.utils.normalize_path_list(key_address: str, value: None | str | list[str], logger: Logger) list[tmt.utils.Path]

Normalize a path-or-list-of-paths input value.

This is a fairly common input format present mostly in fmf nodes where tmt, to make things easier for humans, allows this:

foo: /foo/bar

foo:
  - /foo/bar
  - /baz

Internally, we should stick to one type only, and make sure whatever we get on the input, a list of strings would be the output.

Parameters:

value – input value from key source.

tmt.utils.normalize_shell_script(key_address: str, value: None | str, logger: Logger) ShellScript | None

Normalize a single shell script input that may be unset.

Parameters:

value – input value from key source.

tmt.utils.normalize_shell_script_list(key_address: str, value: None | str | list[str], logger: Logger) list[tmt.utils.ShellScript]

Normalize a string-or-list-of-strings input value.

This is a fairly common input format present mostly in fmf nodes where tmt, to make things easier for humans, allows this:

foo: bar

foo:
  - bar
  - baz

Internally, we should stick to one type only, and make sure whatever we get on the input, a list of strings would be the output.

Parameters:

value – input value from key source.

tmt.utils.normalize_storage_size(key_address: str, value: Any, logger: Logger) int

Normalize a storage size.

As of now, it’s just a simple integer with units interpreted by the owning plugin. In the future, we want this function to switch to proper units and return pint.Quantity instead.

tmt.utils.normalize_string_list(key_address: str, value: None | str | list[str], logger: Logger) list[str]

Normalize a string-or-list-of-strings input value.

This is a fairly common input format present mostly in fmf nodes where tmt, to make things easier for humans, allows this:

foo: bar

foo:
  - bar
  - baz

Internally, we should stick to one type only, and make sure whatever we get on the input, a list of strings would be the output.

Parameters:

value – input value from key source.

tmt.utils.option_to_key(option: str) str

Convert an option name to corresponding key name

tmt.utils.parse_rst(text: str) document

Parse a ReST document into docutils tree of nodes

tmt.utils.public_git_url(url: str) str

Convert a git url into a public format.

Parameters:

url – an URL to convert.

Returns:

URL that is publicly accessible without authentication, or the original URL if no applicable conversion was found.

tmt.utils.quote(string: str) str

Surround a string with double quotes

tmt.utils.remove_color(text: str) str

Remove ansi color sequences from the string

tmt.utils.render_exception(exception: BaseException) Iterator[str]

Render the exception and its causes for printing

tmt.utils.render_rst(text: str, logger: Logger) str

Render a ReST document

tmt.utils.render_run_exception(exception: RunError) Iterator[str]

Render detailed output upon command execution errors for printing

tmt.utils.render_run_exception_streams(stdout: str | None, stderr: str | None, verbose: int = 0) Iterator[str]

Render run exception output streams for printing

tmt.utils.render_template(template: str, template_filepath: Path | None = None, environment: Environment | None = None, **variables: Any) str

Render a template.

Parameters:
  • template – template to render.

  • template_filepath – path to the template file, if any.

  • environment – Jinja2 environment to use.

  • variables – variables to pass to the template.

tmt.utils.render_template_file(template_filepath: Path, environment: Environment | None = None, **variables: Any) str

Render a template from a file.

Parameters:
  • template_filepath – path to the template file.

  • environment – Jinja2 environment to use.

  • variables – variables to pass to the template.

tmt.utils.resource_files(path: str | Path, package: str | module = 'tmt') Path

Helper function to get path of package file or directory.

A thin wrapper for importlib.resources.files(): files() returns Traversable object, though in our use-case it should always produce a pathlib.PosixPath object. Converting it to tmt.utils.Path instance should be safe and stick to the “Path only!” rule in tmt’s code base.

Parameters:
  • path – file or directory path to retrieve, relative to the package root.

  • package – package in which to search for the file/directory.

Returns:

an absolute path to the requested file or directory.

tmt.utils.retry(func: Callable[[...], T], attempts: int, interval: int, label: str, logger: Logger, *args: Any, **kwargs: Any) T

Retry functionality to be used elsewhere in the code.

Parameters:
  • func – function to be called with all unclaimed positional and keyword arguments.

  • attempts – number of tries to call the function

  • interval – amount of seconds to wait before a new try

  • label – action to retry

Returns:

propagates return value of func.

class tmt.utils.retry_session(retries: int = 3, backoff_factor: float = 0.1, allowed_methods: tuple[str, ...] | None = None, status_forcelist: tuple[int, ...] | None = None, timeout: int | None = None)

Bases: AbstractContextManager

Context manager for requests.Session() with retries and timeout

static create(retries: int = 3, backoff_factor: float = 0.1, allowed_methods: tuple[str, ...] | None = None, status_forcelist: tuple[int, ...] | None = None, timeout: int | None = None) Session
tmt.utils.rewrite_git_url(url: str, patterns: list[tuple[str, str]]) str

Rewrite git url based on supplied patterns

Parameters:
  • url – an URL to modify

  • patterns – List of patterns to try in order

Returns:

Modified url or the original one if no pattern was be applied.

tmt.utils.sanitize_name(name: str, allow_slash: bool = True) str

Create a safe variant of a name that does not contain special characters.

Spaces and other special characters are removed to prevent problems with tools which do not expect them (e.g. in directory names).

Parameters:
  • name – a name to sanitize.

  • allow_slash – if set, even a slash character, /, would be replaced.

tmt.utils.shell_variables(data: list[str] | tuple[str, ...] | dict[str, Any]) list[str]

Prepare variables to be consumed by shell

Convert dictionary or list/tuple of key=value pairs to list of key=value pairs where value is quoted with shlex.quote().

tmt.utils.show_exception(exception: BaseException) None

Display the exception and its causes

tmt.utils.uniq(values: list[T]) list[T]

Return a list of all unique items from values

tmt.utils.validate_fmf_node(node: Tree, schema_name: str, logger: Logger) list[tuple[jsonschema.exceptions.ValidationError, str]]

Validate a given fmf node

tmt.utils.validate_git_status(test: Test) tuple[bool, str]

Validate that test has current metadata on fmf_id

Return a tuple (boolean, message) as the result of validation.

Checks that sources: - all local changes are committed - up to date on remote repository - .fmf/version marking fmf root is committed as well

When all checks pass returns (True, ‘’).

tmt.utils.verdict(decision: bool, comment: str | None = None, good: str = 'pass', bad: str = 'fail', problem: str = 'warn', **kwargs: Any) bool
tmt.utils.verdict(decision: None, comment: str | None = None, good: str = 'pass', bad: str = 'fail', problem: str = 'warn', **kwargs: Any) None

Print verdict in green, red or yellow based on the decision

The supported decision values are:

True …. good (green) False … bad (red) None …. problem (yellow)

Anything else raises an exception. Additional arguments are passed to the echo function. Returns back the decision.

tmt.utils.wait(parent: Common, check: Callable[[], T], timeout: timedelta, tick: float = 30.0, tick_increase: float = 1.0) T

Wait for a condition to become true.

To test the condition state, a check callback is called every tick seconds until check reports a success. The callback may:

  • decide the condition has been fulfilled. This is a successfull outcome, check shall then simply return, and waiting ends. Or,

  • decide more time is needed. This is not a successfull outcome, check shall then raise WaitingIncomplete exception, and wait() will try again later.

Parameters:
  • parent – “owner” of the wait process. Used for its logging capability.

  • check – a callable responsible for testing the condition. Accepts no arguments. To indicate more time and attempts are needed, the callable shall raise WaitingIncomplete, otherwise it shall return without exception. Its return value will be propagated by wait() up to wait()’s. All other exceptions raised by check will propagate to wait()’s caller as well, terminating the wait.

  • timeout – amount of time wait() is alowed to spend waiting for successfull outcome of check call.

  • tick – how many seconds to wait between two consecutive calls of check.

  • tick_increase – a multiplier applied to tick after every attempt.

Returns:

value returned by check reporting success.

Raises:
tmt.utils.web_git_url(url: str, ref: str, path: Path | None = None) str

Convert a public git url into a clickable web url format

Compose a clickable link from git url, ref and path to file for the most common git servers.

tmt.utils.yaml_to_dict(data: Any, yaml_type: Literal['rt', 'safe', 'unsafe', 'base'] | None = None) dict[Any, Any]

Convert yaml into dictionary

tmt.utils.yaml_to_list(data: Any, yaml_type: Literal['rt', 'safe', 'unsafe', 'base'] | None = 'safe') list[Any]

Convert yaml into list

Module contents

Test Management Tool