Skip to content
This repository has been archived by the owner on Apr 7, 2022. It is now read-only.

Commit

Permalink
add parameters toml to make it flexible
Browse files Browse the repository at this point in the history
  • Loading branch information
zigen committed Jan 9, 2022
1 parent b8ee37b commit 5b52f87
Show file tree
Hide file tree
Showing 14 changed files with 417 additions and 93 deletions.
12 changes: 10 additions & 2 deletions crispr/commands/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@
from crispr import config
from crispr.parameter_registry.registry import ParameterRegistry, init_registry
from crispr.utils import console
from crispr.constants import CRISPR_TEMPALTE_PARAMETERS_TOML
from rich.prompt import Confirm


@click.command()
@click.option(
"--parameter-schema", type=click.Path(exists=True), default=CRISPR_TEMPALTE_PARAMETERS_TOML
)
@click.argument(
"simulation_plan_file_path",
type=click.Path(exists=True),
required=False,
default="simulation.plan",
)
def plan(simulation_plan_file_path: str):
def plan(simulation_plan_file_path: str, parameter_schema: str):
source = ""
with open(simulation_plan_file_path, "rt") as f:
source = f.read()
registry = init_registry(ParameterRegistry())
param_toml = ""
with open(parameter_schema, "rt") as f:
param_toml = f.read()
registry = ParameterRegistry()
registry.load_from_toml(param_toml)
sim_plan = config.parse_config(source, registry)
settings = sim_plan.populate()
console.print(f"[green]{len(settings)} simulation settings populated.")
Expand Down
4 changes: 3 additions & 1 deletion crispr/config/parser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from crispr.simulation import SimPlan
from crispr.utils import console, error_console
from crispr.utils import console, error_console, logger
from crispr.parameter_registry import ParameterRegistry


Expand All @@ -23,6 +23,8 @@ def define_param(*args, **kwargs):
def parse_config(plan_source: str, registry: ParameterRegistry) -> SimPlan:
console.print("[yellow]Parsing simulation plan...")
config_vars = registry.create_default_config_vars()
logger.debug("defalut config_vars: ")
logger.debug(config_vars)
try:
exec(
plan_source,
Expand Down
1 change: 1 addition & 0 deletions crispr/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
CRISPR_TEMPALTE_OMNETPP_INI = os.path.join(CRISPR_ROOT_DIR, "templates", "omnetpp.ini")
CRISPR_TEMPALTE_IPYNB = os.path.join(CRISPR_ROOT_DIR, "templates", "analysis.ipynb")
CRISPR_TEMPALTE_TOPOLOGY_DIR = os.path.join(CRISPR_ROOT_DIR, "templates", "topology")
CRISPR_TEMPALTE_PARAMETERS_TOML = os.path.join(CRISPR_ROOT_DIR, "templates", "parameters.toml")

DEFAULT_RICH_CONSOLE_THEME = Theme(
{
Expand Down
48 changes: 41 additions & 7 deletions crispr/parameter_registry/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@
Any,
Tuple,
Union,
get_args,
)
from dataclasses import dataclass
from crispr.utils import error_console


class ParameterKind(Enum):
META = 1 # meta data, not used in simulation
BUILT_IN = 2 # built-in parameter, network_type, etc.
NETWORK_PARAM = 3 # {network_name}.{param_name} = {param_value}
PARAM = 4
META = "meta" # meta data, not used in simulation
BUILT_IN = "built_in" # built-in parameter, network_type, etc.
NETWORK_PARAM = "network_param" # {network_name}.{param_name} = {param_value}
PARAM = "param"


T = TypeVar("T")
Expand Down Expand Up @@ -47,8 +46,8 @@ def validate(self) -> bool:
return True

def default_key_value(self) -> Tuple[str, Optional[Union[T, List[T]]]]:
if self.singular is not None:
if self.plural is not None:
if self.singular:
if self.plural: # prefer plural
return self.plural, self.default_values
return self.singular, self.default_value
assert False, f"Unexpected case: {self}"
Expand Down Expand Up @@ -104,3 +103,38 @@ def is_number(self) -> bool:

def is_bool(self) -> bool:
return self.__orig_class__.__args__[0] is bool # type: ignore

@staticmethod
def from_dict(key: str, data) -> "Parameter":
p = Parameter(
singular=key,
plural=data["plural"] if "plural" in data else None,
kind=ParameterKind(data["kind"]),
param_key=data["param_key"] if "param_key" in data else "",
required=data["required"],
default_value=data["default_value"] if "default_value" in data else None,
default_values=data["default_values"] if "default_values" in data else None,
options=data["options"] if "options" in data else None,
)

class OrigClass:
args: List[Any]

def __init__(self, t):
self.args = [t]

@property
def __args__(self):
return self.args

# XXX: dirty hack to provide type var for parameter
p.__orig_class__ = OrigClass(TYPES[data["type"]]) # type: ignore
return p


TYPES = {
"str": str,
"int": int,
"float": float,
"bool": bool,
}
39 changes: 36 additions & 3 deletions crispr/parameter_registry/registry.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from typing import List, Dict, Any
from crispr.utils import error_console
from typing import List, Dict, Any, Optional
import toml
from crispr.parameter_registry.schema import PARAM_SCHEMA_SCHEMA
from crispr.utils import error_console, logger
from .parameter import Parameter, ParameterKind
from .schema import validate_config


class ParameterRegistry:
Expand All @@ -9,18 +12,32 @@ class ParameterRegistry:
def __init__(self) -> None:
self.parameters = []

@staticmethod
def extract_config(source_str: str) -> List[Parameter]:
conf = toml.loads(source_str)
logger.debug(conf)
if not validate_config(conf):
raise RuntimeError("Invalid config")
param_data = conf["parameter"]
return [Parameter.from_dict(key, param_data[key]) for key in param_data]

def register(self, parameter: Parameter):
if [p for p in self.parameters if p == parameter]:
return
if not parameter.validate():
raise RuntimeError(f"Invalid parameter: {parameter}")
self.parameters.append(parameter)

def register_all(self, parameters: List[Parameter]):
for p in parameters:
self.register(p)

def create_default_config_vars(self) -> Dict[str, Any]:
vars = dict()
for parameter in self.parameters:
k, v = parameter.default_key_value()
vars[k] = v
vars["config_ini_file"] = self.find_by_name("config_ini_file").default_value
return vars

def validate_config_vars(self, vars: Dict[str, Any]) -> bool:
Expand All @@ -46,8 +63,16 @@ def validate_config_vars(self, vars: Dict[str, Any]) -> bool:
key = parameter.plural
if not parameter.validate_type(key, vars[key]):
is_valid = False

for key in vars:
if not self.find_by_name_or_none(key):
error_console.print(f"[yellow]warning: {key} is not registered, ignoring")

return is_valid

def load_from_toml(self, source_str: str) -> None:
self.register_all(self.extract_config(source_str))

def get_singular_name(self, singular_or_plural_name: str) -> str:
for p in self.parameters:
if singular_or_plural_name == p.plural:
Expand All @@ -63,7 +88,15 @@ def find_by_name(self, name: str) -> Parameter:
for p in self.parameters:
if name == p.singular:
return p
raise RuntimeError("Parameter {name} is not registered")
raise RuntimeError(f"Parameter {name} is not registered")

def find_by_name_or_none(self, name: str) -> Optional[Parameter]:
for p in self.parameters:
if name == p.singular:
return p
if p.plural and name == p.plural:
return p
return None


def init_registry(registry: ParameterRegistry) -> ParameterRegistry:
Expand Down
143 changes: 87 additions & 56 deletions crispr/parameter_registry/registry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,26 @@

def test_registry():
r = ParameterRegistry()
r.register(
Parameter[str](
singular="title",
plural=None,
kind=ParameterKind.META,
default_value=None,
required=True,
)
r.register_all(
[
Parameter[str](
singular="title",
plural=None,
kind=ParameterKind.META,
default_value=None,
required=True,
),
Parameter[str](
singular="config_ini_file",
plural=None,
kind=ParameterKind.META,
default_value=None,
required=True,
),
]
)
vars = r.create_default_config_vars()
vars["config_ini_file"] = "test"
assert "title" in vars
assert vars["title"] is None
is_valid = r.validate_config_vars(vars)
Expand All @@ -40,7 +50,6 @@ def test_validate_config_vars():
def test_cannot_register_same_parameter():
r = ParameterRegistry()
assert len(r.parameters) == 0
print(r.parameters)
r.register(
Parameter[int](
singular="num_buf",
Expand All @@ -63,53 +72,75 @@ def test_cannot_register_same_parameter():
assert len(r.parameters) == 1


def test_load_toml_file():
toml_str = """
title = "hoge"
[parameter.num_buf]
plural = "num_bufs"
default_values = [5]
kind = "meta"
type = "int"
required = true
param_key = "beffers"
[parameter.num_node]
plural = "num_nodes"
default_values = [5]
kind = "param"
type = "int"
required = true
param_key = "nodes"
"""
params = ParameterRegistry.extract_config(toml_str)
r = ParameterRegistry()
r.register_all(params)


def init_registry() -> ParameterRegistry:
registry = ParameterRegistry()
registry.register(
Parameter[int](
singular="num_buf",
plural="num_bufs",
kind=ParameterKind.PARAM,
default_values=[50],
required=True,
)
)
registry.register(
Parameter[int](
singular="num_node",
plural="num_nodes",
kind=ParameterKind.NETWORK_PARAM,
default_values=[5],
required=True,
)
)
registry.register(
Parameter[str](
singular="network_type",
plural="network_types",
kind=ParameterKind.BUILT_IN,
default_value="linear",
required=True,
options=["linear"],
)
)
registry.register(
Parameter[str](
singular="connection_type",
plural="connection_types",
kind=ParameterKind.NETWORK_PARAM,
default_value=None,
required=True,
options=["MIM", "MM"],
)
)
registry.register(
Parameter[str](
singular="config_ini_file",
plural=None,
kind=ParameterKind.BUILT_IN,
default_value="",
required=True,
)
)
config_toml = """
title = "test config"
[parameter.num_buf]
plural = "num_bufs"
kind = "param"
type = "int"
required = true
default_values = [50]
param_key = "beffers"
[parameter.num_node]
plural = "num_nodes"
kind = "network_param"
type = "int"
default_values = [5]
required = true
param_key = "numNodes"
[parameter.network_type]
plural = "network_types"
kind = "built_in"
default_values = ["linear"]
required = true
param_key = "networkType"
type = "str"
options = ["linear"]
[parameter.connection_type]
plural = "connection_types"
kind = "network_param"
required = true
param_key = "connectionType"
type = "str"
options = ["MM", "MIM"]
[parameter.config_ini_file]
kind = "built_in"
required = true
param_key = ""
type = "str"
"""
registry.register_all(ParameterRegistry.extract_config(config_toml))

return registry
Loading

0 comments on commit 5b52f87

Please sign in to comment.