DPDK patches and discussions
 help / color / mirror / Atom feed
From: Nicholas Pratte <npratte@iol.unh.edu>
To: Luca Vizzarro <luca.vizzarro@arm.com>
Cc: dev@dpdk.org, Paul Szczepanek <paul.szczepanek@arm.com>,
	Dean Marx <dmarx@iol.unh.edu>, Patrick Robb <probb@iol.unh.edu>
Subject: Re: [PATCH v4 5/7] dts: handle CLI overrides in the configuration
Date: Fri, 24 Jan 2025 13:15:39 -0500	[thread overview]
Message-ID: <CAKXZ7ehyV2HEz_n7rUOkwkQ8ce1aUj1ra=HYhy59ZmJ0v42MDQ@mail.gmail.com> (raw)
In-Reply-To: <20250124113909.137128-6-luca.vizzarro@arm.com>

Thank you for addressing this. Great work!

Reviewed-by: Nicholas Pratte <npratte@iol.unh.edu>

On Fri, Jan 24, 2025 at 6:39 AM Luca Vizzarro <luca.vizzarro@arm.com> wrote:
>
> The current handling of the configuration loading is inconsistent. After
> the whole configuration is loaded, if there are any CLI or environment
> overrides set, the code forcefully modifies the frozen configuration to
> use them.
>
> This changes the handling by passing the environment/CLI settings as
> part of the configuration context and handle the overrides directly at
> the field level before these are validated. As a positive side effect,
> the validator won't complain if a field is missing from the file but it
> has been specified as an environment/CLI override.
>
> Bugzilla ID: 1360
> Bugzilla ID: 1598
>
> Signed-off-by: Nicholas Pratte <npratte@iol.unh.edu>
> Signed-off-by: Luca Vizzarro <luca.vizzarro@arm.com>
> Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
> Reviewed-by: Dean Marx <dmarx@iol.unh.edu>
> ---
>  dts/framework/config/__init__.py | 65 ++++++++++++++++++++++++++++++--
>  dts/framework/runner.py          | 18 ++-------
>  2 files changed, 64 insertions(+), 19 deletions(-)
>
> diff --git a/dts/framework/config/__init__.py b/dts/framework/config/__init__.py
> index 2496f48e20..6ae98d0387 100644
> --- a/dts/framework/config/__init__.py
> +++ b/dts/framework/config/__init__.py
> @@ -33,10 +33,11 @@
>  """
>
>  import tarfile
> +from collections.abc import Callable, MutableMapping
>  from enum import Enum, auto, unique
>  from functools import cached_property
>  from pathlib import Path, PurePath
> -from typing import TYPE_CHECKING, Annotated, Any, Literal, NamedTuple
> +from typing import TYPE_CHECKING, Annotated, Any, Literal, NamedTuple, TypedDict, cast
>
>  import yaml
>  from pydantic import (
> @@ -44,18 +45,60 @@
>      ConfigDict,
>      Field,
>      ValidationError,
> +    ValidationInfo,
>      field_validator,
>      model_validator,
>  )
>  from typing_extensions import Self
>
>  from framework.exception import ConfigurationError
> +from framework.settings import Settings
>  from framework.utils import REGEX_FOR_PCI_ADDRESS, StrEnum
>
>  if TYPE_CHECKING:
>      from framework.test_suite import TestSuiteSpec
>
>
> +class ValidationContext(TypedDict):
> +    """A context dictionary to use for validation."""
> +
> +    #: The command line settings.
> +    settings: Settings
> +
> +
> +def load_fields_from_settings(
> +    *fields: str | tuple[str, str],
> +) -> Callable[[Any, ValidationInfo], Any]:
> +    """Before model validator that injects values from :attr:`ValidationContext.settings`.
> +
> +    Args:
> +        *fields: The name of the fields to apply the argument value to. If the settings field name
> +            is not the same as the configuration field, supply a tuple with the respective names.
> +
> +    Returns:
> +        Pydantic before model validator.
> +    """
> +
> +    def _loader(data: Any, info: ValidationInfo) -> Any:
> +        if not isinstance(data, MutableMapping):
> +            return data
> +
> +        settings = cast(ValidationContext, info.context)["settings"]
> +        for field in fields:
> +            if isinstance(field, tuple):
> +                settings_field = field[0]
> +                config_field = field[1]
> +            else:
> +                settings_field = config_field = field
> +
> +            if settings_data := getattr(settings, settings_field):
> +                data[config_field] = settings_data
> +
> +        return data
> +
> +    return _loader
> +
> +
>  class FrozenModel(BaseModel):
>      """A pre-configured :class:`~pydantic.BaseModel`."""
>
> @@ -317,6 +360,10 @@ class BaseDPDKBuildConfiguration(FrozenModel):
>      #: The location of the DPDK tree.
>      dpdk_location: DPDKLocation
>
> +    dpdk_location_from_settings = model_validator(mode="before")(
> +        load_fields_from_settings("dpdk_location")
> +    )
> +
>
>  class DPDKPrecompiledBuildConfiguration(BaseDPDKBuildConfiguration):
>      """DPDK precompiled build configuration."""
> @@ -325,6 +372,10 @@ class DPDKPrecompiledBuildConfiguration(BaseDPDKBuildConfiguration):
>      #: subdirectory of `~dpdk_location.dpdk_tree` or `~dpdk_location.tarball` root directory.
>      precompiled_build_dir: str = Field(min_length=1)
>
> +    build_dir_from_settings = model_validator(mode="before")(
> +        load_fields_from_settings("precompiled_build_dir")
> +    )
> +
>
>  class DPDKBuildOptionsConfiguration(FrozenModel):
>      """DPDK build options configuration.
> @@ -439,6 +490,10 @@ class TestRunConfiguration(FrozenModel):
>      #: The seed to use for pseudo-random generation.
>      random_seed: int | None = None
>
> +    fields_from_settings = model_validator(mode="before")(
> +        load_fields_from_settings("test_suites", "random_seed")
> +    )
> +
>
>  class TestRunWithNodesConfiguration(NamedTuple):
>      """Tuple containing the configuration of the test run and its associated nodes."""
> @@ -541,7 +596,7 @@ def validate_test_runs_with_nodes(self) -> Self:
>          return self
>
>
> -def load_config(config_file_path: Path) -> Configuration:
> +def load_config(settings: Settings) -> Configuration:
>      """Load DTS test run configuration from a file.
>
>      Load the YAML test run configuration file, validate it, and create a test run configuration
> @@ -552,6 +607,7 @@ def load_config(config_file_path: Path) -> Configuration:
>
>      Args:
>          config_file_path: The path to the YAML test run configuration file.
> +        settings: The settings provided by the user on the command line.
>
>      Returns:
>          The parsed test run configuration.
> @@ -559,10 +615,11 @@ def load_config(config_file_path: Path) -> Configuration:
>      Raises:
>          ConfigurationError: If the supplied configuration file is invalid.
>      """
> -    with open(config_file_path, "r") as f:
> +    with open(settings.config_file_path, "r") as f:
>          config_data = yaml.safe_load(f)
>
>      try:
> -        return Configuration.model_validate(config_data)
> +        context = ValidationContext(settings=settings)
> +        return Configuration.model_validate(config_data, context=context)
>      except ValidationError as e:
>          raise ConfigurationError("failed to load the supplied configuration") from e
> diff --git a/dts/framework/runner.py b/dts/framework/runner.py
> index 0cdbb07e06..e46a8c1a4f 100644
> --- a/dts/framework/runner.py
> +++ b/dts/framework/runner.py
> @@ -31,7 +31,6 @@
>
>  from .config import (
>      Configuration,
> -    DPDKPrecompiledBuildConfiguration,
>      SutNodeConfiguration,
>      TestRunConfiguration,
>      TestSuiteConfig,
> @@ -82,7 +81,7 @@ class DTSRunner:
>
>      def __init__(self):
>          """Initialize the instance with configuration, logger, result and string constants."""
> -        self._configuration = load_config(SETTINGS.config_file_path)
> +        self._configuration = load_config(SETTINGS)
>          self._logger = get_dts_logger()
>          if not os.path.exists(SETTINGS.output_dir):
>              os.makedirs(SETTINGS.output_dir)
> @@ -142,9 +141,7 @@ def run(self) -> None:
>                  self._init_random_seed(test_run_config)
>                  test_run_result = self._result.add_test_run(test_run_config)
>                  # we don't want to modify the original config, so create a copy
> -                test_run_test_suites = list(
> -                    SETTINGS.test_suites if SETTINGS.test_suites else test_run_config.test_suites
> -                )
> +                test_run_test_suites = test_run_config.test_suites
>                  if not test_run_config.skip_smoke_tests:
>                      test_run_test_suites[:0] = [TestSuiteConfig(test_suite="smoke_tests")]
>                  try:
> @@ -320,15 +317,6 @@ def _run_test_run(
>          test_run_result.sut_info = sut_node.node_info
>          try:
>              dpdk_build_config = test_run_config.dpdk_config
> -            if new_location := SETTINGS.dpdk_location:
> -                dpdk_build_config = dpdk_build_config.model_copy(
> -                    update={"dpdk_location": new_location}
> -                )
> -            if dir := SETTINGS.precompiled_build_dir:
> -                dpdk_build_config = DPDKPrecompiledBuildConfiguration(
> -                    dpdk_location=dpdk_build_config.dpdk_location,
> -                    precompiled_build_dir=dir,
> -                )
>              sut_node.set_up_test_run(test_run_config, dpdk_build_config)
>              test_run_result.dpdk_build_info = sut_node.get_dpdk_build_info()
>              tg_node.set_up_test_run(test_run_config, dpdk_build_config)
> @@ -622,6 +610,6 @@ def _exit_dts(self) -> None:
>
>      def _init_random_seed(self, conf: TestRunConfiguration) -> None:
>          """Initialize the random seed to use for the test run."""
> -        seed = SETTINGS.random_seed or conf.random_seed or random.randrange(0xFFFF_FFFF)
> +        seed = conf.random_seed or random.randrange(0xFFFF_FFFF)
>          self._logger.info(f"Initializing test run with random seed {seed}.")
>          random.seed(seed)
> --
> 2.43.0
>

  reply	other threads:[~2025-01-24 18:15 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-13 20:18 [PATCH 0/4] dts: Remove Excess Attributes From User Config Nicholas Pratte
2024-06-13 20:18 ` [PATCH 1/4] dts: Remove build target config and list of devices Nicholas Pratte
2024-06-14 18:07   ` Jeremy Spewock
2024-06-13 20:18 ` [PATCH 2/4] dts: Use First Core Logic Change Nicholas Pratte
2024-06-14 18:09   ` Jeremy Spewock
2024-06-20 13:41     ` Nicholas Pratte
2024-06-13 20:18 ` [PATCH 3/4] dts: Self-Discovering Architecture Change Nicholas Pratte
2024-06-14 18:09   ` Jeremy Spewock
2024-06-13 20:18 ` [PATCH 4/4] dts: Rework DPDK Attributes In SUT Node Config Nicholas Pratte
2024-06-14 18:11   ` Jeremy Spewock
2024-07-05 17:13 ` [PATCH v2 0/6] dts: Remove Excess Attributes From User Config Nicholas Pratte
2024-07-05 18:29   ` [PATCH v2 1/6] dts: Remove build target config and list of devices Nicholas Pratte
2024-11-06 19:29     ` Dean Marx
2024-07-05 18:31   ` [PATCH v2 2/6] dts: Use First Core Logic Change Nicholas Pratte
2024-11-06 19:48     ` Dean Marx
2024-07-05 18:32   ` [PATCH v2 3/6] dts: Self-Discovering Architecture Change Nicholas Pratte
2024-11-06 20:13     ` Dean Marx
2024-07-05 18:32   ` [PATCH v2 4/6] dts: Rework DPDK Attributes In SUT Node Config Nicholas Pratte
2024-11-06 20:32     ` Dean Marx
2024-07-05 18:33   ` [PATCH v2 5/6] dts: add conditional behavior for test suite Nicholas Pratte
2024-07-05 18:33   ` [PATCH v2 6/6] doc: dpdk documentation changes for new dts config Nicholas Pratte
2025-01-15 14:18   ` [PATCH v3 0/7] dts: refactor configuration Luca Vizzarro
2025-01-15 14:18     ` [PATCH v3 1/7] dts: enable arch self-discovery Luca Vizzarro
2025-01-16 20:52       ` Dean Marx
2025-01-22 17:38       ` Nicholas Pratte
2025-01-15 14:18     ` [PATCH v3 2/7] dts: simplify build options config Luca Vizzarro
2025-01-16 20:53       ` Dean Marx
2025-01-22 17:45       ` Nicholas Pratte
2025-01-15 14:18     ` [PATCH v3 3/7] dts: infer use first core without config Luca Vizzarro
2025-01-16 20:53       ` Dean Marx
2025-01-22 18:02       ` Nicholas Pratte
2025-01-15 14:18     ` [PATCH v3 4/7] dts: rework DPDK attributes in SUT node config Luca Vizzarro
2025-01-16 20:53       ` Dean Marx
2025-01-15 14:18     ` [PATCH v3 5/7] dts: handle CLI overrides in the configuration Luca Vizzarro
2025-01-16 20:53       ` Dean Marx
2025-01-15 14:18     ` [PATCH v3 6/7] dts: split configuration file Luca Vizzarro
2025-01-16 20:54       ` Dean Marx
2025-01-15 14:18     ` [PATCH v3 7/7] dts: run all test suites by default Luca Vizzarro
2025-01-16 21:01       ` Dean Marx
2025-01-20 10:00         ` Luca Vizzarro
2024-07-05 17:13 ` [PATCH v2 1/6] dts: Remove build target config and list of devices Nicholas Pratte
2024-07-16 15:07   ` Jeremy Spewock
2024-09-12 20:33     ` Nicholas Pratte
2024-09-10 11:30   ` Juraj Linkeš
2024-09-12 20:31     ` Nicholas Pratte
2024-11-18 16:51   ` Luca Vizzarro
2024-07-05 17:13 ` [PATCH v2 2/6] dts: Use First Core Logic Change Nicholas Pratte
2024-09-10 13:34   ` Juraj Linkeš
2024-11-18 16:54   ` Luca Vizzarro
2024-07-05 17:13 ` [PATCH v2 3/6] dts: Self-Discovering Architecture Change Nicholas Pratte
2024-09-10 13:41   ` Juraj Linkeš
2024-11-18 17:14   ` Luca Vizzarro
2024-07-05 17:13 ` [PATCH v2 4/6] dts: Rework DPDK Attributes In SUT Node Config Nicholas Pratte
2024-09-10 14:04   ` Juraj Linkeš
2024-11-18 17:16   ` Luca Vizzarro
2024-07-05 17:13 ` [PATCH v2 5/6] dts: add conditional behavior for test suite Nicholas Pratte
2024-07-16 14:59   ` Jeremy Spewock
2024-09-10 14:12   ` Juraj Linkeš
2024-11-06 20:52   ` Dean Marx
2024-11-18 17:21   ` Luca Vizzarro
2024-07-05 17:13 ` [PATCH v2 6/6] doc: dpdk documentation changes for new dts config Nicholas Pratte
2024-09-10 14:17   ` Juraj Linkeš
2024-11-06 20:57   ` Dean Marx
2024-11-18 17:21   ` Luca Vizzarro
2024-07-05 18:24 ` [PATCH v2 1/6] dts: Remove build target config and list of devices Nicholas Pratte
2025-01-24 11:39 ` [PATCH v4 0/7] dts: refactor configuration Luca Vizzarro
2025-01-24 11:39   ` [PATCH v4 1/7] dts: enable arch self-discovery Luca Vizzarro
2025-01-24 18:09     ` Nicholas Pratte
2025-01-24 11:39   ` [PATCH v4 2/7] dts: simplify build options config Luca Vizzarro
2025-01-24 18:10     ` Nicholas Pratte
2025-01-24 11:39   ` [PATCH v4 3/7] dts: infer use first core without config Luca Vizzarro
2025-01-24 18:14     ` Nicholas Pratte
2025-01-24 11:39   ` [PATCH v4 4/7] dts: rework DPDK attributes in SUT node config Luca Vizzarro
2025-01-24 18:14     ` Nicholas Pratte
2025-01-24 11:39   ` [PATCH v4 5/7] dts: handle CLI overrides in the configuration Luca Vizzarro
2025-01-24 18:15     ` Nicholas Pratte [this message]
2025-01-24 11:39   ` [PATCH v4 6/7] dts: split configuration file Luca Vizzarro
2025-01-24 18:18     ` Nicholas Pratte
2025-01-24 11:39   ` [PATCH v4 7/7] dts: run all test suites by default Luca Vizzarro
2025-01-24 18:20     ` Nicholas Pratte
2025-01-24 18:54   ` [PATCH v4 0/7] dts: refactor configuration Nicholas Pratte

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='CAKXZ7ehyV2HEz_n7rUOkwkQ8ce1aUj1ra=HYhy59ZmJ0v42MDQ@mail.gmail.com' \
    --to=npratte@iol.unh.edu \
    --cc=dev@dpdk.org \
    --cc=dmarx@iol.unh.edu \
    --cc=luca.vizzarro@arm.com \
    --cc=paul.szczepanek@arm.com \
    --cc=probb@iol.unh.edu \
    /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).