exonware-xwlazy 0.1.0.23__py3-none-any.whl → 1.0.1.2__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.
Files changed (96) hide show
  1. exonware/__init__.py +85 -34
  2. exonware/xwlazy/version.py +5 -5
  3. exonware/xwlazy.py +2546 -0
  4. exonware/xwlazy_external_libs.toml +716 -0
  5. {exonware_xwlazy-0.1.0.23.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/METADATA +5 -1
  6. exonware_xwlazy-1.0.1.2.dist-info/RECORD +8 -0
  7. exonware/xwlazy/__init__.py +0 -379
  8. exonware/xwlazy/common/__init__.py +0 -55
  9. exonware/xwlazy/common/base.py +0 -65
  10. exonware/xwlazy/common/cache.py +0 -504
  11. exonware/xwlazy/common/logger.py +0 -257
  12. exonware/xwlazy/common/services/__init__.py +0 -72
  13. exonware/xwlazy/common/services/dependency_mapper.py +0 -250
  14. exonware/xwlazy/common/services/install_async_utils.py +0 -170
  15. exonware/xwlazy/common/services/install_cache_utils.py +0 -245
  16. exonware/xwlazy/common/services/keyword_detection.py +0 -283
  17. exonware/xwlazy/common/services/spec_cache.py +0 -165
  18. exonware/xwlazy/common/services/state_manager.py +0 -84
  19. exonware/xwlazy/common/strategies/__init__.py +0 -28
  20. exonware/xwlazy/common/strategies/caching_dict.py +0 -44
  21. exonware/xwlazy/common/strategies/caching_installation.py +0 -88
  22. exonware/xwlazy/common/strategies/caching_lfu.py +0 -66
  23. exonware/xwlazy/common/strategies/caching_lru.py +0 -63
  24. exonware/xwlazy/common/strategies/caching_multitier.py +0 -59
  25. exonware/xwlazy/common/strategies/caching_ttl.py +0 -59
  26. exonware/xwlazy/common/utils.py +0 -142
  27. exonware/xwlazy/config.py +0 -193
  28. exonware/xwlazy/contracts.py +0 -1533
  29. exonware/xwlazy/defs.py +0 -378
  30. exonware/xwlazy/errors.py +0 -276
  31. exonware/xwlazy/facade.py +0 -1137
  32. exonware/xwlazy/host/__init__.py +0 -8
  33. exonware/xwlazy/host/conf.py +0 -16
  34. exonware/xwlazy/module/__init__.py +0 -18
  35. exonware/xwlazy/module/base.py +0 -622
  36. exonware/xwlazy/module/data.py +0 -17
  37. exonware/xwlazy/module/facade.py +0 -246
  38. exonware/xwlazy/module/importer_engine.py +0 -2964
  39. exonware/xwlazy/module/partial_module_detector.py +0 -275
  40. exonware/xwlazy/module/strategies/__init__.py +0 -22
  41. exonware/xwlazy/module/strategies/module_helper_lazy.py +0 -93
  42. exonware/xwlazy/module/strategies/module_helper_simple.py +0 -65
  43. exonware/xwlazy/module/strategies/module_manager_advanced.py +0 -111
  44. exonware/xwlazy/module/strategies/module_manager_simple.py +0 -95
  45. exonware/xwlazy/package/__init__.py +0 -18
  46. exonware/xwlazy/package/base.py +0 -863
  47. exonware/xwlazy/package/conf.py +0 -324
  48. exonware/xwlazy/package/data.py +0 -17
  49. exonware/xwlazy/package/facade.py +0 -480
  50. exonware/xwlazy/package/services/__init__.py +0 -84
  51. exonware/xwlazy/package/services/async_install_handle.py +0 -87
  52. exonware/xwlazy/package/services/config_manager.py +0 -249
  53. exonware/xwlazy/package/services/discovery.py +0 -435
  54. exonware/xwlazy/package/services/host_packages.py +0 -180
  55. exonware/xwlazy/package/services/install_async.py +0 -291
  56. exonware/xwlazy/package/services/install_cache.py +0 -145
  57. exonware/xwlazy/package/services/install_interactive.py +0 -59
  58. exonware/xwlazy/package/services/install_policy.py +0 -156
  59. exonware/xwlazy/package/services/install_registry.py +0 -54
  60. exonware/xwlazy/package/services/install_result.py +0 -17
  61. exonware/xwlazy/package/services/install_sbom.py +0 -153
  62. exonware/xwlazy/package/services/install_utils.py +0 -79
  63. exonware/xwlazy/package/services/installer_engine.py +0 -406
  64. exonware/xwlazy/package/services/lazy_installer.py +0 -803
  65. exonware/xwlazy/package/services/manifest.py +0 -503
  66. exonware/xwlazy/package/services/strategy_registry.py +0 -324
  67. exonware/xwlazy/package/strategies/__init__.py +0 -57
  68. exonware/xwlazy/package/strategies/package_discovery_file.py +0 -129
  69. exonware/xwlazy/package/strategies/package_discovery_hybrid.py +0 -84
  70. exonware/xwlazy/package/strategies/package_discovery_manifest.py +0 -101
  71. exonware/xwlazy/package/strategies/package_execution_async.py +0 -113
  72. exonware/xwlazy/package/strategies/package_execution_cached.py +0 -90
  73. exonware/xwlazy/package/strategies/package_execution_pip.py +0 -99
  74. exonware/xwlazy/package/strategies/package_execution_wheel.py +0 -106
  75. exonware/xwlazy/package/strategies/package_mapping_discovery_first.py +0 -100
  76. exonware/xwlazy/package/strategies/package_mapping_hybrid.py +0 -105
  77. exonware/xwlazy/package/strategies/package_mapping_manifest_first.py +0 -100
  78. exonware/xwlazy/package/strategies/package_policy_allow_list.py +0 -57
  79. exonware/xwlazy/package/strategies/package_policy_deny_list.py +0 -57
  80. exonware/xwlazy/package/strategies/package_policy_permissive.py +0 -46
  81. exonware/xwlazy/package/strategies/package_timing_clean.py +0 -67
  82. exonware/xwlazy/package/strategies/package_timing_full.py +0 -66
  83. exonware/xwlazy/package/strategies/package_timing_smart.py +0 -68
  84. exonware/xwlazy/package/strategies/package_timing_temporary.py +0 -66
  85. exonware/xwlazy/runtime/__init__.py +0 -18
  86. exonware/xwlazy/runtime/adaptive_learner.py +0 -129
  87. exonware/xwlazy/runtime/base.py +0 -274
  88. exonware/xwlazy/runtime/facade.py +0 -94
  89. exonware/xwlazy/runtime/intelligent_selector.py +0 -170
  90. exonware/xwlazy/runtime/metrics.py +0 -60
  91. exonware/xwlazy/runtime/performance.py +0 -37
  92. exonware_xwlazy-0.1.0.23.dist-info/RECORD +0 -93
  93. xwlazy/__init__.py +0 -14
  94. xwlazy/lazy.py +0 -30
  95. {exonware_xwlazy-0.1.0.23.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/WHEEL +0 -0
  96. {exonware_xwlazy-0.1.0.23.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,275 +0,0 @@
1
- """
2
- Partial Module Detection Strategies
3
-
4
- Detects if a module in sys.modules is partially initialized (still being imported).
5
- This prevents returning partially initialized modules that cause ImportErrors.
6
-
7
- Company: eXonware.com
8
- Author: Eng. Muhammad AlShehri
9
- Email: connect@exonware.com
10
-
11
- Generation Date: 27-Dec-2025
12
- """
13
-
14
- import sys
15
- import threading
16
- from types import ModuleType
17
- from typing import Optional
18
- from enum import Enum
19
-
20
- class DetectionStrategy(Enum):
21
- """Different strategies for detecting partially initialized modules."""
22
- FRAME_STACK = "frame_stack" # Check call stack for import functions
23
- ATTRIBUTE_CHECK = "attribute_check" # Check if expected attributes exist
24
- IMPORT_LOCK = "import_lock" # Use importlib's import lock state
25
- MODULE_STATE = "module_state" # Check module's __spec__ and loader state
26
- HYBRID = "hybrid" # Combine multiple strategies
27
-
28
- # Track modules currently being imported (thread-safe)
29
- _importing_modules: set[str] = set()
30
- _import_lock = threading.RLock()
31
-
32
- def mark_module_importing(module_name: str) -> None:
33
- """Mark a module as currently being imported."""
34
- with _import_lock:
35
- _importing_modules.add(module_name)
36
-
37
- def unmark_module_importing(module_name: str) -> None:
38
- """Unmark a module as no longer being imported."""
39
- with _import_lock:
40
- _importing_modules.discard(module_name)
41
-
42
- def is_module_importing(module_name: str) -> bool:
43
- """Check if a module is currently being imported."""
44
- with _import_lock:
45
- return module_name in _importing_modules
46
-
47
- class PartialModuleDetector:
48
- """
49
- Modular detector for partially initialized modules.
50
-
51
- Uses different strategies to detect if a module in sys.modules
52
- is still being initialized and shouldn't be returned yet.
53
- """
54
-
55
- def __init__(self, strategy: DetectionStrategy = DetectionStrategy.HYBRID):
56
- self.strategy = strategy
57
-
58
- def is_partially_initialized(self, module_name: str, module: ModuleType) -> bool:
59
- """
60
- Check if module is partially initialized (still being imported).
61
-
62
- Args:
63
- module_name: Name of the module
64
- module: Module object from sys.modules
65
-
66
- Returns:
67
- True if module is partially initialized, False if fully loaded
68
- """
69
- if self.strategy == DetectionStrategy.FRAME_STACK:
70
- return self._check_frame_stack(module_name)
71
- elif self.strategy == DetectionStrategy.ATTRIBUTE_CHECK:
72
- return self._check_attributes(module_name, module)
73
- elif self.strategy == DetectionStrategy.IMPORT_LOCK:
74
- return self._check_import_lock(module_name)
75
- elif self.strategy == DetectionStrategy.MODULE_STATE:
76
- return self._check_module_state(module_name, module)
77
- elif self.strategy == DetectionStrategy.HYBRID:
78
- return self._check_hybrid(module_name, module)
79
- else:
80
- return False
81
-
82
- def _check_frame_stack(self, module_name: str) -> bool:
83
- """
84
- Strategy 1: Check call stack for import-related functions.
85
-
86
- If we're in _find_and_load, _load_unlocked, or exec_module,
87
- the module is likely still being imported.
88
-
89
- CRITICAL: This checks if the CURRENT import call is for this module,
90
- not just if we're in an import function.
91
- """
92
- try:
93
- # Start from frame 2 (skip our own function and the caller)
94
- frame = sys._getframe(2)
95
- depth = 0
96
- max_depth = 30 # Increased depth to catch deeper import chains
97
-
98
- while frame and depth < max_depth:
99
- code = frame.f_code
100
- func_name = code.co_name
101
-
102
- # Check for import-related functions in Python's importlib
103
- import_keywords = [
104
- '_find_and_load', '_load_unlocked', 'exec_module',
105
- '_call_with_frames_removed', '_load_module_spec',
106
- '_intercepting_import', '__import__'
107
- ]
108
-
109
- if any(keyword in func_name for keyword in import_keywords):
110
- # Check if this module is in the frame's locals or globals
111
- if hasattr(frame, 'f_locals'):
112
- locals_dict = frame.f_locals
113
- # Check various ways module name might appear
114
- frame_module_name = (
115
- locals_dict.get('name') or
116
- locals_dict.get('fullname') or
117
- locals_dict.get('__name__') or
118
- (locals_dict.get('module') and getattr(locals_dict.get('module'), '__name__', None))
119
- )
120
-
121
- if frame_module_name == module_name:
122
- return True
123
-
124
- # Also check globals
125
- if hasattr(frame, 'f_globals'):
126
- globals_dict = frame.f_globals
127
- if '__name__' in globals_dict and globals_dict.get('__name__') == module_name:
128
- return True
129
-
130
- frame = frame.f_back
131
- depth += 1
132
- except (AttributeError, ValueError):
133
- # Frame inspection failed, assume not importing
134
- pass
135
-
136
- return False
137
-
138
- def _check_attributes(self, module_name: str, module: ModuleType) -> bool:
139
- """
140
- Strategy 2: Check if module has expected attributes.
141
-
142
- A fully initialized module should have certain attributes.
143
- If key attributes are missing, it might be partially initialized.
144
-
145
- CRITICAL: We need to be careful - some modules legitimately don't have
146
- __file__ (namespace packages, built-ins). We only flag as partial if
147
- we're CERTAIN it's not fully initialized.
148
- """
149
- module_dict = getattr(module, '__dict__', {})
150
-
151
- # Check for placeholder patterns (lazy loaders often add __getattr__)
152
- if hasattr(module, '__getattr__'):
153
- # If it has __getattr__ but very few attributes, it's likely a placeholder
154
- if len(module_dict) <= 5: # Only __name__, __loader__, __spec__, __getattr__, etc.
155
- if not hasattr(module, '__file__') and not hasattr(module, '__path__'):
156
- # Not a namespace package and no file - likely placeholder
157
- return True
158
-
159
- # Check if module has __spec__ but loader hasn't executed yet
160
- if hasattr(module, '__spec__') and module.__spec__ is not None:
161
- spec = module.__spec__
162
- # If loader exists but module dict is very small, it might not be fully loaded
163
- if hasattr(spec, 'loader') and spec.loader is not None:
164
- # Check if module dict is suspiciously small (only metadata, no actual content)
165
- if len(module_dict) <= 3:
166
- # Only has __name__, __loader__, __spec__ - likely not executed
167
- if not hasattr(module, '__file__') and not hasattr(module, '__path__'):
168
- # Not a namespace package - likely partial
169
- return True
170
-
171
- # If module is in sys.modules but has no meaningful content, it's likely partial
172
- # This is a heuristic - be conservative
173
- if module_name in sys.modules:
174
- # Check if module has been executed by looking for non-metadata attributes
175
- metadata_attrs = {'__name__', '__loader__', '__spec__', '__package__', '__file__', '__path__', '__cached__'}
176
- content_attrs = set(module_dict.keys()) - metadata_attrs
177
- if len(content_attrs) == 0 and len(module_dict) > 0:
178
- # Has metadata but no content - might be partial
179
- # But be conservative - only flag if we're sure
180
- if hasattr(module, '__loader__') and module.__loader__ is not None:
181
- # Has loader but no content - likely partial
182
- return True
183
-
184
- return False
185
-
186
- def _check_import_lock(self, module_name: str) -> bool:
187
- """
188
- Strategy 3: Use our own import tracking.
189
-
190
- Check if module is marked as currently being imported.
191
- """
192
- return is_module_importing(module_name)
193
-
194
- def _check_module_state(self, module_name: str, module: ModuleType) -> bool:
195
- """
196
- Strategy 4: Check module's internal state.
197
-
198
- Look at __spec__, __loader__, and other state indicators.
199
- """
200
- # If module doesn't have __spec__, it's likely not fully initialized
201
- if not hasattr(module, '__spec__') or module.__spec__ is None:
202
- # Exception: Some built-in modules don't have __spec__
203
- if module_name not in sys.builtin_module_names:
204
- return True
205
-
206
- # Check if module has __loader__ but loader hasn't executed
207
- if hasattr(module, '__loader__') and module.__loader__ is not None:
208
- loader = module.__loader__
209
- # If loader has exec_module but module doesn't have expected attributes,
210
- # it might not be fully executed
211
- if hasattr(loader, 'exec_module'):
212
- # Check if module has been executed by looking for common attributes
213
- # This is heuristic - modules should have some content after execution
214
- module_dict = getattr(module, '__dict__', {})
215
- # If dict is mostly empty (only has __name__, __loader__, __spec__),
216
- # it might not be fully initialized
217
- if len(module_dict) <= 3:
218
- # Check if it's a legitimate empty module
219
- if '__file__' not in module_dict and '__path__' not in module_dict:
220
- return True
221
-
222
- return False
223
-
224
- def _check_hybrid(self, module_name: str, module: ModuleType) -> bool:
225
- """
226
- Strategy 5: Hybrid - combine multiple strategies.
227
-
228
- Returns True if ANY strategy indicates partial initialization.
229
- This is the most conservative approach.
230
-
231
- NOTE: We check frame stack FIRST because it's most accurate for detecting
232
- modules currently being imported. Import lock is secondary.
233
- """
234
- # Check frame stack first (most accurate for detecting active imports)
235
- if self._check_frame_stack(module_name):
236
- return True
237
-
238
- # Check attributes (fast, reliable)
239
- if self._check_attributes(module_name, module):
240
- return True
241
-
242
- # Check module state (medium speed)
243
- if self._check_module_state(module_name, module):
244
- return True
245
-
246
- # Check import lock last (may have false positives)
247
- # Only use if other checks are inconclusive
248
- if is_module_importing(module_name):
249
- # Double-check with frame stack to avoid false positives
250
- if self._check_frame_stack(module_name):
251
- return True
252
-
253
- return False
254
-
255
- # Global detector instance (defaults to HYBRID strategy)
256
- _default_detector = PartialModuleDetector(DetectionStrategy.HYBRID)
257
-
258
- def is_partially_initialized(module_name: str, module: ModuleType,
259
- strategy: Optional[DetectionStrategy] = None) -> bool:
260
- """
261
- Convenience function to check if module is partially initialized.
262
-
263
- Args:
264
- module_name: Name of the module
265
- module: Module object from sys.modules
266
- strategy: Optional strategy override
267
-
268
- Returns:
269
- True if module is partially initialized
270
- """
271
- if strategy:
272
- detector = PartialModuleDetector(strategy)
273
- return detector.is_partially_initialized(module_name, module)
274
- return _default_detector.is_partially_initialized(module_name, module)
275
-
@@ -1,22 +0,0 @@
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
-
@@ -1,93 +0,0 @@
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
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
-
@@ -1,65 +0,0 @@
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
-
@@ -1,111 +0,0 @@
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
-
@@ -1,95 +0,0 @@
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
-
@@ -1,18 +0,0 @@
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