Update utils/__init__.py
Browse files- utils/__init__.py +54 -28
utils/__init__.py
CHANGED
|
@@ -1,12 +1,5 @@
|
|
| 1 |
"""
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
Behavior:
|
| 5 |
-
- Avoids importing/probing `utils` at import time (prevents recursion).
|
| 6 |
-
- On first attribute access, imports the real `utils`, replaces sys.modules["utilities"]
|
| 7 |
-
with that real module (so subsequent imports resolve normally), and aliases any
|
| 8 |
-
already-loaded utils submodules under utilities.* for backward compatibility.
|
| 9 |
-
- Minimal and non-destructive.
|
| 10 |
"""
|
| 11 |
|
| 12 |
from __future__ import annotations
|
|
@@ -19,29 +12,64 @@
|
|
| 19 |
__all__ = ["__getattr__", "__dir__"]
|
| 20 |
|
| 21 |
_swapped: bool = False
|
|
|
|
| 22 |
|
| 23 |
def _swap_with_utils() -> ModuleType:
|
| 24 |
-
global _swapped
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
if _swapped:
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
def __getattr__(name: str) -> Any:
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
def __dir__() -> Iterable[str]:
|
| 47 |
try:
|
|
@@ -49,5 +77,3 @@ def __dir__() -> Iterable[str]:
|
|
| 49 |
return dir(real)
|
| 50 |
except Exception:
|
| 51 |
return ["__getattr__", "__dir__"]
|
| 52 |
-
|
| 53 |
-
__doc__ = __doc__
|
|
|
|
| 1 |
"""
|
| 2 |
+
Fixed utils/__init__.py - Prevents recursion in __getattr__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
"""
|
| 4 |
|
| 5 |
from __future__ import annotations
|
|
|
|
| 12 |
__all__ = ["__getattr__", "__dir__"]
|
| 13 |
|
| 14 |
_swapped: bool = False
|
| 15 |
+
_real_utils: ModuleType | None = None
|
| 16 |
|
| 17 |
def _swap_with_utils() -> ModuleType:
|
| 18 |
+
global _swapped, _real_utils
|
| 19 |
+
|
| 20 |
+
# Return cached module if already swapped
|
| 21 |
+
if _swapped and _real_utils is not None:
|
| 22 |
+
return _real_utils
|
| 23 |
+
|
| 24 |
+
# Prevent recursion by checking if we're already in the process
|
| 25 |
if _swapped:
|
| 26 |
+
# If we're here, something went wrong - return a dummy module
|
| 27 |
+
dummy = ModuleType("utils_dummy")
|
| 28 |
+
return dummy
|
| 29 |
+
|
| 30 |
+
try:
|
| 31 |
+
_swapped = True # Set this BEFORE importing to prevent recursion
|
| 32 |
+
_real_utils = importlib.import_module("utils")
|
| 33 |
+
|
| 34 |
+
# Replace utilities in sys.modules
|
| 35 |
+
sys.modules["utilities"] = _real_utils
|
| 36 |
+
|
| 37 |
+
# Alias submodules
|
| 38 |
+
for modname, module in list(sys.modules.items()):
|
| 39 |
+
if modname.startswith("utils.") and isinstance(module, ModuleType):
|
| 40 |
+
suffix = modname.partition(".")[2]
|
| 41 |
+
sys.modules[f"utilities.{suffix}"] = module
|
| 42 |
+
|
| 43 |
+
return _real_utils
|
| 44 |
+
|
| 45 |
+
except Exception as e:
|
| 46 |
+
# Reset state on failure
|
| 47 |
+
_swapped = False
|
| 48 |
+
_real_utils = None
|
| 49 |
+
# Create a minimal fallback module to prevent further errors
|
| 50 |
+
fallback = ModuleType("utils_fallback")
|
| 51 |
+
fallback.__dict__.update({
|
| 52 |
+
'device': ModuleType('device'),
|
| 53 |
+
'logging': ModuleType('logging'),
|
| 54 |
+
'config': ModuleType('config')
|
| 55 |
+
})
|
| 56 |
+
return fallback
|
| 57 |
|
| 58 |
def __getattr__(name: str) -> Any:
|
| 59 |
+
# Prevent infinite recursion by checking if we're already trying to get this attribute
|
| 60 |
+
if hasattr(__getattr__, '_in_progress'):
|
| 61 |
+
raise AttributeError(f"Recursion detected while getting attribute '{name}'")
|
| 62 |
+
|
| 63 |
+
try:
|
| 64 |
+
__getattr__._in_progress = True
|
| 65 |
+
real = _swap_with_utils()
|
| 66 |
+
if hasattr(real, name):
|
| 67 |
+
return getattr(real, name)
|
| 68 |
+
else:
|
| 69 |
+
raise AttributeError(f"module 'utilities' has no attribute '{name}'")
|
| 70 |
+
finally:
|
| 71 |
+
if hasattr(__getattr__, '_in_progress'):
|
| 72 |
+
delattr(__getattr__, '_in_progress')
|
| 73 |
|
| 74 |
def __dir__() -> Iterable[str]:
|
| 75 |
try:
|
|
|
|
| 77 |
return dir(real)
|
| 78 |
except Exception:
|
| 79 |
return ["__getattr__", "__dir__"]
|
|
|
|
|
|