aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2025-09-02 13:31:10 +0400
committerMarc-André Lureau <marcandre.lureau@redhat.com>2025-09-03 16:18:12 +0400
commit402651d98f1a3635ee22b005cb4b4be15004daf0 (patch)
tree0b1529a23a2325c8a7b07c94ef51a8495c0efa24
parenta6f5d50239a64a26266a744f86ad2591e12c5fec (diff)
downloadlibvirt-ci-master.zip
libvirt-ci-master.tar.gz
libvirt-ci-master.tar.bz2
lcitool: complete the type annotationsHEADmaster
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
-rw-r--r--lcitool/__main__.py7
-rw-r--r--lcitool/ansible_wrapper.py2
-rw-r--r--lcitool/application.py77
-rw-r--r--lcitool/commandline.py37
-rw-r--r--pyproject.toml15
5 files changed, 79 insertions, 59 deletions
diff --git a/lcitool/__main__.py b/lcitool/__main__.py
index 99297a3..284eb4e 100644
--- a/lcitool/__main__.py
+++ b/lcitool/__main__.py
@@ -1,5 +1,6 @@
import sys
import logging
+from typing import Any
from lcitool.application import Application
from lcitool.commandline import CommandLine
@@ -7,11 +8,11 @@ from lcitool.logger import LevelFormatter
class LcitoolLogger(logging.Logger):
- def debug(self, *args, **kwargs):
+ def debug(self, *args: Any, **kwargs: Any) -> None:
super().debug(*args, **kwargs, exc_info=True)
-def main():
+def main() -> None:
log_level_formats = {
logging.DEBUG: "[%(levelname)s] %(module)s:%(funcName)s:%(lineno)d: %(message)s",
logging.INFO: "[%(levelname)s]: %(message)s",
@@ -40,4 +41,4 @@ def main():
if __name__ == "__main__":
- sys.exit(main())
+ main()
diff --git a/lcitool/ansible_wrapper.py b/lcitool/ansible_wrapper.py
index 8b5a01c..21e5c46 100644
--- a/lcitool/ansible_wrapper.py
+++ b/lcitool/ansible_wrapper.py
@@ -86,7 +86,7 @@ class AnsibleWrapper:
Any,
]
] = None,
- extravars: None = None,
+ extravars: Optional[Dict[str, Any]] = None,
) -> None:
"""
Prepares the Ansible runner execution environment.
diff --git a/lcitool/application.py b/lcitool/application.py
index f65fc3f..1b76d0c 100644
--- a/lcitool/application.py
+++ b/lcitool/application.py
@@ -7,12 +7,15 @@
import logging
import sys
import textwrap
+from typing import Any, Callable, Dict, Optional, Union
+import argparse
from pathlib import Path
from tempfile import TemporaryDirectory, NamedTemporaryFile
from lcitool import util, LcitoolError
from lcitool.config import Config
+from lcitool.util import DataDir
from lcitool.inventory import Inventory
from lcitool.packages import Packages
from lcitool.projects import Projects
@@ -26,14 +29,15 @@ from lcitool.formatters import (
from lcitool.formatters import ShellBuildEnvFormatter
from lcitool.manifest import Manifest
from lcitool.containers import Docker, Podman, ContainerExecError
+from lcitool.containers.containers import Container
log = logging.getLogger(__name__)
-def required_deps(*deps):
- def inner_decorator(func):
- def wrapped(*args, **kwargs):
+def required_deps(*deps: str) -> Callable:
+ def inner_decorator(func: Callable) -> Callable:
+ def wrapped(*args: Any, **kwargs: Any) -> Any:
cmd = func.__name__[len("_action_") :]
for dep in deps:
try:
@@ -52,18 +56,18 @@ def required_deps(*deps):
class ApplicationError(LcitoolError):
- def __init__(self, message):
+ def __init__(self, message: str) -> None:
super().__init__(message, "Application")
class Application:
- def __init__(self):
+ def __init__(self) -> None:
# make sure the lcitool cache dir exists
cache_dir_path = util.get_cache_dir()
cache_dir_path.mkdir(parents=True, exist_ok=True)
@staticmethod
- def _entrypoint_debug(args):
+ def _entrypoint_debug(args: argparse.Namespace) -> None:
cli_args = {}
for arg, val in vars(args).items():
if arg not in ["func", "debug"]:
@@ -71,8 +75,14 @@ class Application:
log.debug(f"Cmdline args={cli_args}")
def _execute_playbook(
- self, playbook, hosts_pattern, projects_pattern, config, data_dir, verbosity=0
- ):
+ self,
+ playbook: str,
+ hosts_pattern: str,
+ projects_pattern: str,
+ config_path: Optional[Path],
+ data_dir: DataDir,
+ verbosity: int = 0,
+ ) -> None:
from lcitool.ansible_wrapper import AnsibleWrapper
log.debug(
@@ -82,7 +92,7 @@ class Application:
)
base = util.package_resource(__package__, "ansible").as_posix()
- config = Config(config)
+ config = Config(config_path)
targets = Targets(data_dir)
packages = Packages(data_dir)
projects = Projects(data_dir)
@@ -98,12 +108,14 @@ class Application:
user_pre = False
if data_dir:
+ assert data_dir.path
ansible_path = Path(data_dir.path, "ansible")
if ansible_path.exists():
if Path(ansible_path, "pre/tasks/main.yml").exists():
user_pre = True
- extra_vars = config.values
+ extra_vars: Dict[str, Any] = {}
+ extra_vars.update(config.values)
extra_vars.update(
{
"base": base,
@@ -130,7 +142,7 @@ class Application:
)
ansible_runner.prepare_env(
- playbookdir=playbook_base,
+ playbookdir=None,
inventories=[inventory.ansible_inventory],
group_vars=group_vars,
extravars=extra_vars,
@@ -139,7 +151,7 @@ class Application:
ansible_runner.run_playbook(limit=hosts_expanded, verbosity=verbosity)
@required_deps("ansible_runner", "libvirt")
- def _action_hosts(self, args):
+ def _action_hosts(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
config_path = None
@@ -154,7 +166,7 @@ class Application:
for host in sorted(inventory.hosts):
print(host)
- def _action_targets(self, args):
+ def _action_targets(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
targets = Targets(args.data_dir)
@@ -167,7 +179,7 @@ class Application:
print(target)
- def _action_projects(self, args):
+ def _action_projects(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
projects = Projects(args.data_dir)
@@ -175,7 +187,7 @@ class Application:
print(project)
@required_deps("libvirt")
- def _action_install(self, args):
+ def _action_install(self, args: argparse.Namespace) -> None:
from lcitool.install import VirtInstall
self._entrypoint_debug(args)
@@ -230,7 +242,7 @@ class Application:
virt_install(wait=args.wait)
@required_deps("ansible_runner", "libvirt")
- def _action_update(self, args):
+ def _action_update(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
config_path = None
@@ -246,7 +258,7 @@ class Application:
args.verbose,
)
- def _action_variables(self, args):
+ def _action_variables(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
targets = Targets(args.data_dir)
@@ -254,6 +266,9 @@ class Application:
projects = Projects(args.data_dir)
projects_expanded = projects.expand_names(args.projects)
+ formatter: Union[
+ ShellVariablesFormatter, YamlVariablesFormatter, JSONVariablesFormatter
+ ]
if args.format == "shell":
formatter = ShellVariablesFormatter(projects)
elif args.format == "yaml":
@@ -280,7 +295,7 @@ class Application:
print(header + variables)
- def _action_dockerfile(self, args):
+ def _action_dockerfile(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
targets = Targets(args.data_dir)
@@ -308,7 +323,7 @@ class Application:
print(header + dockerfile)
- def _action_buildenvscript(self, args):
+ def _action_buildenvscript(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
targets = Targets(args.data_dir)
@@ -333,7 +348,7 @@ class Application:
print(header + buildenvscript)
- def _action_manifest(self, args):
+ def _action_manifest(self, args: argparse.Namespace) -> None:
base_path = None
if args.base_dir is not None:
base_path = Path(args.base_dir)
@@ -347,8 +362,8 @@ class Application:
manifest.generate(args.dry_run)
@staticmethod
- def _container_handle(engine):
- handle = Podman()
+ def _container_handle(engine: str) -> Container:
+ handle: Container = Podman()
if engine == "docker":
handle = Docker()
@@ -357,7 +372,7 @@ class Application:
return handle
- def _action_list_engines(self, args):
+ def _action_list_engines(self, args: argparse.Namespace) -> None:
engines = []
for engine in [Podman(), Docker()]:
if engine.available:
@@ -368,7 +383,7 @@ class Application:
else:
print("No engine available")
- def _action_container_build(self, args):
+ def _action_container_build(self, args: argparse.Namespace) -> None:
self._entrypoint_debug(args)
targets = Targets()
@@ -397,12 +412,12 @@ class Application:
log.debug(f"Generated Dockerfile copied to {_file}")
- engine.build(tag=tag, filepath=_file, **params)
+ engine.build(tag=tag, filepath=Path(_file), tempdir=Path(params["tempdir"]))
log.debug(f"Generated image tag --> {tag}")
print(f"Image '{tag}' successfully built.")
- def _get_container_run_common_params(self):
+ def _get_container_run_common_params(self) -> Dict[str, Any]:
params = {}
params["image"] = self.args.image
params["user"] = self.args.user
@@ -426,7 +441,9 @@ class Application:
return params
- def _container_run(self, container_params, shell=False):
+ def _container_run(
+ self, container_params: Dict[str, Any], shell: bool = False
+ ) -> int:
"""
Call into the container handle object.
@@ -444,19 +461,19 @@ class Application:
return engine.shell(**container_params)
return engine.run(**container_params)
- def _action_container_run(self, args):
+ def _action_container_run(self, args: argparse.Namespace) -> int:
self._entrypoint_debug(self.args)
params = self._get_container_run_common_params()
params["container_cmd"] = "./script"
return self._container_run(params)
- def _action_container_shell(self, args):
+ def _action_container_shell(self, args: argparse.Namespace) -> int:
self._entrypoint_debug(self.args)
return self._container_run(self._get_container_run_common_params(), shell=True)
- def run(self, args):
+ def run(self, args: argparse.Namespace) -> None:
try:
self.args = args
args.func(self, args)
diff --git a/lcitool/commandline.py b/lcitool/commandline.py
index fe58971..fc02c52 100644
--- a/lcitool/commandline.py
+++ b/lcitool/commandline.py
@@ -7,6 +7,7 @@
import sys
import logging
import argparse
+from typing import Any, List, Optional
from pathlib import Path
@@ -19,18 +20,34 @@ log = logging.getLogger(__name__)
class DataDirAction(argparse.Action):
- def __init__(self, option_strings, dest, default=DataDir(), nargs=None, **kwargs):
+ def __init__(
+ self,
+ option_strings: List[str],
+ dest: str,
+ default: DataDir = DataDir(),
+ nargs: Optional[Any] = None,
+ **kwargs: Any,
+ ) -> None:
if nargs is not None:
raise ValueError("nargs not allowed")
super().__init__(option_strings, dest, default=default, nargs=1, **kwargs)
- def __call__(self, parser, namespace, values, option_string=None):
- setattr(namespace, self.dest, DataDir(values[0]))
+ def __call__(
+ self,
+ parser: argparse.ArgumentParser,
+ namespace: argparse.Namespace,
+ values: Any,
+ option_string: Optional[str] = None,
+ ) -> None:
+ if isinstance(values, (list, tuple)) and values:
+ setattr(namespace, self.dest, DataDir(Path(str(values[0]))))
+ elif isinstance(values, str):
+ setattr(namespace, self.dest, DataDir(Path(values)))
class CommandLine:
- def __init__(self):
+ def __init__(self) -> None:
# Common option parsers to inherit from
hostsopt = argparse.ArgumentParser(add_help=False)
@@ -391,7 +408,7 @@ class CommandLine:
shell_containerparser.set_defaults(func=Application._action_container_shell)
@staticmethod
- def _validate_container(args):
+ def _validate_container(args: argparse.Namespace) -> None:
if args.container not in ["build", "run", "shell"]:
return
@@ -399,7 +416,7 @@ class CommandLine:
# "build" subcommand.
if args.container == "build":
if args.projects and args.target:
- return args
+ pass
else:
log.error("--target and --projects are required")
sys.exit(1)
@@ -412,16 +429,14 @@ class CommandLine:
sys.exit(1)
@staticmethod
- def _validate_install(args):
+ def _validate_install(args: argparse.Namespace) -> None:
if args.strategy == "template":
if not args.template:
log.error("--template is required with with --strategy=template")
sys.exit(1)
- return
-
# Main CLI validating method
- def _validate(self, args):
+ def _validate(self, args: argparse.Namespace) -> argparse.Namespace:
"""
Validate command line arguments.
:param args: argparse.Namespace object which contains
@@ -438,5 +453,5 @@ class CommandLine:
return args
- def parse(self):
+ def parse(self) -> argparse.Namespace:
return self._validate(self._parser.parse_args())
diff --git a/pyproject.toml b/pyproject.toml
index 47d0131..a3a81de 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -65,20 +65,7 @@ warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
files = [
- "lcitool/__init__.py",
- "lcitool/ansible_wrapper.py",
- "lcitool/config.py",
- "lcitool/containers/*.py",
- "lcitool/install/*.py",
- "lcitool/formatters.py",
- "lcitool/gitlab.py",
- "lcitool/inventory.py",
- "lcitool/libvirt_wrapper.py",
- "lcitool/logger.py",
- "lcitool/manifest.py",
- "lcitool/projects.py",
- "lcitool/targets.py",
- "lcitool/util.py",
+ "lcitool/",
]
[[tool.mypy.overrides]]