protomotions.utils.config_utils module#

protomotions.utils.config_utils.is_union(ann)[source]#

Whether a resolved annotation is a union in either spelling.

protomotions.utils.config_utils.declaring_module(cls, name)[source]#

The module of the class in cls’s MRO that declares field name.

A field’s annotation string (from __future__ import annotations) names types imported where the field is DECLARED; a subclass in another module inherits the field without those imports, so the string is evaluated against the declaring class’s module, as typing.get_type_hints does. Falls back to cls.__module__ for a name no class in the MRO annotates.

protomotions.utils.config_utils.resolve_field_annotation(cls, name)[source]#

The resolved annotation of cls.name, from that field alone; raises TypeError naming the field when the annotation string cannot be evaluated.

The one per-field resolver shared by the B4 saved form (config_schema) and the B3 override funnel. Resolving the whole class (get_type_hints) would fail whenever any OTHER field carries a name that does not resolve; resolving per field keeps one unrelated sibling from breaking every field being saved or overridden. The field’s type must be importable at the level of the module that DECLARES the field (an inherited field resolves in its base class’s module, as get_type_hints does; config.py imports MdpComponent and TerminationRule there) and spelled so this Python can evaluate it (PEP 604 unions and builtin generics need 3.10 / 3.9); an annotation that does not resolve is a real error, not a case to silence by returning Any (which would drop the None-for-non-Optional refusal at save).

protomotions.utils.config_utils.coerce(value, ann, path, cls, name)[source]#

Coerce a parsed literal to a field’s declared annotation (never its runtime value).

protomotions.utils.config_utils.apply_overrides(configs, overrides, roots=None)[source]#

Apply {root.path: value} overrides to an ExperimentConfigs in place.

The leaf is typed by its dataclass annotation, never by the runtime value, so a typo or a wrong type fails at parse time naming the field. roots limits which roots are applied (None = all), which lets the build funnel apply robot and simulator early and the rest after the build. Returns the coerced {path: value} that landed, for the undo check.

protomotions.utils.config_utils.read_override(configs, path)[source]#

Read the current value at a root.path override path on an ExperimentConfigs.

Walks the way the funnel does (a dict step by key, a dataclass or any other object by attribute). The inference derivation and the build-time undo check read back through this to see whether a builder step changed an early override.

protomotions.utils.config_utils.parse_cli_overrides(override_strings)[source]#

Parse command-line override strings into a dictionary.

Supports the format: “key=value” where value can be: - Numbers: “env.max_episode_length=1000” - Floats: “agent.learning_rate=1e-5” - Booleans: “env.enable_terrain=True” - Strings: “env.terrain.type=flat” - None: “env.early_termination=None”

Parameters:

override_strings (list) – List of “key=value” strings

Returns:

Dictionary of parsed overrides

Raises:

ValueError – If any override string is not in “key=value” format or key is empty.

Return type:

Dict[str, Any]

Example

parse_cli_overrides([“env.max_episode_length=1000”, “simulator.num_envs=4096”]) # Returns: {“env.max_episode_length”: 1000, “simulator.num_envs”: 4096}