from gym import Env class ProxyEnv(Env): def __init__(self, wrapped_env): self._wrapped_env = wrapped_env self.action_space = self._wrapped_env.action_space self.observation_space = self._wrapped_env.observation_space @property def wrapped_env(self): return self._wrapped_env def reset(self, **kwargs): return self._wrapped_env.reset(**kwargs) def step(self, action): return self._wrapped_env.step(action) def render(self, *args, **kwargs): return self._wrapped_env.render(*args, **kwargs) @property def horizon(self): return self._wrapped_env.horizon def terminate(self): if hasattr(self.wrapped_env, "terminate"): self.wrapped_env.terminate() def __getattr__(self, attr): if attr == '_wrapped_env': raise AttributeError() return getattr(self._wrapped_env, attr) def __getstate__(self): """ This is useful to override in case the wrapped env has some funky __getstate__ that doesn't play well with overriding __getattr__. The main problematic case is/was gym's EzPickle serialization scheme. :return: """ return self.__dict__ def __setstate__(self, state): self.__dict__.update(state) def __str__(self): return '{}({})'.format(type(self).__name__, self.wrapped_env)