diff --git a/docs/api/vector.md b/docs/api/vector.md index c1e3e7b86..dbe0f5374 100644 --- a/docs/api/vector.md +++ b/docs/api/vector.md @@ -53,6 +53,10 @@ vector/utils The ``EnvSpec`` of the environment normally set during :py:meth:`gymnasium.make_vec` +.. autoattribute:: gymnasium.vector.VectorEnv.metadata + + The metadata of the environment containing rendering modes, rendering fps, etc + .. autoattribute:: gymnasium.vector.VectorEnv.render_mode The render mode of the environment which should follow similar specifications to `Env.render_mode`. diff --git a/gymnasium/vector/vector_env.py b/gymnasium/vector/vector_env.py index 7127dd9aa..271603a9a 100644 --- a/gymnasium/vector/vector_env.py +++ b/gymnasium/vector/vector_env.py @@ -92,6 +92,9 @@ class VectorEnv(Generic[ObsType, ActType, ArrayType]): :func:`make_vec` is the equivalent function to :func:`make` for vector environments. """ + # Set this in SOME subclasses + metadata: dict[str, Any] = {"render_modes": []} + spec: EnvSpec | None = None render_mode: str | None = None closed: bool = False @@ -446,6 +449,11 @@ class VectorWrapper(VectorEnv): """Returns the `render_mode` from the base environment.""" return self.env.render_mode + @property + def metadata(self) -> dict[str, Any]: + """Returns the `metadata` from the base environment.""" + return self.env.metadata + @property def np_random(self) -> np.random.Generator: """Returns the environment's internal :attr:`_np_random` that if not set will initialise with a random seed. diff --git a/tests/vector/test_vector_wrapper.py b/tests/vector/test_vector_wrapper.py index 2701ecbb7..16dd82932 100644 --- a/tests/vector/test_vector_wrapper.py +++ b/tests/vector/test_vector_wrapper.py @@ -54,3 +54,17 @@ def test_vector_env_wrapper_attributes(): assert np.allclose(wrapped.env.get_attr("gravity"), env.get_attr("gravity")) env.close() + + +def test_vector_env_metadata(): + """Test if `metadata` property for VectorWrapper correctly forwards to the vector env it is wrapping.""" + env = gym.make_vec("CartPole-v1", num_envs=3, vectorization_mode="sync") + wrapped = DummyVectorWrapper( + gym.make_vec("CartPole-v1", num_envs=3, vectorization_mode="sync") + ) + + assert env.metadata == wrapped.metadata + env.metadata = {"render_modes": ["rgb_array"]} + assert env.metadata != wrapped.metadata + + env.close()