Skip to content

Commit 6cab116

Browse files
committed
Rewrite _coconut_lazy_module as function creating per-module class+metaclass
Instead of a class with complex __getattribute__/__setattr__ overrides, _coconut_lazy_module is now a function that creates a unique class per lazy module. The class IS the lazy module proxy, and its metaclass handles attribute access and dunder forwarding via closures over the load state. This eliminates the need for _coconut_base_getattr/_coconut_base_setattr hacks and __slots__ with prefixed names. Also simplifies trollius handling by removing the _coconut_trollius_module subclass. https://claude.ai/code/session_01KBLQLYTdfjLPaR2UJhgnkq
1 parent b157666 commit 6cab116

File tree

2 files changed

+44
-68
lines changed

2 files changed

+44
-68
lines changed

coconut/compiler/header.py

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,13 @@ def process_header_args(which, use_hash, target, no_tco, strict, no_wrap):
322322
(2, 7),
323323
if_lt='''
324324
import imp
325-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_module", imp.load_module(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_name"), *imp.find_module(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_name"))))
325+
return imp.load_module(name, *imp.find_module(name))
326326
''',
327327
if_ge='''
328328
import importlib
329-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_module", importlib.import_module(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_name")))
329+
return importlib.import_module(name)
330330
''',
331-
indent=4,
331+
indent=1,
332332
),
333333
import_OrderedDict=prepare(
334334
r'''
@@ -761,21 +761,9 @@ class you_need_to_install_typing_extensions{object}:
761761
import_asyncio=pycondition(
762762
(3, 4),
763763
if_lt='''
764-
class _coconut_trollius_module(_coconut_lazy_module):
765-
__slots__ = ()
766-
def coroutine(self, func):
767-
try:
768-
mod = self._coconut_load()
769-
except ImportError:
770-
def raise_import_error(*args, **kwargs):
771-
raise _coconut_lazy_module._coconut_base_getattr(self, "_coconut_import_err")
772-
return raise_import_error
773-
return mod.coroutine(func)
774-
def Return(self, obj):
775-
return self._coconut_load().Return(obj)
776-
asyncio = _coconut_trollius_module("trollius")
777-
asyncio_Return = asyncio.Return
778-
'''.format(**format_dict),
764+
asyncio = _coconut_lazy_module("trollius")
765+
asyncio_Return = _coconut_lazy_module("trollius", attr="Return")
766+
''',
779767
if_ge='''
780768
import asyncio
781769
asyncio_Return = StopIteration

coconut/compiler/templates/header.py_template

Lines changed: 38 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,45 @@
1-
class _coconut_lazy_module{object}:
2-
__slots__ = ("_coconut_name", "_coconut_module", "_coconut_on_import", "_coconut_import_err", "_coconut_attr")
3-
_coconut_base_getattr = object.__getattribute__
4-
_coconut_base_setattr = object.__setattr__
5-
def __init__(self, name, on_import=None, attr=None):
6-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_name", name)
7-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_module", None)
8-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_on_import", on_import)
9-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_import_err", None)
10-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_attr", attr)
11-
def _coconut_load(self):
12-
if _coconut_lazy_module._coconut_base_getattr(self, "_coconut_module") is None and _coconut_lazy_module._coconut_base_getattr(self, "_coconut_import_err") is None:
13-
try:
1+
def _coconut_import_module(name):
142
{lazy_module_import}
3+
_coconut_lazy_dunders = ("__call__", "__iter__", "__next__", "__len__", "__contains__", "__getitem__", "__setitem__", "__delitem__", "__reversed__", "__missing__", "__repr__", "__str__", "__format__", "__bytes__", "__hash__", "__int__", "__float__", "__complex__", "__index__", "__round__", "__ceil__", "__floor__", "__trunc__", "__neg__", "__pos__", "__abs__", "__invert__", "__add__", "__radd__", "__iadd__", "__sub__", "__rsub__", "__isub__", "__mul__", "__rmul__", "__imul__", "__truediv__", "__rtruediv__", "__itruediv__", "__floordiv__", "__rfloordiv__", "__ifloordiv__", "__mod__", "__rmod__", "__imod__", "__pow__", "__rpow__", "__ipow__", "__matmul__", "__rmatmul__", "__imatmul__", "__lshift__", "__rlshift__", "__ilshift__", "__rshift__", "__rrshift__", "__irshift__", "__and__", "__rand__", "__iand__", "__or__", "__ror__", "__ior__", "__xor__", "__rxor__", "__ixor__", "__lt__", "__le__", "__gt__", "__ge__", "__eq__", "__ne__", "__enter__", "__exit__", "__aiter__", "__anext__", "__aenter__", "__aexit__", "__await__", "__divmod__", "__rdivmod__", "__nonzero__", "__length_hint__")
4+
def _coconut_lazy_module(name, on_import=None, attr=None):
5+
_coconut_lazy_state = [None, None]
6+
def _coconut_lazy_load():
7+
if _coconut_lazy_state[0] is None and _coconut_lazy_state[1] is None:
8+
try:
9+
_coconut_lazy_state[0] = _coconut_import_module(name)
1510
except _coconut.ImportError as err:
16-
_coconut_lazy_module._coconut_base_setattr(self, "_coconut_import_err", err)
11+
_coconut_lazy_state[1] = err
1712
else:
18-
on_import = _coconut_lazy_module._coconut_base_getattr(self, "_coconut_on_import")
1913
if on_import is not None:
20-
on_import(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_module"))
21-
_coconut_import_err = _coconut_lazy_module._coconut_base_getattr(self, "_coconut_import_err")
22-
if _coconut_import_err is not None:
23-
raise _coconut_import_err
24-
_coconut_module = _coconut_lazy_module._coconut_base_getattr(self, "_coconut_module")
25-
_coconut_attr = _coconut_lazy_module._coconut_base_getattr(self, "_coconut_attr")
26-
if _coconut_attr is not None:
27-
return _coconut.getattr(_coconut_module, _coconut_attr)
28-
return _coconut_module
29-
def __getattribute__(self, name):
30-
if name in _coconut_lazy_module.__slots__ or name == "_coconut_load":
31-
return _coconut_lazy_module._coconut_base_getattr(self, name)
32-
try:
33-
return _coconut_lazy_module._coconut_base_getattr(self, name)
34-
except _coconut.AttributeError:
35-
pass
36-
return _coconut.getattr(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_load")(), name)
37-
def __setattr__(self, name, value):
38-
if name in _coconut_lazy_module.__slots__:
39-
_coconut_lazy_module._coconut_base_setattr(self, name, value)
40-
else:
41-
_coconut.setattr(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_load")(), name, value)
42-
def __dir__(self):
43-
try:
44-
return _coconut.dir(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_load")())
45-
except _coconut.ImportError:
46-
return _coconut_lazy_module.__slots__
47-
def __bool__(self):
48-
return True
49-
def _coconut_make_lazy_dunder(_coconut_dunder_name):
50-
def _coconut_lazy_dunder(self, *args, **kwargs):
51-
return _coconut.getattr(_coconut_lazy_module._coconut_base_getattr(self, "_coconut_load")(), _coconut_dunder_name)(*args, **kwargs)
52-
return _coconut_lazy_dunder
53-
for _coconut_dunder in ("__call__", "__iter__", "__next__", "__len__", "__contains__", "__getitem__", "__setitem__", "__delitem__", "__reversed__", "__missing__", "__repr__", "__str__", "__format__", "__bytes__", "__hash__", "__int__", "__float__", "__complex__", "__index__", "__round__", "__ceil__", "__floor__", "__trunc__", "__neg__", "__pos__", "__abs__", "__invert__", "__add__", "__radd__", "__iadd__", "__sub__", "__rsub__", "__isub__", "__mul__", "__rmul__", "__imul__", "__truediv__", "__rtruediv__", "__itruediv__", "__floordiv__", "__rfloordiv__", "__ifloordiv__", "__mod__", "__rmod__", "__imod__", "__pow__", "__rpow__", "__ipow__", "__matmul__", "__rmatmul__", "__imatmul__", "__lshift__", "__rlshift__", "__ilshift__", "__rshift__", "__rrshift__", "__irshift__", "__and__", "__rand__", "__iand__", "__or__", "__ror__", "__ior__", "__xor__", "__rxor__", "__ixor__", "__lt__", "__le__", "__gt__", "__ge__", "__eq__", "__ne__", "__enter__", "__exit__", "__aiter__", "__anext__", "__aenter__", "__aexit__", "__await__", "__divmod__", "__rdivmod__", "__nonzero__", "__length_hint__"):
54-
setattr(_coconut_lazy_module, _coconut_dunder, _coconut_make_lazy_dunder(_coconut_dunder))
14+
on_import(_coconut_lazy_state[0])
15+
if _coconut_lazy_state[1] is not None:
16+
raise _coconut_lazy_state[1]
17+
if attr is not None:
18+
return _coconut.getattr(_coconut_lazy_state[0], attr)
19+
return _coconut_lazy_state[0]
20+
class _coconut_lazy_meta(type):
21+
def __getattr__(cls, name):
22+
return _coconut.getattr(_coconut_lazy_load(), name)
23+
def __setattr__(cls, name, value):
24+
if name.startswith("__") and name.endswith("__"):
25+
type.__setattr__(cls, name, value)
26+
else:
27+
_coconut.setattr(_coconut_lazy_load(), name, value)
28+
def __dir__(cls):
29+
try:
30+
return _coconut.dir(_coconut_lazy_load())
31+
except _coconut.ImportError:
32+
return []
33+
def __bool__(cls):
34+
return True
35+
__nonzero__ = __bool__
36+
def _coconut_make_lazy_dunder(dname):
37+
def _coconut_lazy_dunder(cls, *args, **kwargs):
38+
return _coconut.getattr(_coconut_lazy_load(), dname)(*args, **kwargs)
39+
return _coconut_lazy_dunder
40+
for _coconut_dunder in _coconut_lazy_dunders:
41+
setattr(_coconut_lazy_meta, _coconut_dunder, _coconut_make_lazy_dunder(_coconut_dunder))
42+
return _coconut_lazy_meta("_coconut_lazy_module", (), {{}})
5543
@_coconut_wraps(_coconut_py_super)
5644
def _coconut_super(type=None, object_or_type=None):
5745
if type is None:

0 commit comments

Comments
 (0)