Skip to content

Commit

Permalink
Add more helpful error messages if users use a mixture of Gym and Gym…
Browse files Browse the repository at this point in the history
…nasium
  • Loading branch information
pseudo-rnd-thoughts committed Mar 7, 2024
1 parent 36598b9 commit c8b51c2
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 12 deletions.
15 changes: 15 additions & 0 deletions gymnasium/envs/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,21 @@ def make(
f"{e} was raised from the environment creator for {env_spec.id} with kwargs ({env_spec_kwargs})"
)

if not isinstance(env, gym.Env):
if (
str(env.__class__.__base__) == "<class 'gym.core.Env'>"
or str(env.__class__.__base__) == "<class 'gym.core.Wrapper'>"
):
raise TypeError(
"Gym is incompatible with Gymnasium, please update the environment class to `gymnasium.Env`. "
"See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
)
else:
raise TypeError(
f"The environment must inherit from the gymnasium.Env class, actual class: {type(env)}. "
"See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
)

# Set the minimal env spec for the environment.
env.unwrapped.spec = EnvSpec(
id=env_spec.id,
Expand Down
24 changes: 17 additions & 7 deletions gymnasium/utils/env_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,20 @@ def check_env(
if warn is not None:
logger.warn("`check_env(warn=...)` parameter is now ignored.")

assert isinstance(
env, gym.Env
), "The environment must inherit from the gymnasium.Env class. See https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/ for more info."

if not isinstance(env, gym.Env):
if (
str(env.__class__.__base__) == "<class 'gym.core.Env'>"
or str(env.__class__.__base__) == "<class 'gym.core.Wrapper'>"
):
raise TypeError(
"Gym is incompatible with Gymnasium, please update the environment class to `gymnasium.Env`. "
"See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
)
else:
raise TypeError(
f"The environment must inherit from the gymnasium.Env class, actual class: {type(env)}. "
"See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
)
if env.unwrapped is not env:
logger.warn(
f"The environment ({env}) is different from the unwrapped version ({env.unwrapped}). This could effect the environment checker as the environment most likely has a wrapper applied to it. We recommend using the raw environment for `check_env` using `env.unwrapped`."
Expand All @@ -297,13 +307,13 @@ def check_env(
# ============= Check the spaces (observation and action) ================
assert hasattr(
env, "action_space"
), "The environment must specify an action space. See https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/ for more info."
), "The environment must specify an action space. See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
check_action_space(env.action_space)
check_space_limit(env.action_space, "action")

assert hasattr(
env, "observation_space"
), "The environment must specify an observation space. See https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/ for more info."
), "The environment must specify an observation space. See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
check_observation_space(env.observation_space)
check_space_limit(env.observation_space, "observation")

Expand Down Expand Up @@ -331,7 +341,7 @@ def check_env(
new_env.close()
else:
logger.warn(
"Not able to test alternative render modes due to the environment not having a spec. Try instantialising the environment through gymnasium.make"
"Not able to test alternative render modes due to the environment not having a spec. Try instantiating the environment through `gymnasium.make`"
)

if not skip_close_check and env.spec is not None:
Expand Down
11 changes: 8 additions & 3 deletions gymnasium/utils/passive_env_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,14 @@ def check_space(
):
"""A passive check of the environment action space that should not affect the environment."""
if not isinstance(space, spaces.Space):
raise AssertionError(
f"{space_type} space does not inherit from `gymnasium.spaces.Space`, actual type: {type(space)}"
)
if str(space.__class__.__base__) == "<class 'gym.spaces.space.Space'>":
raise TypeError(
f"Gym is incompatible with Gymnasium, please update the environment {space_type}_space to `{str(space.__class__.__base__).replace('gym', 'gymnasium')}`."
)
else:
raise TypeError(
f"{space_type} space does not inherit from `gymnasium.spaces.Space`, actual type: {type(space)}"
)

elif isinstance(space, spaces.Box):
check_box_space_fn(space)
Expand Down
16 changes: 14 additions & 2 deletions gymnasium/wrappers/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,25 @@ def __init__(self, env: gym.Env[ObsType, ActType]):
gym.utils.RecordConstructorArgs.__init__(self)
gym.Wrapper.__init__(self, env)

if not isinstance(env, gym.Env):
if str(env.__class__.__base__) == "<class 'gym.core.Env'>":
raise TypeError(
"Gym is incompatible with Gymnasium, please update the environment class to `gymnasium.Env`. "
"See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
)
else:
raise TypeError(
f"The environment must inherit from the gymnasium.Env class, actual class: {type(env)}. "
"See https://gymnasium.farama.org/introduction/create_custom_env/ for more info."
)

assert hasattr(
env, "action_space"
), "The environment must specify an action space. https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/"
), "The environment must specify an action space. https://gymnasium.farama.org/introduction/create_custom_env/"
check_action_space(env.action_space)
assert hasattr(
env, "observation_space"
), "The environment must specify an observation space. https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/"
), "The environment must specify an observation space. https://gymnasium.farama.org/introduction/create_custom_env/"
check_observation_space(env.observation_space)

self.checked_reset: bool = False
Expand Down
111 changes: 111 additions & 0 deletions tests/utils/test_env_checker_with_gym.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import re

import pytest

import gymnasium
from gymnasium.utils.env_checker import check_env


gym = pytest.importorskip("gym")


class NoClassEnv:
def __init__(self):
self.action_space = gym.spaces.Discrete(2)
self.observation_space = gym.spaces.Discrete(2)


class IncorrectEnv(gym.Env):
def __init__(self):
self.action_space = gym.spaces.Discrete(2)
self.observation_space = gym.spaces.Discrete(2)


class IncorrectAction(gymnasium.Env):
def __init__(self):
self.action_space = gym.spaces.Discrete(2)
self.observation_space = gymnasium.spaces.Discrete(2)


class IncorrectObs(gymnasium.Env):
def __init__(self):
self.action_space = gymnasium.spaces.Discrete(2)
self.observation_space = gym.spaces.Discrete(2)


def test_check_env_with_gym():
with pytest.raises(
TypeError,
match=re.escape(
"The environment must inherit from the gymnasium.Env class, actual class: <class"
),
):
check_env(NoClassEnv())

with pytest.raises(
TypeError,
match=re.escape(
"Gym is incompatible with Gymnasium, please update the environment class to `gymnasium.Env`."
),
):
check_env(IncorrectEnv())

with pytest.raises(
TypeError,
match=re.escape(
"Gym is incompatible with Gymnasium, please update the environment observation_space to `<class 'gymnasium.spaces.space.Space'>`."
),
):
check_env(IncorrectObs())

with pytest.raises(
TypeError,
match=re.escape(
"Gym is incompatible with Gymnasium, please update the environment action_space to `<class 'gymnasium.spaces.space.Space'>`."
),
):
check_env(IncorrectAction())


def test_passive_env_checker_with_gym():
gymnasium.register("NoClassEnv", NoClassEnv)
gymnasium.register("IncorrectEnv", IncorrectEnv)
gymnasium.register("IncorrectObs", IncorrectObs)
gymnasium.register("IncorrectAction", IncorrectAction)

with pytest.raises(
TypeError,
match=re.escape(
"The environment must inherit from the gymnasium.Env class, actual class: <class"
),
):
gymnasium.make("NoClassEnv")

with pytest.raises(
TypeError,
match=re.escape(
"Gym is incompatible with Gymnasium, please update the environment class to `gymnasium.Env`."
),
):
gymnasium.make("IncorrectEnv")

with pytest.raises(
TypeError,
match=re.escape(
"Gym is incompatible with Gymnasium, please update the environment observation_space to `<class 'gymnasium.spaces.space.Space'>`."
),
):
gymnasium.make("IncorrectObs")

with pytest.raises(
TypeError,
match=re.escape(
"Gym is incompatible with Gymnasium, please update the environment action_space to `<class 'gymnasium.spaces.space.Space'>`."
),
):
gymnasium.make("IncorrectAction")

gymnasium.registry.pop("NoClassEnv")
gymnasium.registry.pop("IncorrectEnv")
gymnasium.registry.pop("IncorrectObs")
gymnasium.registry.pop("IncorrectAction")

0 comments on commit c8b51c2

Please sign in to comment.