Skip to content

fix(envs): add __getattr__ to _LazyAsyncVectorEnv for attribute proxying#3331

Open
reeceomahoney wants to merge 1 commit intohuggingface:mainfrom
reeceomahoney:fix/lazy-env-getattr
Open

fix(envs): add __getattr__ to _LazyAsyncVectorEnv for attribute proxying#3331
reeceomahoney wants to merge 1 commit intohuggingface:mainfrom
reeceomahoney:fix/lazy-env-getattr

Conversation

@reeceomahoney
Copy link
Copy Markdown
Contributor

Type / Scope

  • Type: Bug
  • Scope: envs

Summary / Motivation

_LazyAsyncVectorEnv (introduced in #3274) only explicitly delegates reset, step, call, and get_attr. Accessing any other attribute on the wrapper — such as env.unwrapped.metadata["render_fps"] in eval_policy — raises AttributeError:

  File "/home/reece/Work/lerobot/src/lerobot/scripts/lerobot_eval.py", line 422, in eval_policy
    env.unwrapped.metadata["render_fps"],
    ^^^^^^^^^^^^^
AttributeError: '_LazyAsyncVectorEnv' object has no attribute 'unwrapped'

This is hit whenever eval runs with video rendering enabled (max_episodes_rendered > 0).

Related issues

What changed

  • Added __getattr__ to _LazyAsyncVectorEnv that materializes the underlying AsyncVectorEnv and forwards the attribute lookup. This is the standard proxy pattern and ensures all attributes (e.g. unwrapped, metadata, spec) work transparently.

How was this tested

  • Ran pre-commit run --files src/lerobot/envs/utils.py — all checks pass.
  • Reproduced the error by running lerobot-eval with video rendering enabled; confirmed it no longer raises AttributeError.

Checklist (required before merge)

  • Linting/formatting run (pre-commit run -a)
  • All tests pass locally (pytest)
  • Documentation updated
  • CI is green

Reviewer notes

  • Single 4-line change in src/lerobot/envs/utils.py.
  • __getattr__ is only called when normal attribute lookup fails, so the existing explicit methods (reset, step, etc.) are unaffected.

_LazyAsyncVectorEnv only explicitly delegates reset/step/call/get_attr,
so accessing any other attribute (e.g. env.unwrapped.metadata) raises
AttributeError. Add a __getattr__ fallback that materializes the
underlying AsyncVectorEnv and forwards the lookup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 9, 2026 09:38
@github-actions github-actions bot added the evaluation For issues or PRs related to environment evaluation, and benchmarks. label Apr 9, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes _LazyAsyncVectorEnv acting as an incomplete proxy by forwarding unknown attribute access (e.g., unwrapped, metadata, spec) to the underlying lazily-materialized gym.vector.AsyncVectorEnv, preventing AttributeError during evaluation with video rendering.

Changes:

  • Add __getattr__ to _LazyAsyncVectorEnv to call _ensure() and delegate attribute lookup to the wrapped env.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +190 to +192
def __getattr__(self, name: str):
self._ensure()
return getattr(self._env, name)
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

Consider adding a small regression test for this proxying behavior (e.g., that accessing unwrapped/metadata on _LazyAsyncVectorEnv materializes the underlying env and forwards the attribute). A lightweight approach is to monkeypatch gym.vector.AsyncVectorEnv with a dummy object so the test doesn’t need to spawn subprocesses.

Copilot uses AI. Check for mistakes.
Comment on lines +190 to +192
def __getattr__(self, name: str):
self._ensure()
return getattr(self._env, name)
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

For type-safety and clearer failure modes, it’d be good to narrow the optional type after _ensure() (e.g., assert the underlying _env is not None) and consider annotating __getattr__ to return Any to reflect that it forwards arbitrary attributes.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

evaluation For issues or PRs related to environment evaluation, and benchmarks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants