exonware-xwlazy 0.1.0.11__py3-none-any.whl → 0.1.0.20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- exonware/__init__.py +26 -0
- exonware/xwlazy/__init__.py +0 -0
- exonware/xwlazy/common/__init__.py +47 -0
- exonware/xwlazy/common/base.py +56 -0
- exonware/xwlazy/common/cache.py +504 -0
- exonware/xwlazy/common/logger.py +257 -0
- exonware/xwlazy/common/services/__init__.py +72 -0
- exonware/xwlazy/common/services/dependency_mapper.py +232 -0
- exonware/xwlazy/common/services/install_async_utils.py +165 -0
- exonware/xwlazy/common/services/install_cache_utils.py +245 -0
- exonware/xwlazy/common/services/keyword_detection.py +283 -0
- exonware/xwlazy/common/services/spec_cache.py +165 -0
- xwlazy/lazy/lazy_state.py → exonware/xwlazy/common/services/state_manager.py +0 -2
- exonware/xwlazy/common/strategies/__init__.py +28 -0
- exonware/xwlazy/common/strategies/caching_dict.py +44 -0
- exonware/xwlazy/common/strategies/caching_installation.py +88 -0
- exonware/xwlazy/common/strategies/caching_lfu.py +66 -0
- exonware/xwlazy/common/strategies/caching_lru.py +63 -0
- exonware/xwlazy/common/strategies/caching_multitier.py +59 -0
- exonware/xwlazy/common/strategies/caching_ttl.py +59 -0
- {xwlazy/lazy → exonware/xwlazy}/config.py +51 -21
- exonware/xwlazy/contracts.py +1396 -0
- exonware/xwlazy/defs.py +378 -0
- xwlazy/lazy/lazy_errors.py → exonware/xwlazy/errors.py +21 -16
- exonware/xwlazy/facade.py +991 -0
- exonware/xwlazy/module/__init__.py +18 -0
- exonware/xwlazy/module/base.py +565 -0
- exonware/xwlazy/module/data.py +17 -0
- exonware/xwlazy/module/facade.py +246 -0
- exonware/xwlazy/module/importer_engine.py +2117 -0
- exonware/xwlazy/module/strategies/__init__.py +22 -0
- exonware/xwlazy/module/strategies/module_helper_lazy.py +93 -0
- exonware/xwlazy/module/strategies/module_helper_simple.py +65 -0
- exonware/xwlazy/module/strategies/module_manager_advanced.py +111 -0
- exonware/xwlazy/module/strategies/module_manager_simple.py +95 -0
- exonware/xwlazy/package/__init__.py +18 -0
- exonware/xwlazy/package/base.py +798 -0
- xwlazy/lazy/host_conf.py → exonware/xwlazy/package/conf.py +61 -16
- exonware/xwlazy/package/data.py +17 -0
- exonware/xwlazy/package/facade.py +480 -0
- exonware/xwlazy/package/services/__init__.py +84 -0
- exonware/xwlazy/package/services/async_install_handle.py +87 -0
- exonware/xwlazy/package/services/config_manager.py +245 -0
- exonware/xwlazy/package/services/discovery.py +370 -0
- {xwlazy/lazy → exonware/xwlazy/package/services}/host_packages.py +43 -20
- exonware/xwlazy/package/services/install_async.py +277 -0
- exonware/xwlazy/package/services/install_cache.py +145 -0
- exonware/xwlazy/package/services/install_interactive.py +59 -0
- exonware/xwlazy/package/services/install_policy.py +156 -0
- exonware/xwlazy/package/services/install_registry.py +54 -0
- exonware/xwlazy/package/services/install_result.py +17 -0
- exonware/xwlazy/package/services/install_sbom.py +153 -0
- exonware/xwlazy/package/services/install_utils.py +79 -0
- exonware/xwlazy/package/services/installer_engine.py +406 -0
- exonware/xwlazy/package/services/lazy_installer.py +718 -0
- {xwlazy/lazy → exonware/xwlazy/package/services}/manifest.py +40 -33
- exonware/xwlazy/package/services/strategy_registry.py +186 -0
- exonware/xwlazy/package/strategies/__init__.py +57 -0
- exonware/xwlazy/package/strategies/package_discovery_file.py +129 -0
- exonware/xwlazy/package/strategies/package_discovery_hybrid.py +84 -0
- exonware/xwlazy/package/strategies/package_discovery_manifest.py +101 -0
- exonware/xwlazy/package/strategies/package_execution_async.py +113 -0
- exonware/xwlazy/package/strategies/package_execution_cached.py +90 -0
- exonware/xwlazy/package/strategies/package_execution_pip.py +99 -0
- exonware/xwlazy/package/strategies/package_execution_wheel.py +106 -0
- exonware/xwlazy/package/strategies/package_mapping_discovery_first.py +100 -0
- exonware/xwlazy/package/strategies/package_mapping_hybrid.py +105 -0
- exonware/xwlazy/package/strategies/package_mapping_manifest_first.py +100 -0
- exonware/xwlazy/package/strategies/package_policy_allow_list.py +57 -0
- exonware/xwlazy/package/strategies/package_policy_deny_list.py +57 -0
- exonware/xwlazy/package/strategies/package_policy_permissive.py +46 -0
- exonware/xwlazy/package/strategies/package_timing_clean.py +67 -0
- exonware/xwlazy/package/strategies/package_timing_full.py +66 -0
- exonware/xwlazy/package/strategies/package_timing_smart.py +68 -0
- exonware/xwlazy/package/strategies/package_timing_temporary.py +66 -0
- exonware/xwlazy/runtime/__init__.py +18 -0
- exonware/xwlazy/runtime/adaptive_learner.py +129 -0
- exonware/xwlazy/runtime/base.py +274 -0
- exonware/xwlazy/runtime/facade.py +94 -0
- exonware/xwlazy/runtime/intelligent_selector.py +170 -0
- exonware/xwlazy/runtime/metrics.py +60 -0
- exonware/xwlazy/runtime/performance.py +37 -0
- exonware/xwlazy/version.py +2 -2
- {exonware_xwlazy-0.1.0.11.dist-info → exonware_xwlazy-0.1.0.20.dist-info}/METADATA +89 -11
- exonware_xwlazy-0.1.0.20.dist-info/RECORD +87 -0
- exonware_xwlazy-0.1.0.11.dist-info/RECORD +0 -20
- xwlazy/__init__.py +0 -34
- xwlazy/lazy/__init__.py +0 -301
- xwlazy/lazy/bootstrap.py +0 -106
- xwlazy/lazy/lazy_base.py +0 -465
- xwlazy/lazy/lazy_contracts.py +0 -290
- xwlazy/lazy/lazy_core.py +0 -3727
- xwlazy/lazy/logging_utils.py +0 -194
- xwlazy/version.py +0 -77
- {exonware_xwlazy-0.1.0.11.dist-info → exonware_xwlazy-0.1.0.20.dist-info}/WHEEL +0 -0
- {exonware_xwlazy-0.1.0.11.dist-info → exonware_xwlazy-0.1.0.20.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module Strategies - Helper and Manager implementations.
|
|
3
|
+
|
|
4
|
+
Company: eXonware.com
|
|
5
|
+
Author: Eng. Muhammad AlShehri
|
|
6
|
+
Email: connect@exonware.com
|
|
7
|
+
|
|
8
|
+
Generation Date: 15-Nov-2025
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .module_helper_simple import SimpleHelper
|
|
12
|
+
from .module_helper_lazy import LazyHelper
|
|
13
|
+
from .module_manager_simple import SimpleManager
|
|
14
|
+
from .module_manager_advanced import AdvancedManager
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
'SimpleHelper',
|
|
18
|
+
'LazyHelper',
|
|
19
|
+
'SimpleManager',
|
|
20
|
+
'AdvancedManager',
|
|
21
|
+
]
|
|
22
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lazy Module Helper Strategy - Deferred loading.
|
|
3
|
+
|
|
4
|
+
Company: eXonware.com
|
|
5
|
+
Author: Eng. Muhammad AlShehri
|
|
6
|
+
Email: connect@exonware.com
|
|
7
|
+
|
|
8
|
+
Generation Date: 15-Nov-2025
|
|
9
|
+
|
|
10
|
+
Lazy loading - loads module on first access with caching.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import importlib
|
|
14
|
+
import importlib.util
|
|
15
|
+
import threading
|
|
16
|
+
from types import ModuleType
|
|
17
|
+
from typing import Any, Optional, Dict
|
|
18
|
+
from ...module.base import AModuleHelperStrategy
|
|
19
|
+
from ..data import ModuleData
|
|
20
|
+
|
|
21
|
+
class LazyHelper(AModuleHelperStrategy):
|
|
22
|
+
"""
|
|
23
|
+
Lazy helper - deferred loading with caching.
|
|
24
|
+
|
|
25
|
+
Loads module on first access and caches it.
|
|
26
|
+
Thread-safe with circular import detection.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
"""Initialize lazy helper."""
|
|
31
|
+
self._cache: Dict[str, ModuleType] = {}
|
|
32
|
+
self._loading: Dict[str, bool] = {}
|
|
33
|
+
self._lock = threading.RLock()
|
|
34
|
+
|
|
35
|
+
def load(self, module_path: str, package_helper: Any) -> ModuleType:
|
|
36
|
+
"""
|
|
37
|
+
Load the module lazily (with caching).
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
module_path: Module path to load
|
|
41
|
+
package_helper: Package helper (unused)
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Loaded module
|
|
45
|
+
"""
|
|
46
|
+
# Check cache first
|
|
47
|
+
if module_path in self._cache:
|
|
48
|
+
return self._cache[module_path]
|
|
49
|
+
|
|
50
|
+
with self._lock:
|
|
51
|
+
# Double-check after acquiring lock
|
|
52
|
+
if module_path in self._cache:
|
|
53
|
+
return self._cache[module_path]
|
|
54
|
+
|
|
55
|
+
# Check for circular import
|
|
56
|
+
if self._loading.get(module_path, False):
|
|
57
|
+
raise ImportError(f"Circular import detected for {module_path}")
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
self._loading[module_path] = True
|
|
61
|
+
module = importlib.import_module(module_path)
|
|
62
|
+
self._cache[module_path] = module
|
|
63
|
+
return module
|
|
64
|
+
finally:
|
|
65
|
+
self._loading[module_path] = False
|
|
66
|
+
|
|
67
|
+
def unload(self, module_path: str) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Unload the module from cache.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
module_path: Module path to unload
|
|
73
|
+
"""
|
|
74
|
+
with self._lock:
|
|
75
|
+
self._cache.pop(module_path, None)
|
|
76
|
+
self._loading.pop(module_path, None)
|
|
77
|
+
|
|
78
|
+
def check_importability(self, path: str) -> bool:
|
|
79
|
+
"""
|
|
80
|
+
Check if module is importable.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
path: Module path to check
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
True if importable, False otherwise
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
spec = importlib.util.find_spec(path)
|
|
90
|
+
return spec is not None
|
|
91
|
+
except (ValueError, AttributeError, ImportError):
|
|
92
|
+
return False
|
|
93
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simple Module Helper Strategy - Basic synchronous loading.
|
|
3
|
+
|
|
4
|
+
Company: eXonware.com
|
|
5
|
+
Author: Eng. Muhammad AlShehri
|
|
6
|
+
Email: connect@exonware.com
|
|
7
|
+
|
|
8
|
+
Generation Date: 15-Nov-2025
|
|
9
|
+
|
|
10
|
+
Simple synchronous module loading - no lazy loading.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import importlib
|
|
14
|
+
from types import ModuleType
|
|
15
|
+
from typing import Any
|
|
16
|
+
from ...module.base import AModuleHelperStrategy
|
|
17
|
+
|
|
18
|
+
class SimpleHelper(AModuleHelperStrategy):
|
|
19
|
+
"""
|
|
20
|
+
Simple helper - standard synchronous import.
|
|
21
|
+
|
|
22
|
+
No lazy loading, no caching, just direct importlib.import_module.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def load(self, module_path: str, package_helper: Any) -> ModuleType:
|
|
26
|
+
"""
|
|
27
|
+
Load the module synchronously.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
module_path: Module path to load
|
|
31
|
+
package_helper: Package helper (unused in simple mode)
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Loaded module
|
|
35
|
+
"""
|
|
36
|
+
return importlib.import_module(module_path)
|
|
37
|
+
|
|
38
|
+
def unload(self, module_path: str) -> None:
|
|
39
|
+
"""
|
|
40
|
+
Unload the module.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
module_path: Module path to unload
|
|
44
|
+
"""
|
|
45
|
+
# Simple mode doesn't track loaded modules
|
|
46
|
+
# Could remove from sys.modules if needed
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
def check_importability(self, path: str) -> bool:
|
|
50
|
+
"""
|
|
51
|
+
Check if module is importable.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
path: Module path to check
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
True if importable, False otherwise
|
|
58
|
+
"""
|
|
59
|
+
import importlib.util
|
|
60
|
+
try:
|
|
61
|
+
spec = importlib.util.find_spec(path)
|
|
62
|
+
return spec is not None
|
|
63
|
+
except (ValueError, AttributeError, ImportError):
|
|
64
|
+
return False
|
|
65
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Advanced Module Manager Strategy - Full features.
|
|
3
|
+
|
|
4
|
+
Company: eXonware.com
|
|
5
|
+
Author: Eng. Muhammad AlShehri
|
|
6
|
+
Email: connect@exonware.com
|
|
7
|
+
|
|
8
|
+
Generation Date: 15-Nov-2025
|
|
9
|
+
|
|
10
|
+
Advanced manager - with hooks, error handling, and full features.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
from types import ModuleType
|
|
15
|
+
from typing import Optional
|
|
16
|
+
from ...module.base import AModuleManagerStrategy
|
|
17
|
+
from ...contracts import ICachingStrategy, IModuleHelperStrategy
|
|
18
|
+
from ...package.base import APackageHelper
|
|
19
|
+
from ...module import importer_engine
|
|
20
|
+
|
|
21
|
+
class AdvancedManager(AModuleManagerStrategy):
|
|
22
|
+
"""
|
|
23
|
+
Advanced manager - full features with hooks and error handling.
|
|
24
|
+
|
|
25
|
+
Supports import hooks, error recovery, and all advanced features.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
package_name: str,
|
|
31
|
+
package_helper: APackageHelper,
|
|
32
|
+
caching: ICachingStrategy,
|
|
33
|
+
helper: IModuleHelperStrategy
|
|
34
|
+
):
|
|
35
|
+
"""
|
|
36
|
+
Initialize advanced manager.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
package_name: Package name for isolation
|
|
40
|
+
package_helper: Package helper instance
|
|
41
|
+
caching: Caching strategy
|
|
42
|
+
helper: Helper strategy
|
|
43
|
+
"""
|
|
44
|
+
self._package_name = package_name
|
|
45
|
+
self._package_helper = package_helper
|
|
46
|
+
self._caching = caching
|
|
47
|
+
self._helper = helper
|
|
48
|
+
self._import_hook: Optional[importer_engine.LazyImportHook] = None
|
|
49
|
+
|
|
50
|
+
def load_module(self, module_path: str) -> ModuleType:
|
|
51
|
+
"""
|
|
52
|
+
Load a module.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
module_path: Module path to load
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Loaded module
|
|
59
|
+
"""
|
|
60
|
+
# Check cache first
|
|
61
|
+
cached = self._caching.get(module_path)
|
|
62
|
+
if cached is not None:
|
|
63
|
+
return cached
|
|
64
|
+
|
|
65
|
+
# Load using helper
|
|
66
|
+
module = self._helper.load(module_path, self._package_helper)
|
|
67
|
+
|
|
68
|
+
# Cache it
|
|
69
|
+
self._caching.set(module_path, module)
|
|
70
|
+
|
|
71
|
+
return module
|
|
72
|
+
|
|
73
|
+
def unload_module(self, module_path: str) -> None:
|
|
74
|
+
"""
|
|
75
|
+
Unload a module.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
module_path: Module path to unload
|
|
79
|
+
"""
|
|
80
|
+
self._helper.unload(module_path)
|
|
81
|
+
self._caching.invalidate(module_path)
|
|
82
|
+
|
|
83
|
+
# Also remove from sys.modules if present
|
|
84
|
+
if module_path in sys.modules:
|
|
85
|
+
del sys.modules[module_path]
|
|
86
|
+
|
|
87
|
+
def install_hook(self) -> None:
|
|
88
|
+
"""Install import hook into sys.meta_path."""
|
|
89
|
+
importer_engine.install_import_hook(self._package_name)
|
|
90
|
+
|
|
91
|
+
def uninstall_hook(self) -> None:
|
|
92
|
+
"""Uninstall import hook from sys.meta_path."""
|
|
93
|
+
importer_engine.uninstall_import_hook(self._package_name)
|
|
94
|
+
|
|
95
|
+
def handle_import_error(self, module_name: str) -> Optional[ModuleType]:
|
|
96
|
+
"""
|
|
97
|
+
Handle ImportError by attempting to install and re-import.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
module_name: Name of module that failed to import
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Imported module if successful, None otherwise
|
|
104
|
+
"""
|
|
105
|
+
if self._import_hook is None:
|
|
106
|
+
self._import_hook = importer_engine.LazyImportHook(
|
|
107
|
+
self._package_name,
|
|
108
|
+
self._package_helper
|
|
109
|
+
)
|
|
110
|
+
return self._import_hook.handle_import_error(module_name)
|
|
111
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simple Module Manager Strategy - Basic operations.
|
|
3
|
+
|
|
4
|
+
Company: eXonware.com
|
|
5
|
+
Author: Eng. Muhammad AlShehri
|
|
6
|
+
Email: connect@exonware.com
|
|
7
|
+
|
|
8
|
+
Generation Date: 15-Nov-2025
|
|
9
|
+
|
|
10
|
+
Simple manager - basic module loading/unloading only.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from types import ModuleType
|
|
14
|
+
from typing import Optional
|
|
15
|
+
from ...module.base import AModuleManagerStrategy
|
|
16
|
+
from ...contracts import ICachingStrategy, IModuleHelperStrategy
|
|
17
|
+
|
|
18
|
+
class SimpleManager(AModuleManagerStrategy):
|
|
19
|
+
"""
|
|
20
|
+
Simple manager - basic module operations only.
|
|
21
|
+
|
|
22
|
+
No hooks, no error handling, just load/unload.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
package_name: str,
|
|
28
|
+
caching: ICachingStrategy,
|
|
29
|
+
helper: IModuleHelperStrategy
|
|
30
|
+
):
|
|
31
|
+
"""
|
|
32
|
+
Initialize simple manager.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
package_name: Package name for isolation
|
|
36
|
+
caching: Caching strategy
|
|
37
|
+
helper: Helper strategy
|
|
38
|
+
"""
|
|
39
|
+
self._package_name = package_name
|
|
40
|
+
self._caching = caching
|
|
41
|
+
self._helper = helper
|
|
42
|
+
|
|
43
|
+
def load_module(self, module_path: str) -> ModuleType:
|
|
44
|
+
"""
|
|
45
|
+
Load a module.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
module_path: Module path to load
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Loaded module
|
|
52
|
+
"""
|
|
53
|
+
# Check cache first
|
|
54
|
+
cached = self._caching.get(module_path)
|
|
55
|
+
if cached is not None:
|
|
56
|
+
return cached
|
|
57
|
+
|
|
58
|
+
# Load using helper
|
|
59
|
+
module = self._helper.load(module_path, None)
|
|
60
|
+
|
|
61
|
+
# Cache it
|
|
62
|
+
self._caching.set(module_path, module)
|
|
63
|
+
|
|
64
|
+
return module
|
|
65
|
+
|
|
66
|
+
def unload_module(self, module_path: str) -> None:
|
|
67
|
+
"""
|
|
68
|
+
Unload a module.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
module_path: Module path to unload
|
|
72
|
+
"""
|
|
73
|
+
self._helper.unload(module_path)
|
|
74
|
+
self._caching.invalidate(module_path)
|
|
75
|
+
|
|
76
|
+
def install_hook(self) -> None:
|
|
77
|
+
"""Install import hook (not supported in simple mode)."""
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
def uninstall_hook(self) -> None:
|
|
81
|
+
"""Uninstall import hook (not supported in simple mode)."""
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
def handle_import_error(self, module_name: str) -> Optional[ModuleType]:
|
|
85
|
+
"""
|
|
86
|
+
Handle import error (not supported in simple mode).
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
module_name: Module name that failed
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
None (simple mode doesn't handle errors)
|
|
93
|
+
"""
|
|
94
|
+
return None
|
|
95
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Package Operations Module
|
|
3
|
+
|
|
4
|
+
This module provides concrete implementations for package operations.
|
|
5
|
+
Main facade: XWPackageHelper extends APackageHelper
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Lazy imports to avoid circular dependencies
|
|
9
|
+
def __getattr__(name: str):
|
|
10
|
+
if name == 'XWPackageHelper':
|
|
11
|
+
from .facade import XWPackageHelper
|
|
12
|
+
return XWPackageHelper
|
|
13
|
+
if name == 'XWPackage': # Backward compatibility alias
|
|
14
|
+
from .facade import XWPackageHelper
|
|
15
|
+
return XWPackageHelper
|
|
16
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
17
|
+
|
|
18
|
+
__all__ = ['XWPackageHelper', 'XWPackage'] # XWPackage is backward compatibility alias
|