Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a complete compatibility wrapper #3066

Merged
merged 22 commits into from
Sep 6, 2022

Conversation

RedTachyon
Copy link
Contributor

This should in principle make it so that any* legacy environment can be created and then converted into a valid modern environment.

WIP, I want to see if tests work for 3.6 (ugh) since I had to do a hack around protocols. I also still need to automatically integrate it into the make pipeline.

Brief explanation of the methodology: I implemented a protocol which will type check if something is a valid legacy env according to a minimal "mandatory" set of methods and fields. In python >= 3.8, this is available by default in typing. In 3.7, we need to use typing_extensions, which in turn does not support 3.6, for which the protocol check will be de facto disabled.

*Restrictions apply. Old environments expected to inherit the old gym.Env and will instead inherit from the new gym.Env, so there may be issues in some cases.

@RedTachyon RedTachyon marked this pull request as ready for review September 5, 2022 15:56
@RedTachyon RedTachyon changed the title [WIP] Add a complete compatibility wrapper Add a complete compatibility wrapper Sep 5, 2022
Copy link
Contributor

@pseudo-rnd-thoughts pseudo-rnd-thoughts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good. Do we not want to change the name in make and EnvSpec fromapply_step_compatibility to apply_env_compatibility?

assert env.observation_space == Discrete(1)
assert env.action_space == Discrete(1)
assert env.reset() == (0, {})
assert env.reset(seed=0, options={"some": "option"}) == (0, {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a test that reset actual calls seed correctly but Im not sure that matters

@@ -146,7 +140,6 @@ def test_apply_step_compatibility():
max_episode_steps=3,
)
env = gym.make("testing-old-env")
assert has_wrapper(env, StepAPICompatibility)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this assert removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old semantic for the compatibility layer was that it's a valid gym.Wrapper, because a gym.Env could be both in the old and new API. Now for an env to be a valid gym.Env, it has to follow the new API, which means that something written with the old API, isn't technically a gym.Env, i.e. it can't be the input to a gym.Wrapper.

The new compatibility layer is simply an implementation of a gym.Env, which happens to have a somewhat similar structure to a wrapper, but isn't one. So it used to be the case that an old-to-new environment is wrapped by StepAPICompatibility as a wrapper, which was checked in the test. Now that's not the case anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the environment not come before the passive environment checker?

@RedTachyon
Copy link
Contributor Author

Do we not want to change the name in make and EnvSpec from apply_step_compatibility to apply_env_compatibility?

Changed it to apply_api_compatibility to be a bit more informative, does that make sense?

Copy link
Contributor

@pseudo-rnd-thoughts pseudo-rnd-thoughts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM unless depending on if we want the passive environment checker to trigger for the old environments. Currently the warnings will occur.

@Markus28
Copy link
Contributor

Markus28 commented Sep 5, 2022

I talked to @younik about auto human rendering today (i.e. not having to call render if render_mode is set to "human"; this feature was originally part of the new API, then accidentally removed, then added back in #3063). I think the compatibility wrapper should also implement this.
With the current implementation, I believe that we need to keep calling wrapped_env.render() for human-rendering, which isn't in line with the new API.

@RedTachyon
Copy link
Contributor Author

I put the compatibility layer before the env checker, I agree it makes more sense this way. I think? I feel like some sort of an acknowledgment of "You shouldn't be doing this" is warranted (which would have been thrown up by the env checker), but at the same time, you have to enable this explicitly, so you know what you're doing.


About the rendering - I'm a bit out of loop with the details of those changes, as I understand we just want

if self.render_mode == "human":
    self.render()

inside env.step?

@Markus28
Copy link
Contributor

Markus28 commented Sep 6, 2022

Yes, I think that's essentially right, though we would also want to add this to reset (and correspondingly, it should be at the very end of the step method, which it currently is :)).

@RedTachyon
Copy link
Contributor Author

In the last commit I added some logic to allow doing gym.make("LegacyEnv", render_mode=...), does it make sense? It removes the render_mode argument from kwargs if we're using the compatibility layer, and redirects it to the wrapper.

@RedTachyon
Copy link
Contributor Author

(for anyone in the future wondering what's going on - I added an unrelated fix for #3068)

@pseudo-rnd-thoughts
Copy link
Contributor

LGTM

Comment on lines +9 to +12
if sys.version_info >= (3, 8):
from typing import Protocol, runtime_checkable
elif sys.version_info >= (3, 7):
from typing_extensions import Protocol, runtime_checkable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typing_extension does the version check internally, is it necessary to check here? pytorch seems to simply use typing_extensions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your right but this shouldn't change the implementation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants