Skip to content

Lazy-load concrete renderer classes via PEP 562 __getattr__#64

Merged
hallerite merged 3 commits into
mainfrom
lazy-init-getattr
May 25, 2026
Merged

Lazy-load concrete renderer classes via PEP 562 __getattr__#64
hallerite merged 3 commits into
mainfrom
lazy-init-getattr

Conversation

@hallerite
Copy link
Copy Markdown
Member

@hallerite hallerite commented May 25, 2026

Summary

  • renderers/__init__.py previously imported every concrete renderer module (renderers.default, renderers.qwen3, …) at load time. Each does from transformers.tokenization_utils import PreTrainedTokenizer at the top, so plain import renderers always pulled transformers into sys.modules.
  • That blocked light-import callers — most visibly prime-rl-configs's slim-install gate, which only needs the RendererConfig discriminated union from renderers.configs (no heavy deps).
  • Defer the concrete-class imports to a module-level __getattr__ (PEP 562). Configs and base symbols stay eager; from renderers import DefaultRenderer still works but only loads renderers.default (and hence transformers) on first attribute access. create_renderer is unaffected — renderers.base._populate_registry already lazy-imports the concrete classes when a renderer is instantiated.

Test plan

  • from renderers import RendererConfig no longer pulls transformers into sys.modules
  • renderers.DefaultRenderer (and every other concrete class) still resolves; transformers loads on first access
  • Unknown attribute raises AttributeError with the standard message
  • Full test suite: 1544 passed, 53 skipped, 1 xfailed (no regressions)
  • CI

🤖 Generated with Claude Code


Note

Low Risk
Single-package import wiring with no logic changes to rendering or registry behavior; public API and create_renderer paths stay the same aside from deferred heavy imports.

Overview
renderers/__init__.py no longer eagerly imports every concrete renderer module, so a plain import renderers (for configs, base types, create_renderer, etc.) does not transitively load transformers until something actually needs a renderer class.

Fifteen top-level renderer imports are replaced with a _LAZY_RENDERERS name → submodule map and PEP 562 __getattr__ / __dir__: the first from renderers import DefaultRenderer (or renderers.Qwen3Renderer, etc.) runs importlib.import_module, caches the class on the package, and only then pulls in that submodule’s transformers dependency. __all__ and the public names stay the same; unknown attributes still raise a normal AttributeError.

create_renderer behavior is unchanged — it still relies on renderers.base._populate_registry() to import concrete classes when a renderer is instantiated, not on the package __init__ eager imports.

Reviewed by Cursor Bugbot for commit dc43e11. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Lazy-load concrete renderer classes in renderers/__init__.py via PEP 562 __getattr__

Replaces eager imports of concrete renderer classes with on-demand loading using a _LAZY_RENDERERS name-to-module mapping. A module-level __getattr__ imports and caches the class on first access; __dir__ advertises all lazy names upfront. This reduces import-time overhead for any code that imports from the renderers package without using every renderer.

Macroscope summarized dc43e11.

hallerite and others added 3 commits May 25, 2026 23:44
``renderers/__init__.py`` previously imported every concrete renderer
class (``DefaultRenderer``, ``Qwen3Renderer``, …) at module load. Each
of those modules imports ``transformers.tokenization_utils.PreTrainedTokenizer``
at the top, so plain ``import renderers`` always pulled ``transformers``
into ``sys.modules``. That blocked light-import callers — most visibly
``prime-rl-configs``'s slim-install path, which only needs the
``RendererConfig`` discriminated union from ``renderers.configs`` (no
heavy deps).

Defer the concrete-class imports to a module-level ``__getattr__``
(PEP 562). Configs and base symbols stay eager; ``from renderers import
DefaultRenderer`` still works but only loads ``renderers.default`` (and
hence ``transformers``) on first access. ``create_renderer`` is
unaffected — ``renderers.base._populate_registry`` already lazy-imports
the concrete classes when a renderer is instantiated.

End-user API is unchanged. Full test suite passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The lazy-loading is a general win for any consumer of the config
layer; no need to name a specific downstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@macroscopeapp
Copy link
Copy Markdown

macroscopeapp Bot commented May 25, 2026

Approvability

Verdict: Approved

This PR refactors eager imports to lazy loading using Python's standard PEP 562 getattr pattern. The change is mechanical with no functional difference - renderer classes remain accessible through the same API, just loaded on-demand to avoid unnecessary transformers import overhead.

You can customize Macroscope's approvability policy. Learn more.

@hallerite hallerite merged commit 2ec28a8 into main May 25, 2026
11 checks passed
@hallerite hallerite deleted the lazy-init-getattr branch May 25, 2026 23:52
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.

1 participant