Skip to content

Commit

Permalink
Add deprecation warnings for features removed in Gymnasium v1.0 (#535)
Browse files Browse the repository at this point in the history
  • Loading branch information
pseudo-rnd-thoughts authored Jul 14, 2023
1 parent f46c988 commit 7ddce8c
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 21 deletions.
2 changes: 2 additions & 0 deletions gymnasium/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
registry,
pprint_registry,
make_vec,
register_envs,
)

# necessary for `envs.__init__` which registers all gymnasium environments and loads plugins
Expand All @@ -39,6 +40,7 @@
"register",
"registry",
"pprint_registry",
"register_envs",
# module folders
"envs",
"experimental",
Expand Down
42 changes: 40 additions & 2 deletions gymnasium/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import numpy as np

from gymnasium import spaces
from gymnasium import logger, spaces
from gymnasium.utils import RecordConstructorArgs, seeding


Expand Down Expand Up @@ -234,6 +234,10 @@ def __exit__(self, *args: Any):
# propagate exception
return False

def get_wrapper_attr(self, name: str) -> Any:
"""Gets the attribute `name` from the environment."""
return getattr(self, name)


WrapperObsType = TypeVar("WrapperObsType")
WrapperActType = TypeVar("WrapperActType")
Expand Down Expand Up @@ -273,15 +277,48 @@ def __init__(self, env: Env[ObsType, ActType]):
self._cached_spec: EnvSpec | None = None

def __getattr__(self, name: str) -> Any:
"""Returns an attribute with ``name``, unless ``name`` starts with an underscore."""
"""Returns an attribute with ``name``, unless ``name`` starts with an underscore.
Args:
name: The variable name
Returns:
The value of the variable in the wrapper stack
Warnings:
This feature is deprecated and removed in v1.0 and replaced with `env.get_attr(name})`
"""
if name == "_np_random":
raise AttributeError(
"Can't access `_np_random` of a wrapper, use `self.unwrapped._np_random` or `self.np_random`."
)
elif name.startswith("_"):
raise AttributeError(f"accessing private attribute '{name}' is prohibited")
logger.warn(
f"env.{name} to get variables from other wrappers is deprecated and will be removed in v1.0, "
f"to get this variable you can do `env.unwrapped.{name}` for environment variables or `env.get_attr('{name}')` that will search the reminding wrappers."
)
return getattr(self.env, name)

def get_wrapper_attr(self, name: str) -> Any:
"""Gets an attribute from the wrapper and lower environments if `name` doesn't exist in this object.
Args:
name: The variable name to get
Returns:
The variable with name in wrapper or lower environments
"""
if hasattr(self, name):
return getattr(self, name)
else:
try:
return self.env.get_wrapper_attr(name)
except AttributeError as e:
raise AttributeError(
f"wrapper {self.class_name()} has no attribute {name!r}"
) from e

@property
def spec(self) -> EnvSpec | None:
"""Returns the :attr:`Env` :attr:`spec` attribute with the `WrapperSpec` if the wrapper inherits from `EzPickle`."""
Expand Down Expand Up @@ -361,6 +398,7 @@ def reward_range(self) -> tuple[SupportsFloat, SupportsFloat]:
"""Return the :attr:`Env` :attr:`reward_range` unless overwritten then the wrapper :attr:`reward_range` is used."""
if self._reward_range is None:
return self.env.reward_range
logger.warn("The `reward_range` is deprecated and will be removed in v1.0")
return self._reward_range

@reward_range.setter
Expand Down
24 changes: 22 additions & 2 deletions gymnasium/envs/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import traceback
from collections import defaultdict
from dataclasses import dataclass, field
from types import ModuleType
from typing import Any, Callable, Iterable, Sequence

import gymnasium as gym
Expand Down Expand Up @@ -43,6 +44,7 @@
"make_vec",
"spec",
"pprint_registry",
"register_envs",
]


Expand Down Expand Up @@ -523,7 +525,9 @@ def _find_spec(env_id: str) -> EnvSpec:

if env_spec is None:
_check_version_exists(ns, name, version)
raise error.Error(f"No registered env with id: {env_name}")
raise error.Error(
f"No registered env with id: {env_name}. Did you register it, or import the package that registers it? Use `gymnasium.pprint_registry()` to see all of the registered environments."
)

return env_spec

Expand Down Expand Up @@ -592,6 +596,11 @@ def load_plugin_envs(entry_point: str = "gymnasium.envs"):
logger.warn(f"plugin: {plugin.value} raised {traceback.format_exc()}")


def register_envs(env_module: ModuleType):
"""A No-op function such that it can appear to IDEs that a module is used."""
pass


@contextlib.contextmanager
def namespace(ns: str):
"""Context manager for modifying the current namespace."""
Expand Down Expand Up @@ -658,9 +667,13 @@ def register(
ns_id = current_namespace
else:
ns_id = ns

full_env_id = get_env_id(ns_id, name, version)

if autoreset is True:
logger.warn(
"`gymnasium.register(..., autoreset=True)` is deprecated and will be removed in v1.0. If users wish to use it then add the auto reset wrapper in the `addition_wrappers` argument."
)

new_spec = EnvSpec(
id=full_env_id,
entry_point=entry_point,
Expand Down Expand Up @@ -836,6 +849,9 @@ def make(
if apply_api_compatibility is True or (
apply_api_compatibility is None and env_spec.apply_api_compatibility is True
):
logger.warn(
"`gymnasium.make(..., apply_api_compatibility=True)` and `env_spec.apply_api_compatibility` is deprecated and will be removed in v1.0"
)
env = gym.wrappers.EnvCompatibility(env, render_mode)

# Run the environment checker as the lowest level wrapper
Expand All @@ -858,6 +874,10 @@ def make(
if autoreset is True or (autoreset is None and env_spec.autoreset is True):
env = gym.wrappers.AutoResetWrapper(env)

logger.warn(
"`gymnasium.make(..., autoreset=True)` is deprecated and will be removed in v1.0"
)

for wrapper_spec in env_spec.additional_wrappers[num_prior_wrappers:]:
if wrapper_spec.kwargs is None:
raise ValueError(
Expand Down
5 changes: 2 additions & 3 deletions gymnasium/experimental/wrappers/stateful_observation.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,8 @@ def __init__(
self.flatten: Final[bool] = flatten
self.normalize_time: Final[bool] = normalize_time

if hasattr(env, "_max_episode_steps"):
self.max_timesteps = getattr(env, "_max_episode_steps")
elif env.spec is not None and env.spec.max_episode_steps is not None:
# We don't need to keep if a TimeLimit wrapper exists as `spec` will do that work for us now
if env.spec is not None and env.spec.max_episode_steps is not None:
self.max_timesteps = env.spec.max_episode_steps
else:
raise ValueError(
Expand Down
3 changes: 3 additions & 0 deletions gymnasium/vector/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def make(
[-0.03774345, -0.02418869, -0.00942293, 0.0469184 ]],
dtype=float32), {})
"""
gym.logger.warn(
"`gymnasium.vector.make(...)` is deprecated and will be replaced by `gymnasium.make_vec(...)` in v1.0"
)

def create_env(env_num: int) -> Callable[[], Env]:
"""Creates an environment that can enable or disable the environment checker."""
Expand Down
4 changes: 2 additions & 2 deletions gymnasium/wrappers/compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ def __init__(self, old_env: LegacyEnv, render_mode: Optional[str] = None):
render_mode (str): the render mode to use when rendering the environment, passed automatically to env.render
"""
logger.deprecation(
"The `gymnasium.make(..., apply_api_compatibility=...)` parameter is deprecated and will be removed in v0.29. "
"Instead use `gym.make('GymV21Environment-v0', env_name=...)` or `from shimmy import GymV21CompatibilityV0`"
"The `gymnasium.make(..., apply_api_compatibility=...)` parameter is deprecated and will be removed in v1.0. "
"Instead use `gymnasium.make('GymV21Environment-v0', env_name=...)` or `from shimmy import GymV21CompatibilityV0`"
)

self.env = old_env
Expand Down
18 changes: 14 additions & 4 deletions gymnasium/wrappers/normalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,13 @@ def __init__(self, env: gym.Env, epsilon: float = 1e-8):
gym.utils.RecordConstructorArgs.__init__(self, epsilon=epsilon)
gym.Wrapper.__init__(self, env)

self.num_envs = getattr(env, "num_envs", 1)
self.is_vector_env = getattr(env, "is_vector_env", False)
try:
self.num_envs = self.get_wrapper_attr("num_envs")
self.is_vector_env = self.get_wrapper_attr("is_vector_env")
except AttributeError:
self.num_envs = 1
self.is_vector_env = False

if self.is_vector_env:
self.obs_rms = RunningMeanStd(shape=self.single_observation_space.shape)
else:
Expand Down Expand Up @@ -121,8 +126,13 @@ def __init__(
gym.utils.RecordConstructorArgs.__init__(self, gamma=gamma, epsilon=epsilon)
gym.Wrapper.__init__(self, env)

self.num_envs = getattr(env, "num_envs", 1)
self.is_vector_env = getattr(env, "is_vector_env", False)
try:
self.num_envs = self.get_wrapper_attr("num_envs")
self.is_vector_env = self.get_wrapper_attr("is_vector_env")
except AttributeError:
self.num_envs = 1
self.is_vector_env = False

self.return_rms = RunningMeanStd(shape=())
self.returns = np.zeros(self.num_envs)
self.gamma = gamma
Expand Down
9 changes: 7 additions & 2 deletions gymnasium/wrappers/record_episode_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,19 @@ def __init__(self, env: gym.Env, deque_size: int = 100):
gym.utils.RecordConstructorArgs.__init__(self, deque_size=deque_size)
gym.Wrapper.__init__(self, env)

self.num_envs = getattr(env, "num_envs", 1)
try:
self.num_envs = self.get_wrapper_attr("num_envs")
self.is_vector_env = self.get_wrapper_attr("is_vector_env")
except AttributeError:
self.num_envs = 1
self.is_vector_env = False

self.episode_count = 0
self.episode_start_times: np.ndarray = None
self.episode_returns: Optional[np.ndarray] = None
self.episode_lengths: Optional[np.ndarray] = None
self.return_queue = deque(maxlen=deque_size)
self.length_queue = deque(maxlen=deque_size)
self.is_vector_env = getattr(env, "is_vector_env", False)

def reset(self, **kwargs):
"""Resets the environment using kwargs and resets the episode returns and lengths."""
Expand Down
6 changes: 5 additions & 1 deletion gymnasium/wrappers/record_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,13 @@ def __init__(
self.terminated = False
self.truncated = False
self.recorded_frames = 0
self.is_vector_env = getattr(env, "is_vector_env", False)
self.episode_id = 0

try:
self.is_vector_env = self.get_wrapper_attr("is_vector_env")
except AttributeError:
self.is_vector_env = False

def reset(self, **kwargs):
"""Reset the environment using kwargs and then starts recording if video enabled."""
observations = super().reset(**kwargs)
Expand Down
6 changes: 5 additions & 1 deletion gymnasium/wrappers/time_aware_observation.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ def __init__(self, env: gym.Env):
low = np.append(self.observation_space.low, 0.0)
high = np.append(self.observation_space.high, np.inf)
self.observation_space = Box(low, high, dtype=np.float32)
self.is_vector_env = getattr(env, "is_vector_env", False)

try:
self.is_vector_env = self.get_wrapper_attr("is_vector_env")
except AttributeError:
self.is_vector_env = False

def observation(self, observation):
"""Adds to the observation with the current time step.
Expand Down
8 changes: 4 additions & 4 deletions gymnasium/wrappers/vector_list_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ def __init__(self, env):
Args:
env (Env): The environment to apply the wrapper
"""
assert getattr(
env, "is_vector_env", False
), "This wrapper can only be used in vectorized environments."

gym.utils.RecordConstructorArgs.__init__(self)
gym.Wrapper.__init__(self, env)
try:
self.get_wrapper_attr("is_vector_env")
except AttributeError:
assert False, "This wrapper can only be used in vectorized environments."

def step(self, action):
"""Steps through the environment, convert dict info to list."""
Expand Down

0 comments on commit 7ddce8c

Please sign in to comment.