|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
| 5 | +import inspect |
5 | 6 | import tomllib |
6 | 7 | import warnings |
7 | 8 | from functools import partial, wraps |
8 | 9 | from pathlib import Path |
9 | | -from typing import TYPE_CHECKING, Any, Callable, ParamSpec, Protocol, TypeVar, runtime_checkable |
| 10 | +from typing import TYPE_CHECKING, Any, Callable, ParamSpec, TypeVar |
10 | 11 |
|
11 | 12 | import numpy as np |
12 | 13 |
|
@@ -49,16 +50,6 @@ def wrapper( |
49 | 50 | return decorator |
50 | 51 |
|
51 | 52 |
|
52 | | -model_parameter_registry: dict[str, type[ModelParams]] = {} |
53 | | - |
54 | | - |
55 | | -def named_tuple2xp(params: ModelParams, xp: ModuleType, device: str | None = None) -> ModelParams: |
56 | | - """Convert a named tuple to an array API framework.""" |
57 | | - return params.__class__( |
58 | | - **{k: xp.asarray(v, device=device) for k, v in params._asdict().items()} |
59 | | - ) |
60 | | - |
61 | | - |
62 | 53 | def parametrize( |
63 | 54 | fn: Callable[P, R], drone_model: str, xp: ModuleType | None = None, device: str | None = None |
64 | 55 | ) -> Callable[P, R]: |
@@ -87,59 +78,28 @@ def parametrize( |
87 | 78 | Returns: |
88 | 79 | The parametrized controller function with all keyword argument only parameters filled in. |
89 | 80 | """ |
90 | | - model_id = fn.__module__ + "." + fn.__name__ |
91 | 81 | try: |
92 | | - params = model_parameter_registry[model_id].load(drone_model) |
93 | | - if xp is not None: # Convert to any array API framework |
94 | | - params = named_tuple2xp(params, xp=xp, device=device) |
| 82 | + xp = np if xp is None else xp |
| 83 | + # physics = Path(sys.modules[fn.__module__].__file__).parent.name |
| 84 | + physics = fn.__module__.split(".")[-2] |
| 85 | + sig = inspect.signature(fn) |
| 86 | + kwonly_params = [ |
| 87 | + name |
| 88 | + for name, param in sig.parameters.items() |
| 89 | + if param.kind == inspect.Parameter.KEYWORD_ONLY |
| 90 | + ] |
| 91 | + params = load_params(physics, drone_model) |
| 92 | + |
| 93 | + params = {k: xp.asarray(v, device=device) for k, v in params.items() if k in kwonly_params} |
| 94 | + # if xp is not None: # Convert to any array API framework |
| 95 | + # params = named_tuple2xp(params, xp=xp, device=device) |
95 | 96 | except KeyError as e: |
96 | 97 | raise KeyError( |
97 | | - f"Model `{model_id}` does not exist in the parameter registry for drone `{drone_model}`" |
| 98 | + f"Model `{physics}` does not exist in the parameter registry for drone `{drone_model}`" |
98 | 99 | ) from e |
99 | 100 | except ValueError as e: |
100 | | - raise ValueError(f"Drone model `{drone_model}` not supported for `{model_id}`") from e |
101 | | - return partial(fn, **params._asdict()) |
102 | | - |
103 | | - |
104 | | -@runtime_checkable |
105 | | -class ModelParams(Protocol): |
106 | | - """Protocol for model parameters.""" |
107 | | - |
108 | | - @staticmethod |
109 | | - def load(drone_model: str) -> ModelParams: |
110 | | - """Load the parameters from the config file.""" |
111 | | - |
112 | | - def _asdict(self) -> dict[str, Any]: |
113 | | - """Convert the parameters to a dictionary.""" |
114 | | - |
115 | | - |
116 | | -def register_model_parameters( |
117 | | - params: ModelParams | type[ModelParams], |
118 | | -) -> Callable[[Callable[P, R]], Callable[P, R]]: |
119 | | - """Register the default model parameters for this model. |
120 | | -
|
121 | | - Warning: |
122 | | - The model parameters **must** be a named tuple with a function `load` that takes in the |
123 | | - drone model name and returns an instance of itself, or a class that implements the |
124 | | - ModelParams protocol. |
125 | | -
|
126 | | - Args: |
127 | | - params: The model parameter type. |
128 | | -
|
129 | | - Returns: |
130 | | - A decorator function that registers the parameters and returns the function unchanged. |
131 | | - """ |
132 | | - if not isinstance(params, ModelParams): |
133 | | - raise ValueError(f"{params} does not implement the ModelParams protocol") |
134 | | - |
135 | | - def decorator(fn: Callable[P, R]) -> Callable[P, R]: |
136 | | - controller_id = fn.__module__ + "." + fn.__name__ |
137 | | - if controller_id in model_parameter_registry: |
138 | | - raise ValueError(f"Model `{controller_id}` already registered") |
139 | | - model_parameter_registry[controller_id] = params |
140 | | - return fn |
141 | | - |
142 | | - return decorator |
| 101 | + raise ValueError(f"Drone model `{drone_model}` not supported for `{physics}`") from e |
| 102 | + return partial(fn, **params) |
143 | 103 |
|
144 | 104 |
|
145 | 105 | def load_params(physics: str, drone_model: str, xp: ModuleType | None = None) -> dict: |
|
0 commit comments