DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Juraj Linkeš" <juraj.linkes@pantheon.tech>
To: thomas@monjalon.net, Honnappa.Nagarahalli@arm.com,
	jspewock@iol.unh.edu, probb@iol.unh.edu, paul.szczepanek@arm.com,
	yoan.picchi@foss.arm.com, Luca.Vizzarro@arm.com
Cc: dev@dpdk.org, "Juraj Linkeš" <juraj.linkes@pantheon.tech>
Subject: [PATCH v8 01/21] dts: code adjustments for doc generation
Date: Thu, 23 Nov 2023 16:13:24 +0100	[thread overview]
Message-ID: <20231123151344.162812-2-juraj.linkes@pantheon.tech> (raw)
In-Reply-To: <20231123151344.162812-1-juraj.linkes@pantheon.tech>

The standard Python tool for generating API documentation, Sphinx,
imports modules one-by-one when generating the documentation. This
requires code changes:
* properly guarding argument parsing in the if __name__ == '__main__'
  block,
* the logger used by DTS runner underwent the same treatment so that it
  doesn't create log files outside of a DTS run,
* however, DTS uses the arguments to construct an object holding global
  variables. The defaults for the global variables needed to be moved
  from argument parsing elsewhere,
* importing the remote_session module from framework resulted in
  circular imports because of one module trying to import another
  module. This is fixed by reorganizing the code,
* some code reorganization was done because the resulting structure
  makes more sense, improving documentation clarity.

The are some other changes which are documentation related:
* added missing type annotation so they appear in the generated docs,
* reordered arguments in some methods,
* removed superfluous arguments and attributes,
* change private functions/methods/attributes to private and vice-versa.

The above all appear in the generated documentation and the with them,
the documentation is improved.

Signed-off-by: Juraj Linkeš <juraj.linkes@pantheon.tech>
---
 dts/framework/config/__init__.py              |  8 +-
 dts/framework/dts.py                          | 31 +++++--
 dts/framework/exception.py                    | 54 +++++-------
 dts/framework/remote_session/__init__.py      | 41 +++++----
 .../interactive_remote_session.py             |  0
 .../{remote => }/interactive_shell.py         |  0
 .../{remote => }/python_shell.py              |  0
 .../remote_session/remote/__init__.py         | 27 ------
 .../{remote => }/remote_session.py            |  0
 .../{remote => }/ssh_session.py               | 12 +--
 .../{remote => }/testpmd_shell.py             |  0
 dts/framework/settings.py                     | 85 +++++++++++--------
 dts/framework/test_result.py                  |  4 +-
 dts/framework/test_suite.py                   |  7 +-
 dts/framework/testbed_model/__init__.py       | 12 +--
 dts/framework/testbed_model/{hw => }/cpu.py   | 13 +++
 dts/framework/testbed_model/hw/__init__.py    | 27 ------
 .../linux_session.py                          |  6 +-
 dts/framework/testbed_model/node.py           | 23 +++--
 .../os_session.py                             | 22 ++---
 dts/framework/testbed_model/{hw => }/port.py  |  0
 .../posix_session.py                          |  4 +-
 dts/framework/testbed_model/sut_node.py       |  8 +-
 dts/framework/testbed_model/tg_node.py        | 29 +------
 .../traffic_generator/__init__.py             | 23 +++++
 .../capturing_traffic_generator.py            |  4 +-
 .../{ => traffic_generator}/scapy.py          | 19 ++---
 .../traffic_generator.py                      | 14 ++-
 .../testbed_model/{hw => }/virtual_device.py  |  0
 dts/framework/utils.py                        | 40 +++------
 dts/main.py                                   |  9 +-
 31 files changed, 244 insertions(+), 278 deletions(-)
 rename dts/framework/remote_session/{remote => }/interactive_remote_session.py (100%)
 rename dts/framework/remote_session/{remote => }/interactive_shell.py (100%)
 rename dts/framework/remote_session/{remote => }/python_shell.py (100%)
 delete mode 100644 dts/framework/remote_session/remote/__init__.py
 rename dts/framework/remote_session/{remote => }/remote_session.py (100%)
 rename dts/framework/remote_session/{remote => }/ssh_session.py (91%)
 rename dts/framework/remote_session/{remote => }/testpmd_shell.py (100%)
 rename dts/framework/testbed_model/{hw => }/cpu.py (95%)
 delete mode 100644 dts/framework/testbed_model/hw/__init__.py
 rename dts/framework/{remote_session => testbed_model}/linux_session.py (97%)
 rename dts/framework/{remote_session => testbed_model}/os_session.py (95%)
 rename dts/framework/testbed_model/{hw => }/port.py (100%)
 rename dts/framework/{remote_session => testbed_model}/posix_session.py (98%)
 create mode 100644 dts/framework/testbed_model/traffic_generator/__init__.py
 rename dts/framework/testbed_model/{ => traffic_generator}/capturing_traffic_generator.py (98%)
 rename dts/framework/testbed_model/{ => traffic_generator}/scapy.py (95%)
 rename dts/framework/testbed_model/{ => traffic_generator}/traffic_generator.py (81%)
 rename dts/framework/testbed_model/{hw => }/virtual_device.py (100%)

diff --git a/dts/framework/config/__init__.py b/dts/framework/config/__init__.py
index 9b32cf0532..ef25a463c0 100644
--- a/dts/framework/config/__init__.py
+++ b/dts/framework/config/__init__.py
@@ -17,6 +17,7 @@
 import warlock  # type: ignore[import]
 import yaml
 
+from framework.exception import ConfigurationError
 from framework.settings import SETTINGS
 from framework.utils import StrEnum
 
@@ -89,7 +90,7 @@ class TrafficGeneratorConfig:
     traffic_generator_type: TrafficGeneratorType
 
     @staticmethod
-    def from_dict(d: dict):
+    def from_dict(d: dict) -> "ScapyTrafficGeneratorConfig":
         # This looks useless now, but is designed to allow expansion to traffic
         # generators that require more configuration later.
         match TrafficGeneratorType(d["type"]):
@@ -97,6 +98,8 @@ def from_dict(d: dict):
                 return ScapyTrafficGeneratorConfig(
                     traffic_generator_type=TrafficGeneratorType.SCAPY
                 )
+            case _:
+                raise ConfigurationError(f'Unknown traffic generator type "{d["type"]}".')
 
 
 @dataclass(slots=True, frozen=True)
@@ -314,6 +317,3 @@ def load_config() -> Configuration:
     config: dict[str, Any] = warlock.model_factory(schema, name="_Config")(config_data)
     config_obj: Configuration = Configuration.from_dict(dict(config))
     return config_obj
-
-
-CONFIGURATION = load_config()
diff --git a/dts/framework/dts.py b/dts/framework/dts.py
index 25d6942d81..356368ef10 100644
--- a/dts/framework/dts.py
+++ b/dts/framework/dts.py
@@ -6,19 +6,19 @@
 import sys
 
 from .config import (
-    CONFIGURATION,
     BuildTargetConfiguration,
     ExecutionConfiguration,
     TestSuiteConfig,
+    load_config,
 )
 from .exception import BlockingTestSuiteError
 from .logger import DTSLOG, getLogger
 from .test_result import BuildTargetResult, DTSResult, ExecutionResult, Result
 from .test_suite import get_test_suites
 from .testbed_model import SutNode, TGNode
-from .utils import check_dts_python_version
 
-dts_logger: DTSLOG = getLogger("DTSRunner")
+# dummy defaults to satisfy linters
+dts_logger: DTSLOG = None  # type: ignore[assignment]
 result: DTSResult = DTSResult(dts_logger)
 
 
@@ -30,14 +30,18 @@ def run_all() -> None:
     global dts_logger
     global result
 
+    # create a regular DTS logger and create a new result with it
+    dts_logger = getLogger("DTSRunner")
+    result = DTSResult(dts_logger)
+
     # check the python version of the server that run dts
-    check_dts_python_version()
+    _check_dts_python_version()
 
     sut_nodes: dict[str, SutNode] = {}
     tg_nodes: dict[str, TGNode] = {}
     try:
         # for all Execution sections
-        for execution in CONFIGURATION.executions:
+        for execution in load_config().executions:
             sut_node = sut_nodes.get(execution.system_under_test_node.name)
             tg_node = tg_nodes.get(execution.traffic_generator_node.name)
 
@@ -82,6 +86,23 @@ def run_all() -> None:
     _exit_dts()
 
 
+def _check_dts_python_version() -> None:
+    def RED(text: str) -> str:
+        return f"\u001B[31;1m{str(text)}\u001B[0m"
+
+    if sys.version_info.major < 3 or (sys.version_info.major == 3 and sys.version_info.minor < 10):
+        print(
+            RED(
+                (
+                    "WARNING: DTS execution node's python version is lower than"
+                    "python 3.10, is deprecated and will not work in future releases."
+                )
+            ),
+            file=sys.stderr,
+        )
+        print(RED("Please use Python >= 3.10 instead"), file=sys.stderr)
+
+
 def _run_execution(
     sut_node: SutNode,
     tg_node: TGNode,
diff --git a/dts/framework/exception.py b/dts/framework/exception.py
index b362e42924..151e4d3aa9 100644
--- a/dts/framework/exception.py
+++ b/dts/framework/exception.py
@@ -42,19 +42,14 @@ class SSHTimeoutError(DTSError):
     Command execution timeout.
     """
 
-    command: str
-    output: str
     severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR
+    _command: str
 
-    def __init__(self, command: str, output: str):
-        self.command = command
-        self.output = output
+    def __init__(self, command: str):
+        self._command = command
 
     def __str__(self) -> str:
-        return f"TIMEOUT on {self.command}"
-
-    def get_output(self) -> str:
-        return self.output
+        return f"TIMEOUT on {self._command}"
 
 
 class SSHConnectionError(DTSError):
@@ -62,18 +57,18 @@ class SSHConnectionError(DTSError):
     SSH connection error.
     """
 
-    host: str
-    errors: list[str]
     severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR
+    _host: str
+    _errors: list[str]
 
     def __init__(self, host: str, errors: list[str] | None = None):
-        self.host = host
-        self.errors = [] if errors is None else errors
+        self._host = host
+        self._errors = [] if errors is None else errors
 
     def __str__(self) -> str:
-        message = f"Error trying to connect with {self.host}."
-        if self.errors:
-            message += f" Errors encountered while retrying: {', '.join(self.errors)}"
+        message = f"Error trying to connect with {self._host}."
+        if self._errors:
+            message += f" Errors encountered while retrying: {', '.join(self._errors)}"
 
         return message
 
@@ -84,14 +79,14 @@ class SSHSessionDeadError(DTSError):
     It can no longer be used.
     """
 
-    host: str
     severity: ClassVar[ErrorSeverity] = ErrorSeverity.SSH_ERR
+    _host: str
 
     def __init__(self, host: str):
-        self.host = host
+        self._host = host
 
     def __str__(self) -> str:
-        return f"SSH session with {self.host} has died"
+        return f"SSH session with {self._host} has died"
 
 
 class ConfigurationError(DTSError):
@@ -107,16 +102,16 @@ class RemoteCommandExecutionError(DTSError):
     Raised when a command executed on a Node returns a non-zero exit status.
     """
 
-    command: str
-    command_return_code: int
     severity: ClassVar[ErrorSeverity] = ErrorSeverity.REMOTE_CMD_EXEC_ERR
+    command: str
+    _command_return_code: int
 
     def __init__(self, command: str, command_return_code: int):
         self.command = command
-        self.command_return_code = command_return_code
+        self._command_return_code = command_return_code
 
     def __str__(self) -> str:
-        return f"Command {self.command} returned a non-zero exit code: {self.command_return_code}"
+        return f"Command {self.command} returned a non-zero exit code: {self._command_return_code}"
 
 
 class RemoteDirectoryExistsError(DTSError):
@@ -140,22 +135,15 @@ class TestCaseVerifyError(DTSError):
     Used in test cases to verify the expected behavior.
     """
 
-    value: str
     severity: ClassVar[ErrorSeverity] = ErrorSeverity.TESTCASE_VERIFY_ERR
 
-    def __init__(self, value: str):
-        self.value = value
-
-    def __str__(self) -> str:
-        return repr(self.value)
-
 
 class BlockingTestSuiteError(DTSError):
-    suite_name: str
     severity: ClassVar[ErrorSeverity] = ErrorSeverity.BLOCKING_TESTSUITE_ERR
+    _suite_name: str
 
     def __init__(self, suite_name: str) -> None:
-        self.suite_name = suite_name
+        self._suite_name = suite_name
 
     def __str__(self) -> str:
-        return f"Blocking suite {self.suite_name} failed."
+        return f"Blocking suite {self._suite_name} failed."
diff --git a/dts/framework/remote_session/__init__.py b/dts/framework/remote_session/__init__.py
index 6124417bd7..5e7ddb2b05 100644
--- a/dts/framework/remote_session/__init__.py
+++ b/dts/framework/remote_session/__init__.py
@@ -12,27 +12,24 @@
 
 # pylama:ignore=W0611
 
-from framework.config import OS, NodeConfiguration
-from framework.exception import ConfigurationError
+from framework.config import NodeConfiguration
 from framework.logger import DTSLOG
 
-from .linux_session import LinuxSession
-from .os_session import InteractiveShellType, OSSession
-from .remote import (
-    CommandResult,
-    InteractiveRemoteSession,
-    InteractiveShell,
-    PythonShell,
-    RemoteSession,
-    SSHSession,
-    TestPmdDevice,
-    TestPmdShell,
-)
-
-
-def create_session(node_config: NodeConfiguration, name: str, logger: DTSLOG) -> OSSession:
-    match node_config.os:
-        case OS.linux:
-            return LinuxSession(node_config, name, logger)
-        case _:
-            raise ConfigurationError(f"Unsupported OS {node_config.os}")
+from .interactive_remote_session import InteractiveRemoteSession
+from .interactive_shell import InteractiveShell
+from .python_shell import PythonShell
+from .remote_session import CommandResult, RemoteSession
+from .ssh_session import SSHSession
+from .testpmd_shell import TestPmdShell
+
+
+def create_remote_session(
+    node_config: NodeConfiguration, name: str, logger: DTSLOG
+) -> RemoteSession:
+    return SSHSession(node_config, name, logger)
+
+
+def create_interactive_session(
+    node_config: NodeConfiguration, logger: DTSLOG
+) -> InteractiveRemoteSession:
+    return InteractiveRemoteSession(node_config, logger)
diff --git a/dts/framework/remote_session/remote/interactive_remote_session.py b/dts/framework/remote_session/interactive_remote_session.py
similarity index 100%
rename from dts/framework/remote_session/remote/interactive_remote_session.py
rename to dts/framework/remote_session/interactive_remote_session.py
diff --git a/dts/framework/remote_session/remote/interactive_shell.py b/dts/framework/remote_session/interactive_shell.py
similarity index 100%
rename from dts/framework/remote_session/remote/interactive_shell.py
rename to dts/framework/remote_session/interactive_shell.py
diff --git a/dts/framework/remote_session/remote/python_shell.py b/dts/framework/remote_session/python_shell.py
similarity index 100%
rename from dts/framework/remote_session/remote/python_shell.py
rename to dts/framework/remote_session/python_shell.py
diff --git a/dts/framework/remote_session/remote/__init__.py b/dts/framework/remote_session/remote/__init__.py
deleted file mode 100644
index 06403691a5..0000000000
--- a/dts/framework/remote_session/remote/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2023 PANTHEON.tech s.r.o.
-# Copyright(c) 2023 University of New Hampshire
-
-# pylama:ignore=W0611
-
-from framework.config import NodeConfiguration
-from framework.logger import DTSLOG
-
-from .interactive_remote_session import InteractiveRemoteSession
-from .interactive_shell import InteractiveShell
-from .python_shell import PythonShell
-from .remote_session import CommandResult, RemoteSession
-from .ssh_session import SSHSession
-from .testpmd_shell import TestPmdDevice, TestPmdShell
-
-
-def create_remote_session(
-    node_config: NodeConfiguration, name: str, logger: DTSLOG
-) -> RemoteSession:
-    return SSHSession(node_config, name, logger)
-
-
-def create_interactive_session(
-    node_config: NodeConfiguration, logger: DTSLOG
-) -> InteractiveRemoteSession:
-    return InteractiveRemoteSession(node_config, logger)
diff --git a/dts/framework/remote_session/remote/remote_session.py b/dts/framework/remote_session/remote_session.py
similarity index 100%
rename from dts/framework/remote_session/remote/remote_session.py
rename to dts/framework/remote_session/remote_session.py
diff --git a/dts/framework/remote_session/remote/ssh_session.py b/dts/framework/remote_session/ssh_session.py
similarity index 91%
rename from dts/framework/remote_session/remote/ssh_session.py
rename to dts/framework/remote_session/ssh_session.py
index 1a7ee649ab..a467033a13 100644
--- a/dts/framework/remote_session/remote/ssh_session.py
+++ b/dts/framework/remote_session/ssh_session.py
@@ -18,9 +18,7 @@
     SSHException,
 )
 
-from framework.config import NodeConfiguration
 from framework.exception import SSHConnectionError, SSHSessionDeadError, SSHTimeoutError
-from framework.logger import DTSLOG
 
 from .remote_session import CommandResult, RemoteSession
 
@@ -45,14 +43,6 @@ class SSHSession(RemoteSession):
 
     session: Connection
 
-    def __init__(
-        self,
-        node_config: NodeConfiguration,
-        session_name: str,
-        logger: DTSLOG,
-    ):
-        super(SSHSession, self).__init__(node_config, session_name, logger)
-
     def _connect(self) -> None:
         errors = []
         retry_attempts = 10
@@ -111,7 +101,7 @@ def _send_command(self, command: str, timeout: float, env: dict | None) -> Comma
 
         except CommandTimedOut as e:
             self._logger.exception(e)
-            raise SSHTimeoutError(command, e.result.stderr) from e
+            raise SSHTimeoutError(command) from e
 
         return CommandResult(self.name, command, output.stdout, output.stderr, output.return_code)
 
diff --git a/dts/framework/remote_session/remote/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
similarity index 100%
rename from dts/framework/remote_session/remote/testpmd_shell.py
rename to dts/framework/remote_session/testpmd_shell.py
diff --git a/dts/framework/settings.py b/dts/framework/settings.py
index 974793a11a..25b5dcff22 100644
--- a/dts/framework/settings.py
+++ b/dts/framework/settings.py
@@ -6,7 +6,7 @@
 import argparse
 import os
 from collections.abc import Callable, Iterable, Sequence
-from dataclasses import dataclass
+from dataclasses import dataclass, field
 from pathlib import Path
 from typing import Any, TypeVar
 
@@ -22,8 +22,8 @@ def __init__(
             option_strings: Sequence[str],
             dest: str,
             nargs: str | int | None = None,
-            const: str | None = None,
-            default: str = None,
+            const: bool | None = None,
+            default: Any = None,
             type: Callable[[str], _T | argparse.FileType | None] = None,
             choices: Iterable[_T] | None = None,
             required: bool = False,
@@ -32,6 +32,12 @@ def __init__(
         ) -> None:
             env_var_value = os.environ.get(env_var)
             default = env_var_value or default
+            if const is not None:
+                nargs = 0
+                default = const if env_var_value else default
+                type = None
+                choices = None
+                metavar = None
             super(_EnvironmentArgument, self).__init__(
                 option_strings,
                 dest,
@@ -52,22 +58,28 @@ def __call__(
             values: Any,
             option_string: str = None,
         ) -> None:
-            setattr(namespace, self.dest, values)
+            if self.const is not None:
+                setattr(namespace, self.dest, self.const)
+            else:
+                setattr(namespace, self.dest, values)
 
     return _EnvironmentArgument
 
 
-@dataclass(slots=True, frozen=True)
-class _Settings:
-    config_file_path: str
-    output_dir: str
-    timeout: float
-    verbose: bool
-    skip_setup: bool
-    dpdk_tarball_path: Path
-    compile_timeout: float
-    test_cases: list
-    re_run: int
+@dataclass(slots=True)
+class Settings:
+    config_file_path: Path = Path(__file__).parent.parent.joinpath("conf.yaml")
+    output_dir: str = "output"
+    timeout: float = 15
+    verbose: bool = False
+    skip_setup: bool = False
+    dpdk_tarball_path: Path | str = "dpdk.tar.xz"
+    compile_timeout: float = 1200
+    test_cases: list[str] = field(default_factory=list)
+    re_run: int = 0
+
+
+SETTINGS: Settings = Settings()
 
 
 def _get_parser() -> argparse.ArgumentParser:
@@ -80,7 +92,8 @@ def _get_parser() -> argparse.ArgumentParser:
     parser.add_argument(
         "--config-file",
         action=_env_arg("DTS_CFG_FILE"),
-        default="conf.yaml",
+        default=SETTINGS.config_file_path,
+        type=Path,
         help="[DTS_CFG_FILE] configuration file that describes the test cases, SUTs and targets.",
     )
 
@@ -88,7 +101,7 @@ def _get_parser() -> argparse.ArgumentParser:
         "--output-dir",
         "--output",
         action=_env_arg("DTS_OUTPUT_DIR"),
-        default="output",
+        default=SETTINGS.output_dir,
         help="[DTS_OUTPUT_DIR] Output directory where dts logs and results are saved.",
     )
 
@@ -96,7 +109,7 @@ def _get_parser() -> argparse.ArgumentParser:
         "-t",
         "--timeout",
         action=_env_arg("DTS_TIMEOUT"),
-        default=15,
+        default=SETTINGS.timeout,
         type=float,
         help="[DTS_TIMEOUT] The default timeout for all DTS operations except for compiling DPDK.",
     )
@@ -105,8 +118,9 @@ def _get_parser() -> argparse.ArgumentParser:
         "-v",
         "--verbose",
         action=_env_arg("DTS_VERBOSE"),
-        default="N",
-        help="[DTS_VERBOSE] Set to 'Y' to enable verbose output, logging all messages "
+        default=SETTINGS.verbose,
+        const=True,
+        help="[DTS_VERBOSE] Specify to enable verbose output, logging all messages "
         "to the console.",
     )
 
@@ -114,8 +128,8 @@ def _get_parser() -> argparse.ArgumentParser:
         "-s",
         "--skip-setup",
         action=_env_arg("DTS_SKIP_SETUP"),
-        default="N",
-        help="[DTS_SKIP_SETUP] Set to 'Y' to skip all setup steps on SUT and TG nodes.",
+        const=True,
+        help="[DTS_SKIP_SETUP] Specify to skip all setup steps on SUT and TG nodes.",
     )
 
     parser.add_argument(
@@ -123,7 +137,7 @@ def _get_parser() -> argparse.ArgumentParser:
         "--snapshot",
         "--git-ref",
         action=_env_arg("DTS_DPDK_TARBALL"),
-        default="dpdk.tar.xz",
+        default=SETTINGS.dpdk_tarball_path,
         type=Path,
         help="[DTS_DPDK_TARBALL] Path to DPDK source code tarball or a git commit ID, "
         "tag ID or tree ID to test. To test local changes, first commit them, "
@@ -133,7 +147,7 @@ def _get_parser() -> argparse.ArgumentParser:
     parser.add_argument(
         "--compile-timeout",
         action=_env_arg("DTS_COMPILE_TIMEOUT"),
-        default=1200,
+        default=SETTINGS.compile_timeout,
         type=float,
         help="[DTS_COMPILE_TIMEOUT] The timeout for compiling DPDK.",
     )
@@ -150,7 +164,7 @@ def _get_parser() -> argparse.ArgumentParser:
         "--re-run",
         "--re_run",
         action=_env_arg("DTS_RERUN"),
-        default=0,
+        default=SETTINGS.re_run,
         type=int,
         help="[DTS_RERUN] Re-run each test case the specified amount of times "
         "if a test failure occurs",
@@ -159,21 +173,20 @@ def _get_parser() -> argparse.ArgumentParser:
     return parser
 
 
-def _get_settings() -> _Settings:
+def get_settings() -> Settings:
     parsed_args = _get_parser().parse_args()
-    return _Settings(
+    return Settings(
         config_file_path=parsed_args.config_file,
         output_dir=parsed_args.output_dir,
         timeout=parsed_args.timeout,
-        verbose=(parsed_args.verbose == "Y"),
-        skip_setup=(parsed_args.skip_setup == "Y"),
-        dpdk_tarball_path=Path(DPDKGitTarball(parsed_args.tarball, parsed_args.output_dir))
-        if not os.path.exists(parsed_args.tarball)
-        else Path(parsed_args.tarball),
+        verbose=parsed_args.verbose,
+        skip_setup=parsed_args.skip_setup,
+        dpdk_tarball_path=Path(
+            Path(DPDKGitTarball(parsed_args.tarball, parsed_args.output_dir))
+            if not os.path.exists(parsed_args.tarball)
+            else Path(parsed_args.tarball)
+        ),
         compile_timeout=parsed_args.compile_timeout,
-        test_cases=parsed_args.test_cases.split(",") if parsed_args.test_cases else [],
+        test_cases=(parsed_args.test_cases.split(",") if parsed_args.test_cases else []),
         re_run=parsed_args.re_run,
     )
-
-
-SETTINGS: _Settings = _get_settings()
diff --git a/dts/framework/test_result.py b/dts/framework/test_result.py
index 4c2e7e2418..57090feb04 100644
--- a/dts/framework/test_result.py
+++ b/dts/framework/test_result.py
@@ -246,7 +246,7 @@ def add_build_target(self, build_target: BuildTargetConfiguration) -> BuildTarge
         self._inner_results.append(build_target_result)
         return build_target_result
 
-    def add_sut_info(self, sut_info: NodeInfo):
+    def add_sut_info(self, sut_info: NodeInfo) -> None:
         self.sut_os_name = sut_info.os_name
         self.sut_os_version = sut_info.os_version
         self.sut_kernel_version = sut_info.kernel_version
@@ -289,7 +289,7 @@ def add_execution(self, sut_node: NodeConfiguration) -> ExecutionResult:
         self._inner_results.append(execution_result)
         return execution_result
 
-    def add_error(self, error) -> None:
+    def add_error(self, error: Exception) -> None:
         self._errors.append(error)
 
     def process(self) -> None:
diff --git a/dts/framework/test_suite.py b/dts/framework/test_suite.py
index 4a7907ec33..f9e66e814a 100644
--- a/dts/framework/test_suite.py
+++ b/dts/framework/test_suite.py
@@ -11,7 +11,7 @@
 import re
 from ipaddress import IPv4Interface, IPv6Interface, ip_interface
 from types import MethodType
-from typing import Union
+from typing import Any, Union
 
 from scapy.layers.inet import IP  # type: ignore[import]
 from scapy.layers.l2 import Ether  # type: ignore[import]
@@ -26,8 +26,7 @@
 from .logger import DTSLOG, getLogger
 from .settings import SETTINGS
 from .test_result import BuildTargetResult, Result, TestCaseResult, TestSuiteResult
-from .testbed_model import SutNode, TGNode
-from .testbed_model.hw.port import Port, PortLink
+from .testbed_model import Port, PortLink, SutNode, TGNode
 from .utils import get_packet_summaries
 
 
@@ -426,7 +425,7 @@ def _execute_test_case(
 
 
 def get_test_suites(testsuite_module_path: str) -> list[type[TestSuite]]:
-    def is_test_suite(object) -> bool:
+    def is_test_suite(object: Any) -> bool:
         try:
             if issubclass(object, TestSuite) and object is not TestSuite:
                 return True
diff --git a/dts/framework/testbed_model/__init__.py b/dts/framework/testbed_model/__init__.py
index 5cbb859e47..8ced05653b 100644
--- a/dts/framework/testbed_model/__init__.py
+++ b/dts/framework/testbed_model/__init__.py
@@ -9,15 +9,9 @@
 
 # pylama:ignore=W0611
 
-from .hw import (
-    LogicalCore,
-    LogicalCoreCount,
-    LogicalCoreCountFilter,
-    LogicalCoreList,
-    LogicalCoreListFilter,
-    VirtualDevice,
-    lcore_filter,
-)
+from .cpu import LogicalCoreCount, LogicalCoreCountFilter, LogicalCoreList
 from .node import Node
+from .port import Port, PortLink
 from .sut_node import SutNode
 from .tg_node import TGNode
+from .virtual_device import VirtualDevice
diff --git a/dts/framework/testbed_model/hw/cpu.py b/dts/framework/testbed_model/cpu.py
similarity index 95%
rename from dts/framework/testbed_model/hw/cpu.py
rename to dts/framework/testbed_model/cpu.py
index cbc5fe7fff..1b392689f5 100644
--- a/dts/framework/testbed_model/hw/cpu.py
+++ b/dts/framework/testbed_model/cpu.py
@@ -262,3 +262,16 @@ def filter(self) -> list[LogicalCore]:
             )
 
         return filtered_lcores
+
+
+def lcore_filter(
+    core_list: list[LogicalCore],
+    filter_specifier: LogicalCoreCount | LogicalCoreList,
+    ascending: bool,
+) -> LogicalCoreFilter:
+    if isinstance(filter_specifier, LogicalCoreList):
+        return LogicalCoreListFilter(core_list, filter_specifier, ascending)
+    elif isinstance(filter_specifier, LogicalCoreCount):
+        return LogicalCoreCountFilter(core_list, filter_specifier, ascending)
+    else:
+        raise ValueError(f"Unsupported filter r{filter_specifier}")
diff --git a/dts/framework/testbed_model/hw/__init__.py b/dts/framework/testbed_model/hw/__init__.py
deleted file mode 100644
index 88ccac0b0e..0000000000
--- a/dts/framework/testbed_model/hw/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2023 PANTHEON.tech s.r.o.
-
-# pylama:ignore=W0611
-
-from .cpu import (
-    LogicalCore,
-    LogicalCoreCount,
-    LogicalCoreCountFilter,
-    LogicalCoreFilter,
-    LogicalCoreList,
-    LogicalCoreListFilter,
-)
-from .virtual_device import VirtualDevice
-
-
-def lcore_filter(
-    core_list: list[LogicalCore],
-    filter_specifier: LogicalCoreCount | LogicalCoreList,
-    ascending: bool,
-) -> LogicalCoreFilter:
-    if isinstance(filter_specifier, LogicalCoreList):
-        return LogicalCoreListFilter(core_list, filter_specifier, ascending)
-    elif isinstance(filter_specifier, LogicalCoreCount):
-        return LogicalCoreCountFilter(core_list, filter_specifier, ascending)
-    else:
-        raise ValueError(f"Unsupported filter r{filter_specifier}")
diff --git a/dts/framework/remote_session/linux_session.py b/dts/framework/testbed_model/linux_session.py
similarity index 97%
rename from dts/framework/remote_session/linux_session.py
rename to dts/framework/testbed_model/linux_session.py
index fd877fbfae..055765ba2d 100644
--- a/dts/framework/remote_session/linux_session.py
+++ b/dts/framework/testbed_model/linux_session.py
@@ -9,10 +9,10 @@
 from typing_extensions import NotRequired
 
 from framework.exception import RemoteCommandExecutionError
-from framework.testbed_model import LogicalCore
-from framework.testbed_model.hw.port import Port
 from framework.utils import expand_range
 
+from .cpu import LogicalCore
+from .port import Port
 from .posix_session import PosixSession
 
 
@@ -64,7 +64,7 @@ def get_remote_cpus(self, use_first_core: bool) -> list[LogicalCore]:
             lcores.append(LogicalCore(lcore, core, socket, node))
         return lcores
 
-    def get_dpdk_file_prefix(self, dpdk_prefix) -> str:
+    def get_dpdk_file_prefix(self, dpdk_prefix: str) -> str:
         return dpdk_prefix
 
     def setup_hugepages(self, hugepage_amount: int, force_first_numa: bool) -> None:
diff --git a/dts/framework/testbed_model/node.py b/dts/framework/testbed_model/node.py
index ef700d8114..b313b5ad54 100644
--- a/dts/framework/testbed_model/node.py
+++ b/dts/framework/testbed_model/node.py
@@ -12,23 +12,26 @@
 from typing import Any, Callable, Type, Union
 
 from framework.config import (
+    OS,
     BuildTargetConfiguration,
     ExecutionConfiguration,
     NodeConfiguration,
 )
+from framework.exception import ConfigurationError
 from framework.logger import DTSLOG, getLogger
-from framework.remote_session import InteractiveShellType, OSSession, create_session
 from framework.settings import SETTINGS
 
-from .hw import (
+from .cpu import (
     LogicalCore,
     LogicalCoreCount,
     LogicalCoreList,
     LogicalCoreListFilter,
-    VirtualDevice,
     lcore_filter,
 )
-from .hw.port import Port
+from .linux_session import LinuxSession
+from .os_session import InteractiveShellType, OSSession
+from .port import Port
+from .virtual_device import VirtualDevice
 
 
 class Node(ABC):
@@ -168,9 +171,9 @@ def create_interactive_shell(
 
         return self.main_session.create_interactive_shell(
             shell_cls,
-            app_args,
             timeout,
             privileged,
+            app_args,
         )
 
     def filter_lcores(
@@ -201,7 +204,7 @@ def _get_remote_cpus(self) -> None:
         self._logger.info("Getting CPU information.")
         self.lcores = self.main_session.get_remote_cpus(self.config.use_first_core)
 
-    def _setup_hugepages(self):
+    def _setup_hugepages(self) -> None:
         """
         Setup hugepages on the Node. Different architectures can supply different
         amounts of memory for hugepages and numa-based hugepage allocation may need
@@ -245,3 +248,11 @@ def skip_setup(func: Callable[..., Any]) -> Callable[..., Any]:
             return lambda *args: None
         else:
             return func
+
+
+def create_session(node_config: NodeConfiguration, name: str, logger: DTSLOG) -> OSSession:
+    match node_config.os:
+        case OS.linux:
+            return LinuxSession(node_config, name, logger)
+        case _:
+            raise ConfigurationError(f"Unsupported OS {node_config.os}")
diff --git a/dts/framework/remote_session/os_session.py b/dts/framework/testbed_model/os_session.py
similarity index 95%
rename from dts/framework/remote_session/os_session.py
rename to dts/framework/testbed_model/os_session.py
index 8a709eac1c..76e595a518 100644
--- a/dts/framework/remote_session/os_session.py
+++ b/dts/framework/testbed_model/os_session.py
@@ -10,19 +10,19 @@
 
 from framework.config import Architecture, NodeConfiguration, NodeInfo
 from framework.logger import DTSLOG
-from framework.remote_session.remote import InteractiveShell
-from framework.settings import SETTINGS
-from framework.testbed_model import LogicalCore
-from framework.testbed_model.hw.port import Port
-from framework.utils import MesonArgs
-
-from .remote import (
+from framework.remote_session import (
     CommandResult,
     InteractiveRemoteSession,
+    InteractiveShell,
     RemoteSession,
     create_interactive_session,
     create_remote_session,
 )
+from framework.settings import SETTINGS
+from framework.utils import MesonArgs
+
+from .cpu import LogicalCore
+from .port import Port
 
 InteractiveShellType = TypeVar("InteractiveShellType", bound=InteractiveShell)
 
@@ -85,9 +85,9 @@ def send_command(
     def create_interactive_shell(
         self,
         shell_cls: Type[InteractiveShellType],
-        eal_parameters: str,
         timeout: float,
         privileged: bool,
+        app_args: str,
     ) -> InteractiveShellType:
         """
         See "create_interactive_shell" in SutNode
@@ -96,7 +96,7 @@ def create_interactive_shell(
             self.interactive_session.session,
             self._logger,
             self._get_privileged_command if privileged else None,
-            eal_parameters,
+            app_args,
             timeout,
         )
 
@@ -113,7 +113,7 @@ def _get_privileged_command(command: str) -> str:
         """
 
     @abstractmethod
-    def guess_dpdk_remote_dir(self, remote_dir) -> PurePath:
+    def guess_dpdk_remote_dir(self, remote_dir: str | PurePath) -> PurePath:
         """
         Try to find DPDK remote dir in remote_dir.
         """
@@ -227,7 +227,7 @@ def kill_cleanup_dpdk_apps(self, dpdk_prefix_list: Iterable[str]) -> None:
         """
 
     @abstractmethod
-    def get_dpdk_file_prefix(self, dpdk_prefix) -> str:
+    def get_dpdk_file_prefix(self, dpdk_prefix: str) -> str:
         """
         Get the DPDK file prefix that will be used when running DPDK apps.
         """
diff --git a/dts/framework/testbed_model/hw/port.py b/dts/framework/testbed_model/port.py
similarity index 100%
rename from dts/framework/testbed_model/hw/port.py
rename to dts/framework/testbed_model/port.py
diff --git a/dts/framework/remote_session/posix_session.py b/dts/framework/testbed_model/posix_session.py
similarity index 98%
rename from dts/framework/remote_session/posix_session.py
rename to dts/framework/testbed_model/posix_session.py
index a29e2e8280..5657cc0bc9 100644
--- a/dts/framework/remote_session/posix_session.py
+++ b/dts/framework/testbed_model/posix_session.py
@@ -32,7 +32,7 @@ def combine_short_options(**opts: bool) -> str:
 
         return ret_opts
 
-    def guess_dpdk_remote_dir(self, remote_dir) -> PurePosixPath:
+    def guess_dpdk_remote_dir(self, remote_dir: str | PurePath) -> PurePosixPath:
         remote_guess = self.join_remote_path(remote_dir, "dpdk-*")
         result = self.send_command(f"ls -d {remote_guess} | tail -1")
         return PurePosixPath(result.stdout)
@@ -207,7 +207,7 @@ def _remove_dpdk_runtime_dirs(self, dpdk_runtime_dirs: Iterable[str | PurePath])
         for dpdk_runtime_dir in dpdk_runtime_dirs:
             self.remove_remote_dir(dpdk_runtime_dir)
 
-    def get_dpdk_file_prefix(self, dpdk_prefix) -> str:
+    def get_dpdk_file_prefix(self, dpdk_prefix: str) -> str:
         return ""
 
     def get_compiler_version(self, compiler_name: str) -> str:
diff --git a/dts/framework/testbed_model/sut_node.py b/dts/framework/testbed_model/sut_node.py
index 7f75043bd3..5ce9446dba 100644
--- a/dts/framework/testbed_model/sut_node.py
+++ b/dts/framework/testbed_model/sut_node.py
@@ -15,12 +15,14 @@
     NodeInfo,
     SutNodeConfiguration,
 )
-from framework.remote_session import CommandResult, InteractiveShellType, OSSession
+from framework.remote_session import CommandResult
 from framework.settings import SETTINGS
 from framework.utils import MesonArgs
 
-from .hw import LogicalCoreCount, LogicalCoreList, VirtualDevice
+from .cpu import LogicalCoreCount, LogicalCoreList
 from .node import Node
+from .os_session import InteractiveShellType, OSSession
+from .virtual_device import VirtualDevice
 
 
 class EalParameters(object):
@@ -293,7 +295,7 @@ def create_eal_parameters(
         prefix: str = "dpdk",
         append_prefix_timestamp: bool = True,
         no_pci: bool = False,
-        vdevs: list[VirtualDevice] = None,
+        vdevs: list[VirtualDevice] | None = None,
         other_eal_param: str = "",
     ) -> "EalParameters":
         """
diff --git a/dts/framework/testbed_model/tg_node.py b/dts/framework/testbed_model/tg_node.py
index 79a55663b5..8a8f0019f3 100644
--- a/dts/framework/testbed_model/tg_node.py
+++ b/dts/framework/testbed_model/tg_node.py
@@ -16,16 +16,11 @@
 
 from scapy.packet import Packet  # type: ignore[import]
 
-from framework.config import (
-    ScapyTrafficGeneratorConfig,
-    TGNodeConfiguration,
-    TrafficGeneratorType,
-)
-from framework.exception import ConfigurationError
-
-from .capturing_traffic_generator import CapturingTrafficGenerator
-from .hw.port import Port
+from framework.config import TGNodeConfiguration
+
 from .node import Node
+from .port import Port
+from .traffic_generator import CapturingTrafficGenerator, create_traffic_generator
 
 
 class TGNode(Node):
@@ -78,19 +73,3 @@ def close(self) -> None:
         """Free all resources used by the node"""
         self.traffic_generator.close()
         super(TGNode, self).close()
-
-
-def create_traffic_generator(
-    tg_node: TGNode, traffic_generator_config: ScapyTrafficGeneratorConfig
-) -> CapturingTrafficGenerator:
-    """A factory function for creating traffic generator object from user config."""
-
-    from .scapy import ScapyTrafficGenerator
-
-    match traffic_generator_config.traffic_generator_type:
-        case TrafficGeneratorType.SCAPY:
-            return ScapyTrafficGenerator(tg_node, traffic_generator_config)
-        case _:
-            raise ConfigurationError(
-                f"Unknown traffic generator: {traffic_generator_config.traffic_generator_type}"
-            )
diff --git a/dts/framework/testbed_model/traffic_generator/__init__.py b/dts/framework/testbed_model/traffic_generator/__init__.py
new file mode 100644
index 0000000000..52888d03fa
--- /dev/null
+++ b/dts/framework/testbed_model/traffic_generator/__init__.py
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2023 PANTHEON.tech s.r.o.
+
+from framework.config import ScapyTrafficGeneratorConfig, TrafficGeneratorType
+from framework.exception import ConfigurationError
+from framework.testbed_model.node import Node
+
+from .capturing_traffic_generator import CapturingTrafficGenerator
+from .scapy import ScapyTrafficGenerator
+
+
+def create_traffic_generator(
+    tg_node: Node, traffic_generator_config: ScapyTrafficGeneratorConfig
+) -> CapturingTrafficGenerator:
+    """A factory function for creating traffic generator object from user config."""
+
+    match traffic_generator_config.traffic_generator_type:
+        case TrafficGeneratorType.SCAPY:
+            return ScapyTrafficGenerator(tg_node, traffic_generator_config)
+        case _:
+            raise ConfigurationError(
+                "Unknown traffic generator: {traffic_generator_config.traffic_generator_type}"
+            )
diff --git a/dts/framework/testbed_model/capturing_traffic_generator.py b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py
similarity index 98%
rename from dts/framework/testbed_model/capturing_traffic_generator.py
rename to dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py
index e6512061d7..1fc7f98c05 100644
--- a/dts/framework/testbed_model/capturing_traffic_generator.py
+++ b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py
@@ -16,9 +16,9 @@
 from scapy.packet import Packet  # type: ignore[import]
 
 from framework.settings import SETTINGS
+from framework.testbed_model.port import Port
 from framework.utils import get_packet_summaries
 
-from .hw.port import Port
 from .traffic_generator import TrafficGenerator
 
 
@@ -127,7 +127,7 @@ def _send_packets_and_capture(
         for the specified duration. It must be able to handle no received packets.
         """
 
-    def _write_capture_from_packets(self, capture_name: str, packets: list[Packet]):
+    def _write_capture_from_packets(self, capture_name: str, packets: list[Packet]) -> None:
         file_name = f"{SETTINGS.output_dir}/{capture_name}.pcap"
         self._logger.debug(f"Writing packets to {file_name}.")
         scapy.utils.wrpcap(file_name, packets)
diff --git a/dts/framework/testbed_model/scapy.py b/dts/framework/testbed_model/traffic_generator/scapy.py
similarity index 95%
rename from dts/framework/testbed_model/scapy.py
rename to dts/framework/testbed_model/traffic_generator/scapy.py
index 9083e92b3d..c88cf28369 100644
--- a/dts/framework/testbed_model/scapy.py
+++ b/dts/framework/testbed_model/traffic_generator/scapy.py
@@ -24,16 +24,15 @@
 from scapy.packet import Packet  # type: ignore[import]
 
 from framework.config import OS, ScapyTrafficGeneratorConfig
-from framework.logger import DTSLOG, getLogger
 from framework.remote_session import PythonShell
 from framework.settings import SETTINGS
+from framework.testbed_model.node import Node
+from framework.testbed_model.port import Port
 
 from .capturing_traffic_generator import (
     CapturingTrafficGenerator,
     _get_default_capture_name,
 )
-from .hw.port import Port
-from .tg_node import TGNode
 
 """
 ========= BEGIN RPC FUNCTIONS =========
@@ -144,7 +143,7 @@ def quit(self) -> None:
         self._BaseServer__shutdown_request = True
         return None
 
-    def add_rpc_function(self, name: str, function_bytes: xmlrpc.client.Binary):
+    def add_rpc_function(self, name: str, function_bytes: xmlrpc.client.Binary) -> None:
         """Add a function to the server.
 
         This is meant to be executed remotely.
@@ -189,13 +188,9 @@ class ScapyTrafficGenerator(CapturingTrafficGenerator):
     session: PythonShell
     rpc_server_proxy: xmlrpc.client.ServerProxy
     _config: ScapyTrafficGeneratorConfig
-    _tg_node: TGNode
-    _logger: DTSLOG
 
-    def __init__(self, tg_node: TGNode, config: ScapyTrafficGeneratorConfig):
-        self._config = config
-        self._tg_node = tg_node
-        self._logger = getLogger(f"{self._tg_node.name} {self._config.traffic_generator_type}")
+    def __init__(self, tg_node: Node, config: ScapyTrafficGeneratorConfig):
+        super().__init__(tg_node, config)
 
         assert (
             self._tg_node.config.os == OS.linux
@@ -229,7 +224,7 @@ def __init__(self, tg_node: TGNode, config: ScapyTrafficGeneratorConfig):
             function_bytes = marshal.dumps(function.__code__)
             self.rpc_server_proxy.add_rpc_function(function.__name__, function_bytes)
 
-    def _start_xmlrpc_server_in_remote_python(self, listen_port: int):
+    def _start_xmlrpc_server_in_remote_python(self, listen_port: int) -> None:
         # load the source of the function
         src = inspect.getsource(QuittableXMLRPCServer)
         # Lines with only whitespace break the repl if in the middle of a function
@@ -271,7 +266,7 @@ def _send_packets_and_capture(
         scapy_packets = [Ether(packet.data) for packet in xmlrpc_packets]
         return scapy_packets
 
-    def close(self):
+    def close(self) -> None:
         try:
             self.rpc_server_proxy.quit()
         except ConnectionRefusedError:
diff --git a/dts/framework/testbed_model/traffic_generator.py b/dts/framework/testbed_model/traffic_generator/traffic_generator.py
similarity index 81%
rename from dts/framework/testbed_model/traffic_generator.py
rename to dts/framework/testbed_model/traffic_generator/traffic_generator.py
index 28c35d3ce4..0d9902ddb7 100644
--- a/dts/framework/testbed_model/traffic_generator.py
+++ b/dts/framework/testbed_model/traffic_generator/traffic_generator.py
@@ -12,11 +12,12 @@
 
 from scapy.packet import Packet  # type: ignore[import]
 
-from framework.logger import DTSLOG
+from framework.config import TrafficGeneratorConfig
+from framework.logger import DTSLOG, getLogger
+from framework.testbed_model.node import Node
+from framework.testbed_model.port import Port
 from framework.utils import get_packet_summaries
 
-from .hw.port import Port
-
 
 class TrafficGenerator(ABC):
     """The base traffic generator.
@@ -24,8 +25,15 @@ class TrafficGenerator(ABC):
     Defines the few basic methods that each traffic generator must implement.
     """
 
+    _config: TrafficGeneratorConfig
+    _tg_node: Node
     _logger: DTSLOG
 
+    def __init__(self, tg_node: Node, config: TrafficGeneratorConfig):
+        self._config = config
+        self._tg_node = tg_node
+        self._logger = getLogger(f"{self._tg_node.name} {self._config.traffic_generator_type}")
+
     def send_packet(self, packet: Packet, port: Port) -> None:
         """Send a packet and block until it is fully sent.
 
diff --git a/dts/framework/testbed_model/hw/virtual_device.py b/dts/framework/testbed_model/virtual_device.py
similarity index 100%
rename from dts/framework/testbed_model/hw/virtual_device.py
rename to dts/framework/testbed_model/virtual_device.py
diff --git a/dts/framework/utils.py b/dts/framework/utils.py
index d098d364ff..a0f2173949 100644
--- a/dts/framework/utils.py
+++ b/dts/framework/utils.py
@@ -7,7 +7,6 @@
 import json
 import os
 import subprocess
-import sys
 from enum import Enum
 from pathlib import Path
 from subprocess import SubprocessError
@@ -16,31 +15,7 @@
 
 from .exception import ConfigurationError
 
-
-class StrEnum(Enum):
-    @staticmethod
-    def _generate_next_value_(name: str, start: int, count: int, last_values: object) -> str:
-        return name
-
-    def __str__(self) -> str:
-        return self.name
-
-
-REGEX_FOR_PCI_ADDRESS = "/[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}.[0-9]{1}/"
-
-
-def check_dts_python_version() -> None:
-    if sys.version_info.major < 3 or (sys.version_info.major == 3 and sys.version_info.minor < 10):
-        print(
-            RED(
-                (
-                    "WARNING: DTS execution node's python version is lower than"
-                    "python 3.10, is deprecated and will not work in future releases."
-                )
-            ),
-            file=sys.stderr,
-        )
-        print(RED("Please use Python >= 3.10 instead"), file=sys.stderr)
+REGEX_FOR_PCI_ADDRESS: str = "/[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}.[0-9]{1}/"
 
 
 def expand_range(range_str: str) -> list[int]:
@@ -61,7 +36,7 @@ def expand_range(range_str: str) -> list[int]:
     return expanded_range
 
 
-def get_packet_summaries(packets: list[Packet]):
+def get_packet_summaries(packets: list[Packet]) -> str:
     if len(packets) == 1:
         packet_summaries = packets[0].summary()
     else:
@@ -69,8 +44,13 @@ def get_packet_summaries(packets: list[Packet]):
     return f"Packet contents: \n{packet_summaries}"
 
 
-def RED(text: str) -> str:
-    return f"\u001B[31;1m{str(text)}\u001B[0m"
+class StrEnum(Enum):
+    @staticmethod
+    def _generate_next_value_(name: str, start: int, count: int, last_values: object) -> str:
+        return name
+
+    def __str__(self) -> str:
+        return self.name
 
 
 class MesonArgs(object):
@@ -215,5 +195,5 @@ def _delete_tarball(self) -> None:
         if self._tarball_path and os.path.exists(self._tarball_path):
             os.remove(self._tarball_path)
 
-    def __fspath__(self):
+    def __fspath__(self) -> str:
         return str(self._tarball_path)
diff --git a/dts/main.py b/dts/main.py
index 43311fa847..5d4714b0c3 100755
--- a/dts/main.py
+++ b/dts/main.py
@@ -10,10 +10,17 @@
 
 import logging
 
-from framework import dts
+from framework import settings
 
 
 def main() -> None:
+    """Set DTS settings, then run DTS.
+
+    The DTS settings are taken from the command line arguments and the environment variables.
+    """
+    settings.SETTINGS = settings.get_settings()
+    from framework import dts
+
     dts.run_all()
 
 
-- 
2.34.1


  reply	other threads:[~2023-11-23 15:13 UTC|newest]

Thread overview: 257+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-23 10:40 [RFC PATCH v1 0/4] dts: add dts api docs Juraj Linkeš
2023-03-23 10:40 ` [RFC PATCH v1 1/4] dts: code adjustments for sphinx Juraj Linkeš
2023-03-23 10:40 ` [RFC PATCH v1 2/4] dts: add doc generation dependencies Juraj Linkeš
2023-03-23 10:40 ` [RFC PATCH v1 3/4] dts: add doc generation Juraj Linkeš
2023-03-23 10:40 ` [RFC PATCH v1 4/4] dts: format docstrigs to google format Juraj Linkeš
2023-04-28 19:33   ` Jeremy Spewock
2023-04-03  9:17 ` [RFC PATCH v1 0/4] dts: add dts api docs Juraj Linkeš
2023-04-03  9:42   ` Bruce Richardson
2023-04-25  8:20     ` Juraj Linkeš
2023-04-25  8:44       ` Bruce Richardson
2023-04-25  8:57         ` Juraj Linkeš
2023-04-25  9:43           ` Bruce Richardson
2023-05-03 11:33             ` Juraj Linkeš
2023-05-04 12:37 ` [RFC PATCH v2 " Juraj Linkeš
2023-05-04 12:37   ` [RFC PATCH v2 1/4] dts: code adjustments for sphinx Juraj Linkeš
2023-05-04 12:37   ` [RFC PATCH v2 2/4] dts: add doc generation dependencies Juraj Linkeš
2023-05-04 12:37   ` [RFC PATCH v2 3/4] dts: add doc generation Juraj Linkeš
2023-05-04 12:45     ` Bruce Richardson
2023-05-05  7:53       ` Juraj Linkeš
2023-05-05 10:24         ` Bruce Richardson
2023-05-05 10:41           ` Juraj Linkeš
2023-05-05 10:56     ` Bruce Richardson
2023-05-05 11:13       ` Juraj Linkeš
2023-05-05 13:28         ` Bruce Richardson
2023-05-09  9:23           ` Juraj Linkeš
2023-05-09  9:40             ` Bruce Richardson
2023-05-10 12:19               ` Juraj Linkeš
2023-05-04 12:37   ` [RFC PATCH v2 4/4] dts: format docstrigs to google format Juraj Linkeš
2023-05-05 14:06   ` [RFC PATCH v2 0/4] dts: add dts api docs Bruce Richardson
2023-05-09 15:28     ` Juraj Linkeš
2023-05-11  8:55     ` Juraj Linkeš
2023-05-11  9:14   ` [RFC PATCH v3 " Juraj Linkeš
2023-05-11  9:14     ` [RFC PATCH v3 1/4] dts: code adjustments for sphinx Juraj Linkeš
2023-05-11  9:14     ` [RFC PATCH v3 2/4] dts: add doc generation dependencies Juraj Linkeš
2023-05-11  9:14     ` [RFC PATCH v3 3/4] dts: add doc generation Juraj Linkeš
2023-05-11  9:14     ` [RFC PATCH v3 4/4] dts: format docstrigs to google format Juraj Linkeš
2023-06-21 18:27       ` Jeremy Spewock
2023-05-17 16:56     ` [RFC PATCH v3 0/4] dts: add dts api docs Bruce Richardson
2023-05-22  9:17       ` Juraj Linkeš
2023-08-31 10:04     ` [RFC PATCH v4 " Juraj Linkeš
2023-08-31 10:04       ` [RFC PATCH v4 1/4] dts: code adjustments for sphinx Juraj Linkeš
2023-10-22 14:30         ` Yoan Picchi
2023-10-23  6:44           ` Juraj Linkeš
2023-10-23 11:52             ` Yoan Picchi
2023-10-24  6:39               ` Juraj Linkeš
2023-10-24 12:21                 ` Yoan Picchi
2023-08-31 10:04       ` [RFC PATCH v4 2/4] dts: add doc generation dependencies Juraj Linkeš
2023-10-27 15:27         ` Yoan Picchi
2023-08-31 10:04       ` [RFC PATCH v4 3/4] dts: add doc generation Juraj Linkeš
2023-09-20  7:08         ` Juraj Linkeš
2023-10-26 16:43         ` Yoan Picchi
2023-10-27  9:52           ` Juraj Linkeš
2023-08-31 10:04       ` [RFC PATCH v4 4/4] dts: format docstrigs to google format Juraj Linkeš
2023-09-01 17:02         ` Jeremy Spewock
2023-10-31 12:10         ` Yoan Picchi
2023-11-02 10:17           ` Juraj Linkeš
2023-11-06 17:15       ` [PATCH v5 00/23] dts: add dts api docs Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 01/23] dts: code adjustments for doc generation Juraj Linkeš
2023-11-08 13:35           ` Yoan Picchi
2023-11-15  7:46             ` Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 02/23] dts: add docstring checker Juraj Linkeš
2023-11-07 17:38           ` Yoan Picchi
2023-11-06 17:15         ` [PATCH v5 03/23] dts: add basic developer docs Juraj Linkeš
2023-11-07 14:39           ` Yoan Picchi
2023-11-08  9:01             ` Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 04/23] dts: exceptions docstring update Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 05/23] dts: settings " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 06/23] dts: logger and " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 07/23] dts: dts runner and main " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 08/23] dts: test suite " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 09/23] dts: test result " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 10/23] dts: config " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 11/23] dts: remote session " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 12/23] dts: interactive " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 13/23] dts: port and virtual device " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 14/23] dts: cpu " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 15/23] dts: os session " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 16/23] dts: posix and linux sessions " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 17/23] dts: node " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 18/23] dts: sut and tg nodes " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 19/23] dts: base traffic generators " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 20/23] dts: scapy tg " Juraj Linkeš
2023-11-06 17:15         ` [PATCH v5 21/23] dts: test suites " Juraj Linkeš
2023-11-06 17:16         ` [PATCH v5 22/23] dts: add doc generation dependencies Juraj Linkeš
2023-11-06 17:16         ` [PATCH v5 23/23] dts: add doc generation Juraj Linkeš
2023-11-08 12:53         ` [PATCH v6 01/23] dts: code adjustments for " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 02/23] dts: add docstring checker Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 03/23] dts: add basic developer docs Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 04/23] dts: exceptions docstring update Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 05/23] dts: settings " Juraj Linkeš
2023-11-08 16:17             ` Yoan Picchi
2023-11-15 10:09               ` Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 06/23] dts: logger and " Juraj Linkeš
2023-11-08 17:14             ` Yoan Picchi
2023-11-15 10:11               ` Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 07/23] dts: dts runner and main " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 08/23] dts: test suite " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 09/23] dts: test result " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 10/23] dts: config " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 11/23] dts: remote session " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 12/23] dts: interactive " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 13/23] dts: port and virtual device " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 14/23] dts: cpu " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 15/23] dts: os session " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 16/23] dts: posix and linux sessions " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 17/23] dts: node " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 18/23] dts: sut and tg nodes " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 19/23] dts: base traffic generators " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 20/23] dts: scapy tg " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 21/23] dts: test suites " Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 22/23] dts: add doc generation dependencies Juraj Linkeš
2023-11-08 16:00             ` Yoan Picchi
2023-11-15 10:00               ` Juraj Linkeš
2023-11-08 12:53           ` [PATCH v6 23/23] dts: add doc generation Juraj Linkeš
2023-11-15 13:09             ` [PATCH v7 00/21] dts: docstrings update Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 01/21] dts: code adjustments for doc generation Juraj Linkeš
2023-11-16 21:04                 ` Jeremy Spewock
2023-11-20 16:10                   ` Juraj Linkeš
2023-11-20 16:02                 ` Yoan Picchi
2023-11-15 13:09               ` [PATCH v7 02/21] dts: add docstring checker Juraj Linkeš
2023-11-20 16:03                 ` Yoan Picchi
2023-11-15 13:09               ` [PATCH v7 03/21] dts: add basic developer docs Juraj Linkeš
2023-11-20 16:03                 ` Yoan Picchi
2023-11-15 13:09               ` [PATCH v7 04/21] dts: exceptions docstring update Juraj Linkeš
2023-11-20 16:22                 ` Yoan Picchi
2023-11-20 16:35                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 05/21] dts: settings " Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 06/21] dts: logger and utils " Juraj Linkeš
2023-11-20 16:23                 ` Yoan Picchi
2023-11-20 16:36                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 07/21] dts: dts runner and main " Juraj Linkeš
2023-11-16 21:51                 ` Jeremy Spewock
2023-11-20 16:13                   ` Juraj Linkeš
2023-11-20 17:43                 ` Yoan Picchi
2023-11-21  9:10                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 08/21] dts: test suite " Juraj Linkeš
2023-11-16 22:16                 ` Jeremy Spewock
2023-11-20 16:25                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 09/21] dts: test result " Juraj Linkeš
2023-11-16 22:47                 ` Jeremy Spewock
2023-11-20 16:33                   ` Juraj Linkeš
2023-11-30 21:20                     ` Jeremy Spewock
2023-11-15 13:09               ` [PATCH v7 10/21] dts: config " Juraj Linkeš
2023-11-21 15:08                 ` Yoan Picchi
2023-11-22 10:42                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 11/21] dts: remote session " Juraj Linkeš
2023-11-21 15:36                 ` Yoan Picchi
2023-11-22 11:13                   ` Juraj Linkeš
2023-11-22 11:25                     ` Yoan Picchi
2023-11-15 13:09               ` [PATCH v7 12/21] dts: interactive " Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 13/21] dts: port and virtual device " Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 14/21] dts: cpu " Juraj Linkeš
2023-11-21 17:45                 ` Yoan Picchi
2023-11-22 11:18                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 15/21] dts: os session " Juraj Linkeš
2023-11-22 11:50                 ` Yoan Picchi
2023-11-22 13:27                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 16/21] dts: posix and linux sessions " Juraj Linkeš
2023-11-22 13:24                 ` Yoan Picchi
2023-11-22 13:35                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 17/21] dts: node " Juraj Linkeš
2023-11-22 12:18                 ` Yoan Picchi
2023-11-22 13:28                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 18/21] dts: sut and tg nodes " Juraj Linkeš
2023-11-22 13:12                 ` Yoan Picchi
2023-11-22 13:34                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 19/21] dts: base traffic generators " Juraj Linkeš
2023-11-21 16:20                 ` Yoan Picchi
2023-11-22 11:38                   ` Juraj Linkeš
2023-11-22 11:56                     ` Yoan Picchi
2023-11-22 13:11                       ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 20/21] dts: scapy tg " Juraj Linkeš
2023-11-21 16:33                 ` Yoan Picchi
2023-11-22 13:18                   ` Juraj Linkeš
2023-11-15 13:09               ` [PATCH v7 21/21] dts: test suites " Juraj Linkeš
2023-11-16 17:36                 ` Yoan Picchi
2023-11-20 10:17                   ` Juraj Linkeš
2023-11-20 12:50                     ` Yoan Picchi
2023-11-22 13:40                       ` Juraj Linkeš
2023-11-23 15:13               ` [PATCH v8 00/21] dts: docstrings update Juraj Linkeš
2023-11-23 15:13                 ` Juraj Linkeš [this message]
2023-11-23 15:13                 ` [PATCH v8 02/21] dts: add docstring checker Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 03/21] dts: add basic developer docs Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 04/21] dts: exceptions docstring update Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 05/21] dts: settings " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 06/21] dts: logger and utils " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 07/21] dts: dts runner and main " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 08/21] dts: test suite " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 09/21] dts: test result " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 10/21] dts: config " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 11/21] dts: remote session " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 12/21] dts: interactive " Juraj Linkeš
2023-11-30 21:49                   ` Jeremy Spewock
2023-12-04  9:50                     ` Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 13/21] dts: port and virtual device " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 14/21] dts: cpu " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 15/21] dts: os session " Juraj Linkeš
2023-12-01 17:33                   ` Jeremy Spewock
2023-12-04  9:53                     ` Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 16/21] dts: posix and linux sessions " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 17/21] dts: node " Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 18/21] dts: sut and tg nodes " Juraj Linkeš
2023-12-01 18:06                   ` Jeremy Spewock
2023-12-04 10:02                     ` Juraj Linkeš
2023-12-04 11:02                       ` Bruce Richardson
2023-11-23 15:13                 ` [PATCH v8 19/21] dts: base traffic generators " Juraj Linkeš
2023-12-01 18:05                   ` Jeremy Spewock
2023-12-04 10:03                     ` Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 20/21] dts: scapy tg " Juraj Linkeš
2023-12-01 18:17                   ` Jeremy Spewock
2023-12-04 10:07                     ` Juraj Linkeš
2023-11-23 15:13                 ` [PATCH v8 21/21] dts: test suites " Juraj Linkeš
2023-12-01 16:00                 ` [PATCH v8 00/21] dts: docstrings update Yoan Picchi
2023-12-01 18:23                   ` Jeremy Spewock
2023-12-04 10:24                 ` [PATCH v9 " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 01/21] dts: code adjustments for doc generation Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 02/21] dts: add docstring checker Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 03/21] dts: add basic developer docs Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 04/21] dts: exceptions docstring update Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 05/21] dts: settings " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 06/21] dts: logger and utils " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 07/21] dts: dts runner and main " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 08/21] dts: test suite " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 09/21] dts: test result " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 10/21] dts: config " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 11/21] dts: remote session " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 12/21] dts: interactive " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 13/21] dts: port and virtual device " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 14/21] dts: cpu " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 15/21] dts: os session " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 16/21] dts: posix and linux sessions " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 17/21] dts: node " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 18/21] dts: sut and tg nodes " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 19/21] dts: base traffic generators " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 20/21] dts: scapy tg " Juraj Linkeš
2023-12-04 10:24                   ` [PATCH v9 21/21] dts: test suites " Juraj Linkeš
2023-12-05 18:39                     ` Jeremy Spewock
2023-12-21 11:48                   ` [PATCH v9 00/21] dts: docstrings update Thomas Monjalon
2023-11-15 13:36             ` [PATCH v1 0/2] dts: api docs generation Juraj Linkeš
2023-11-15 13:36               ` [PATCH v1 1/2] dts: add doc generation dependencies Juraj Linkeš
2023-11-15 13:36               ` [PATCH v1 2/2] dts: add doc generation Juraj Linkeš
2024-01-22 12:00               ` [PATCH v2 0/3] dts: API docs generation Juraj Linkeš
2024-01-22 12:00                 ` [PATCH v2 1/3] dts: add doc generation dependencies Juraj Linkeš
2024-01-22 12:00                 ` [PATCH v2 2/3] dts: add API doc sources Juraj Linkeš
2024-01-22 12:00                 ` [PATCH v2 3/3] dts: add API doc generation Juraj Linkeš
2024-01-22 16:35               ` [PATCH v3 0/3] dts: API docs generation Juraj Linkeš
2024-01-22 16:35                 ` [PATCH v3 1/3] dts: add doc generation dependencies Juraj Linkeš
2024-01-22 16:35                 ` [PATCH v3 2/3] dts: add API doc sources Juraj Linkeš
2024-01-22 16:35                 ` [PATCH v3 3/3] dts: add API doc generation Juraj Linkeš
2024-01-29 17:09                   ` Jeremy Spewock
     [not found]                   ` <CAJvnSUCNjo0p-yhROF1MNLKhjiAw2QTyTHO2hpOaVVUn0xnJ0A@mail.gmail.com>
2024-02-29 18:12                     ` Nicholas Pratte
2024-04-12 10:14               ` [PATCH v4 0/3] dts: API docs generation Juraj Linkeš
2024-04-12 10:14                 ` [PATCH v4 1/3] dts: add doc generation dependencies Juraj Linkeš
2024-04-12 10:14                 ` [PATCH v4 2/3] dts: add API doc sources Juraj Linkeš
2024-04-12 10:14                 ` [PATCH v4 3/3] dts: add API doc generation Juraj Linkeš
2024-04-29 13:49                 ` [PATCH v4 0/3] dts: API docs generation Jeremy Spewock
2024-04-29 14:12                   ` Patrick Robb

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231123151344.162812-2-juraj.linkes@pantheon.tech \
    --to=juraj.linkes@pantheon.tech \
    --cc=Honnappa.Nagarahalli@arm.com \
    --cc=Luca.Vizzarro@arm.com \
    --cc=dev@dpdk.org \
    --cc=jspewock@iol.unh.edu \
    --cc=paul.szczepanek@arm.com \
    --cc=probb@iol.unh.edu \
    --cc=thomas@monjalon.net \
    --cc=yoan.picchi@foss.arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).