-
Notifications
You must be signed in to change notification settings - Fork 8.7k
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
Rewriting of the registration mechanism #2748
Conversation
Thanks for the changes, I can't see any obvious issues with the code though I haven't done a thorough review |
I don't think there are reasonable cases where this would break someone code. The removed features are undocumented implementation details and weren't intended for end-user usage as far as I know. But you never know |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some generic software quality comments. Re: docstrings, even a one-liner re-affirming what you would guess from the name can help reader be confident they didn't misunderstand the purpose of a method.
In general I'm also a fan of adding one-liner comments to unit test to say what it's intended to verify, but this is not a core contribution of this PR anyway.
Remove old tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done! LGTM
|
||
from gym import Env, error, logger | ||
from gym.envs.__relocated__ import internal_env_relocation_map | ||
|
||
if sys.version_info >= (3, 8): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we build for python 3.7 and greater then this is still needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea? We're still building for 3.7, so that will still have the else
condition, unless I'm misunderstanding something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested for python 3.7 and without the from __future__ import annotation
then the import fails however with the __future__
I didnt have an issue
Registering the exact same ID again now raises an error as opposed to overriding with a warning before. Is this intentional? (Would this be in issue for backward compatibility or would noone ever intentionally do this?) Also, couple of things not related to the PR changes, but part of registration -
|
@arjun-kg Thanks, I changed back the error-warning thing during registration. I changed the error message because that's fairly straight-forward and doesn't actually change functionality. Updating the parser would be a whole other mess, so keeping this outside the scope of this |
I think I addressed everything, a few things that I'm deliberately keeping out of scope for now (so that the basic functionality can be merged faster) are:
|
@RedTachyon what about the comment about |
@Markus28 I don't think I see the comment? |
@RedTachyon Hmm idk, maybe something weird is going on with GitHub, I can't link the comments and it doesn't show up in the review section. These were my comments, I am mostly concerned about the second one: |
@Markus28 that's like the second time I'm seeing the same issue in a week (from another person), you entered these comments as a review and need to click a green button somewhere on top of the page to submit the review for them to actually show up |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, forgot that
|
||
# Check if the package is installed | ||
# If not instruct the user to install the package and then how to instantiate the env | ||
if importlib.util.find_spec(relocated_package) is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure this will not work for ALE! In __relocation__.py
, the package is called "ale-py", which is indeed what needs to be used for pip install
, but it has to be imported as ale_py
. Even if ale-py is installed, this branch will be taken (which it shouldn't imo).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I think this was copy-pasted verbatim from the previous version of the code, it's possible it doesn't work, but that's out of scope here
gym/envs/registration.py
Outdated
|
||
if self.autoreset: | ||
from gym.wrappers.autoreset import AutoResetWrapper | ||
def check_name_exists(ns: Optional[str], name: str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not completely sure whether I really understand what this is supposed to do. It is my understanding that it checks
- the existence of the namespace
- the existence of the name
separately.
If we assume we had a Box2D namespace something like check_name_exists("Box2D", "AirRaid")
would pass this test, even though there is no environment that matches the pattern "Box2D/AirRaid-v?", is that correct? Do we really want this behavior?
I would have expected something like if spec_.namespace == ns
in line 137.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I'll add the if spec_.namespace == ns
condition
""" | ||
Register an environment with gym. The `id` parameter corresponds to the name of the environment, | ||
with the syntax as follows: | ||
`(namespace)/(env_name)-(version)` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Three uniformed questions:
- I can't parse the regex where at the beginning of the file, but we expect
version
to be of the formv<integer>
, right? Maybe that should be mentioned in the docstring, otherwise people will try to use integers - If
namespace
is not specified, do we expectid
to be of the form/<env-name>-v<version>
? The lineLine 399 in 4cc6edf
full_id = (current_namespace or "") + id current_namespace
is not None? - If
namespace
is specified andcurrent_namespace
is notNone
, the old implementation would override the namespace from the id. There is also a corresponding warning in this line but I don't see how anything is being overwritten at any point? Just looking at the code, it seems to me that we would just get a malformed id?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Updated
- Good point, this actually breaks
with namespace
, I'll fix it - Yep, I'll fix that too
unversioned_spec = next( | ||
( | ||
spec_ | ||
for spec_ in registry.values() | ||
if spec_.namespace == spec.namespace | ||
and spec_.name == spec.name | ||
and spec_.version is None | ||
), | ||
None, | ||
) | ||
|
||
if unversioned_spec and spec.version is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I am misunderstanding the point of this section, I would advise replacing unversioned_spec
with unversinoed_spec is not None
or putting is not None
after the line above. It will work like this but I don't really like the mechanism because it causes bugs on a regular basis (especially when working with integers that might be 0) and it's harder to parse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Description
This is a total rewrite of
gym.envs.regitration
as proposed in #2738.It technically doesn't really add any new features beyond fixing a few things that used not to work, but they weren't necessarily documented, so it's hard to call it a bug fix either.
Instead, this significantly simplifies the implementation of registration so that we can actually start adding features to it
The current version implements all significant* behaviors from the old registration mechanism. The intended mechanism is as follows:
gym.envs.registration
EnvSpec
and add it to the registryEnvSpec
from the registrynamespace/EnvName-vX
(this already existed, but was undocumented, so I'll add it to the docs somewhere later)One thing I have yet to add is adding an optional minimal env checker on
make
to check if the environment uses the up-to-date API.*Some low-level details (like the EnvSpecTree) are removed. Also, the error messages may be a bit different, but following the same spirit, and passing the previous tests for where errors and warnings are expected. This is with the exception of one test which was just bugged.
Highlights
To justify this change, here's a comparison of how
make
changedIn the old implementation, you have
gym.make
which takes an environment name and any kwargs, and instantly just callsregistry.make
. This finds the rightEnvSpec
, and then callsspec.make
. The actual env creation logic lives inspec.make
.Now, it's all handled by
gym.make
-- it finds the rightspec
in theregistry
, initializes it, applies whatever wrappers necessary, and returns the environment.This is significant when trying to change something about
gym.make
. Previously, you'd have to propagate any changes across the three functions. Now you just change the one function responsible for that.An extra bug that this accidentally solves is something that lived in the
register
function. In the old code, all of its logic was in atry-except-finally
block, where the actual registration happened infinally
. So even if you completely malformed your environment registration, it will throw an exception and then... still register it.Notably,
EnvSpecTree
has been removed and replaced with a dictionary and a few functions. This might cause a worse asymptotical lookup complexity if someone has thousands of environments and namespaces registered, and tries to create an incorrectly named environment, but that's about it (if you have the right environment name, the lookup is still just a dictionary lookup)Note:
This is a very core part of the code, so will require significant review. I'm going for full backwards compatibility in terms of
make
,register
andspec
.Checklist:
pre-commit
checks withpre-commit run --all-files
(seeCONTRIBUTING.md
instructions to set it up)