-
Notifications
You must be signed in to change notification settings - Fork 8.6k
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
Avoid metaclass conflicts when inheriting from gym.Env
#3001
Conversation
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.
Hello, thanks for addressing it!
LGTM
(You will probably just need to fix pre-commit hook
)
Using __init_subclass__ instead of metaclass, suggested by PEP 487(introduced in python3.6). As a result, downstream package can safely inherit from gym.Env and abc.ABC/Protocol/...(classes with metaclass != type), or set their own metaclass without making a intermediate metaclass inherited from custom metaclass and type(gym.Env).
6032dc0
to
d9b050c
Compare
"""Hook used for wrapping render method.""" | ||
super().__init_subclass__() | ||
if "render" in vars(cls): | ||
cls.render = _deprecate_mode(vars(cls)["render"]) |
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.
Any reason why this can't be cls.render = _deprecate_mode(cls.render)
? If not, I'd prefer that for simplicity
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.
Given "render" in vars(cls)
is True
, vars(cls)["render"]
is the same as cls.render
in 99.9% cases, except __getattr__
being overridden.
I want to maximize the consistency between exist-check and access. Ideally I want to write if "render" in vars(cls): vars(cls).update(render=vars(cls)["render"])
, but vars(cls)
is read-only.
FWIW, the reason why try...except
or hasattr
check + cls.render
cannot be used is that cls.render
can come from base classes.
BTW, do you think following code is of simplicity?
render_func = vars(cls).get("render")
if render_func is not None:
cls.render = render_func
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 like the alternative you presented here, of course with the added wrapper
Left one comment, looks good otherwise |
Description
Using
__init_subclass__
instead of metaclass, suggested by PEP 487(introduced in python3.6).As a result, downstream package can safely inherit from
gym.Env
andabc.ABC
/Protocol
/...(classes with metaclass !=type
), or set their own metaclass without making a intermediate metaclass inherited from custom metaclass andtype(gym.Env)
.For example, https://github.com/rlworkgroup/metaworld use
abc.ABC
/abc.ABCMeta
, thus it was broken by the metaclass introduced ingym-0.25.0
.https://github.com/rlworkgroup/metaworld/blob/18118a28c06893da0f363786696cc792457b062b/metaworld/envs/mujoco/mujoco_env.py#L31
https://github.com/rlworkgroup/metaworld/blob/18118a28c06893da0f363786696cc792457b062b/metaworld/envs/mujoco/sawyer_xyz/sawyer_xyz_env.py#L14
Above code works on
gym<0.25.0
, but crashs ongym==0.25.0
Type of change
If user-code/downstream library doesn't depend on
type(gym.Env)
, it should not be a breaking change, but there is a rare case that workaround for metaclass introduced ingym-0.25.0
is used:Above code will crash if
issubclass(abc.ABCMeta, type(gym.Env))
, which is true without decorator metaclass introduced ingym-0.25.0
sincetype(gym.Env) is type
, because of MRO conflict. i.e., above code will crash ongym<0.25.0
and after this change.I want to note that following code won't crash on any version of
gym
or after this change:Checklist:
pre-commit
checks withpre-commit run --all-files
(seeCONTRIBUTING.md
instructions to set it up)