Add lazy imports in header and PEP 810 lazy import syntax#898
Conversation
evhub
left a comment
There was a problem hiding this comment.
You also need to add tests, including for all combinations of lazy imports with from and as as well as imports changed across Python versions that should be remapped.
| def __call__(cls, *args, **kwargs): | ||
| return load()(*args, **kwargs) | ||
| def __iter__(cls): | ||
| return _coconut.iter(load()) |
There was a problem hiding this comment.
We should not need to manually set any dunders if the metaclass approach is working properly.
| ) | ||
| import_stmt = Forward() | ||
| import_stmt_ref = from_import | basic_import | ||
| import_stmt_ref = Optional(keyword("lazy"), default="") + (from_import | basic_import) |
There was a problem hiding this comment.
Instead of using default, let's just detect the number of tokens.
| self.name_info[imp_name]["imported"].add(loc) | ||
| if lazy: | ||
| return self.lazy_import(loc, imports, imp_from=imp_from) | ||
| return self.universal_import(loc, imports, imp_from=imp_from) |
There was a problem hiding this comment.
To make the flow clearer, put this in an else.
| ) | ||
| return "\n".join(stmts) | ||
|
|
||
| def lazy_import(self, loc, imports, imp_from=None): |
There was a problem hiding this comment.
universal_import does a lot more that this doesn't currently handle, like py2/py3 mapping. Let's fold this into that function instead of using it as a separate one (we should be replacing single_import instead of universal_import).
Implements `lazy import x` and `lazy from x import y` syntax per PEP 810. Lazy imports defer module loading until first attribute access. - Add `lazy` as optional prefix keyword in import grammar - Add `lazy_import()` method to generate _coconut_lazy_module calls - Add __call__ and __iter__ to lazy module metaclass for callable/iterable attrs - Reject lazy imports for star imports and __future__ Closes #890 https://claude.ai/code/session_01KBLQLYTdfjLPaR2UJhgnkq
- Add comprehensive tests for lazy import syntax (PEP 810) - Add _coconut_lazy_module to underscore_imports for package compilation - Add dir builtin to _coconut class for lazy module __dir__ - Update stub files with _coconut_lazy_module and dir Tests cover: - lazy import x - lazy import x as y - lazy from x import y - lazy from x import y as z - lazy from x import a, b - Remapped imports (queue -> Queue on py2) https://claude.ai/code/session_01KBLQLYTdfjLPaR2UJhgnkq
a69a614 to
efa7c3c
Compare
- Remove __call__ and __iter__ from _coconut_lazy_module metaclass - Detect lazy keyword by token count instead of using default="" - Put lazy/non-lazy import_handle return in if/else - Fold lazy_import into single_import/universal_import instead of being a separate method; lazy from-imports now use immediate attribute access on the lazy module proxy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| imp, imp_as = imp_as, None | ||
|
|
||
| if imp_as is not None and "." in imp_as: | ||
| if lazy: |
There was a problem hiding this comment.
I don't buy that this is the right intervention point; why don't we still need to handle fake_mods like below? I think you should be adding a lazy arg to import_stmt and handling it there instead.
| zip_longest = _zip_longest | ||
|
|
||
| import importlib as _importlib | ||
| _coconut_lazy_module = _importlib.import_module |
There was a problem hiding this comment.
Why is this showing up in the diff? Isn't this already in develop?
| ) | ||
| import_stmt = Forward() | ||
| import_stmt_ref = from_import | basic_import | ||
| import_stmt_ref = Optional(keyword("lazy")) + (from_import | basic_import) |
There was a problem hiding this comment.
It was better when we were using default="" here so that the first token was always either "lazy" or "" and we didn't have to do other weird stuff with the number of tokens. let's go back to that.
- Revert grammar to use default="" for Optional lazy keyword - Simplify import_handle token parsing back to tokens[0] == "lazy" - Move lazy import handling from single_import to import_stmt function - single_import now just passes lazy through to import_stmt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
lazy importsyntax per PEP 810 (Add lazy import syntax #890)Lazy Header Imports (#886)
Third-party imports (
async_generator,tstr,numpy,trollius,backports.functools_lru_cache) are now lazy-loaded using_coconut_lazy_module, a function that creates a per-module class with a metaclass handling attribute forwarding.PEP 810 Lazy Import Syntax (#890)
New syntax:
lazy import json— defers loading until first attribute accesslazy from json import dumps— defers loading until first useRestrictions:
lazy from __future__ import ...→ SyntaxErrorlazy from x import *→ SyntaxErrorTest plan
make testpasseslazy importandlazy from ... importsyntaxCloses #886
Closes #890
https://claude.ai/code/session_01KBLQLYTdfjLPaR2UJhgnkq