Source code for masa.common.utils
from __future__ import annotations
from typing import Optional
import importlib
import warnings
from masa.plugins.helpers import load_plugins
from masa.common.registry import ENV_REGISTRY, CONSTRAINT_REGISTRY
from masa.common.wrappers import TimeLimit, ConstraintMonitor, RewardMonitor
from masa.common.labelled_env import LabelledEnv
from masa.common.label_fn import LabelFn
def load_callable(path: str):
"""Load a callable from 'module_path:object_name' string."""
if ":" not in path:
raise ValueError("Expected 'module:callable' for --label-fn/--cost-fn")
mod, name = path.split(":", 1)
try:
return getattr(importlib.import_module(mod), name)
except AttributeError:
warnings.warn(f"Could not load object from path: {path}")
return None
[docs]
def make_env(
env_id: str,
constraint: str,
max_episode_steps: int,
*,
label_fn: Optional[LabelFn] = None,
**constraint_kwargs
) -> gym.Env:
r"""
Construct a fully wrapped MASA environment using the canonical wrapper order.
This helper creates a Gymnasium environment and applies MASA wrappers in the
**recommended and enforced order**:
:class:`~gymnasium.wrappers.TimeLimit` :math:`\rightarrow`
:class:`~masa.common.labelled_env.LabelledEnv` :math:`\rightarrow`
:class:`~masa.common.constraints.base.BaseConstraintEnv` :math:`\rightarrow`
:class:`~masa.common.wrappers.ConstraintMonitor` :math:`\rightarrow`
:class:`~masa.common.wrappers.RewardMonitor`
The resulting environment exposes labels, constraint metrics, and reward
summaries exclusively via the Gymnasium ``info`` dictionary. Observations
and rewards themselves are left unchanged.
Args:
env_id:
Environment identifier registered in ``ENV_REGISTRY``.
constraint:
Constraint identifier registered in ``CONSTRAINT_REGISTRY``.
max_episode_steps:
Maximum number of steps per episode. Applied via ``TimeLimit`` as
the outermost wrapper.
label_fn:
Optional function mapping observations to atomic predicate labels.
If provided, labels are computed on every ``reset`` and ``step`` and
stored under ``info["labels"]``.
**constraint_kwargs:
Additional keyword arguments forwarded to the constraint wrapper
constructor.
Returns:
A fully wrapped Gymnasium environment compatible with MASA algorithms,
monitors, and logging utilities.
Notes:
- Wrapper order is fixed and enforced.
- Constraints are reset automatically on environment reset.
- All semantic metadata (labels, costs, violations, metrics) is communicated
via the ``info`` dictionary.
See Also:
- :class:`masa.common.labelled_env.LabelledEnv`
- :class:`masa.common.constraints.base.BaseConstraintEnv`
- :class:`masa.common.wrappers.ConstraintMonitor`
- :class:`masa.common.wrappers.RewardMonitor`
"""
load_plugins()
env_ctor = ENV_REGISTRY.get(env_id)
constraint_ctor = CONSTRAINT_REGISTRY.get(constraint)
env = env_ctor()
# must wrap time limit first
env = TimeLimit(env, max_episode_steps)
if label_fn is not None:
env = LabelledEnv(env, label_fn)
env = constraint_ctor(env, **constraint_kwargs)
env = ConstraintMonitor(env)
env = RewardMonitor(env)
return env