refactor: generalize builder types

This commit is contained in:
gmega 2025-01-17 08:34:49 -03:00
parent 60fd274b18
commit 82f1f9a2ed
No known key found for this signature in database
GPG Key ID: 6290D34EAD824B18
5 changed files with 24 additions and 20 deletions

View File

@ -6,8 +6,8 @@ from typing import Dict
from pydantic_core import ValidationError
from benchmarks.core.config import ConfigParser, ExperimentBuilder
from benchmarks.core.experiments.experiments import Experiment
from benchmarks.core.config import ConfigParser
from benchmarks.core.experiments.experiments import Experiment, ExperimentBuilder
from benchmarks.logging.logging import (
basic_log_parser,
LogSplitter,
@ -22,7 +22,7 @@ from benchmarks.logging.sources import (
split_logs_in_source,
)
config_parser = ConfigParser()
config_parser = ConfigParser[ExperimentBuilder]()
config_parser.register(DelugeExperimentConfig)
log_parser = basic_log_parser()

View File

@ -6,39 +6,43 @@ from io import TextIOBase
from typing import Type, Dict, TextIO
import yaml
from typing_extensions import Generic, overload
from typing_extensions import Generic, overload, TypeVar
from benchmarks.core.experiments.experiments import TExperiment
from benchmarks.core.pydantic import SnakeCaseModel
T = TypeVar("T")
class ExperimentBuilder(SnakeCaseModel, Generic[TExperiment]):
""":class:`ExperimentBuilders` can build real :class:`Experiment`s out of :class:`ConfigModel`s."""
class Builder(SnakeCaseModel, Generic[T]):
""":class:`Builder` is a configuration model that can build useful objects."""
@abstractmethod
def build(self) -> TExperiment:
def build(self) -> T:
pass
class ConfigParser:
TBuilder = TypeVar("TBuilder", bound=Builder)
class ConfigParser(Generic[TBuilder]):
"""
:class:`ConfigParser` is a utility class to parse configuration files into :class:`ExperimentBuilder`s.
Currently, each :class:`ExperimentBuilder` can appear at most once in the config file.
:class:`ConfigParser` is a utility class to parse configuration files into :class:`Builder`s.
Currently, each :class:`Builder` type can appear at most once in the config file.
"""
def __init__(self):
self.experiment_types = {}
def register(self, root: Type[ExperimentBuilder[TExperiment]]):
def register(self, root: Type[TBuilder]):
self.experiment_types[root.alias()] = root
@overload
def parse(self, data: dict) -> Dict[str, ExperimentBuilder[TExperiment]]: ...
def parse(self, data: dict) -> Dict[str, TBuilder]: ...
@overload
def parse(self, data: TextIO) -> Dict[str, ExperimentBuilder[TExperiment]]: ...
def parse(self, data: TextIO) -> Dict[str, TBuilder]: ...
def parse(self, data: dict | TextIO) -> Dict[str, ExperimentBuilder[TExperiment]]:
def parse(self, data: dict | TextIO) -> Dict[str, TBuilder]:
if isinstance(data, TextIOBase):
entries = yaml.safe_load(os.path.expandvars(data.read()))
else:

View File

@ -8,6 +8,8 @@ from typing import List, Optional
from typing_extensions import Generic, TypeVar
from benchmarks.core.config import Builder
logger = logging.getLogger(__name__)
@ -22,6 +24,8 @@ class Experiment(ABC):
TExperiment = TypeVar("TExperiment", bound=Experiment)
ExperimentBuilder = Builder[TExperiment]
class ExperimentWithLifecycle(Experiment):
"""An :class:`ExperimentWithLifecycle` is a basic implementation of an :class:`Experiment` with overridable

View File

@ -6,11 +6,11 @@ from pydantic import BaseModel, Field, model_validator, HttpUrl
from torrentool.torrent import Torrent
from urllib3.util import parse_url
from benchmarks.core.config import ExperimentBuilder
from benchmarks.core.experiments.experiments import (
IteratedExperiment,
ExperimentEnvironment,
BoundExperiment,
ExperimentBuilder,
)
from benchmarks.core.experiments.static_experiment import StaticDisseminationExperiment
from benchmarks.core.pydantic import Host

View File

@ -13,7 +13,6 @@ from tenacity import retry, wait_exponential, stop_after_attempt
from tenacity.stop import stop_base
from tenacity.wait import wait_base
from torrentool.torrent import Torrent
from typing_extensions import TypeVar
from urllib3.util import Url
from benchmarks.core.experiments.experiments import ExperimentComponent
@ -168,9 +167,6 @@ class DelugeNode(SharedFSNode[Torrent, DelugeMeta], ExperimentComponent):
return f"DelugeNode({self.name}, {self.daemon_args['host']}:{self.daemon_args['port']})"
T = TypeVar("T")
class ResilientCallWrapper:
def __init__(self, node: Any, wait_policy: wait_base, stop_policy: stop_base):
self.node = node