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
exonware/xwlazy/facade.py DELETED
@@ -1,1137 +0,0 @@
1
- """
2
- #exonware/xwlazy/src/exonware/xwlazy/facade.py
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 10-Oct-2025
9
-
10
- Facade for Lazy Loading System
11
-
12
- This module provides a unified public API facade for the lazy loading system
13
- following GUIDE_ARCH.md structure. It consolidates all public APIs into a
14
- single entry point.
15
-
16
- Design Pattern: Facade Pattern
17
- - Provides simplified interface to complex subsystem
18
- - Hides implementation details
19
- - Centralizes public API
20
- """
21
-
22
- import os
23
- import sys
24
- import subprocess
25
- import importlib
26
- import importlib.util
27
- from typing import Optional, Any
28
- from types import ModuleType
29
-
30
- # Import from contracts for types
31
- from .defs import LazyInstallMode, LazyLoadMode, LazyModeConfig
32
- from .defs import PRESET_MODES, get_preset_mode
33
-
34
- # Import from new structure modules
35
- from .package.services.config_manager import LazyInstallConfig
36
- from .common.services import LazyStateManager
37
- from .runtime.metrics import MetricsCollector, get_metrics_collector
38
- from .runtime.performance import LazyPerformanceMonitor
39
- from .package.services.manifest import get_manifest_loader, refresh_manifest_cache
40
- from .common.logger import get_logger, log_event as _log
41
- # Import directly from submodule bases
42
- from .package.base import APackageHelper
43
- from .module.base import AModuleHelper
44
- from .runtime.base import ARuntimeHelper
45
- # Import concrete implementations from new folder structure
46
- from .package import XWPackageHelper
47
- from .module import XWModuleHelper
48
- from .runtime import XWRuntimeHelper
49
-
50
- # Import from domain modules
51
- from .package.services.discovery import get_lazy_discovery as _get_lazy_discovery
52
- from .common.services.dependency_mapper import DependencyMapper
53
- from .common.services import (
54
- enable_keyword_detection as _enable_keyword_detection,
55
- is_keyword_detection_enabled as _is_keyword_detection_enabled,
56
- get_keyword_detection_keyword as _get_keyword_detection_keyword,
57
- check_package_keywords as _check_package_keywords,
58
- _detect_lazy_installation,
59
- _detect_meta_info_mode,
60
- )
61
- from .package.services import (
62
- LazyInstallerRegistry,
63
- LazyInstaller,
64
- LazyInstallPolicy,
65
- is_externally_managed as _is_externally_managed,
66
- )
67
- from .common.cache import InstallationCache
68
- from .module.importer_engine import (
69
- install_import_hook as _install_import_hook,
70
- uninstall_import_hook as _uninstall_import_hook,
71
- is_import_hook_installed as _is_import_hook_installed,
72
- register_lazy_module_prefix as _register_lazy_module_prefix,
73
- register_lazy_module_methods as _register_lazy_module_methods,
74
- register_lazy_package as _register_lazy_package,
75
- install_global_import_hook as _install_global_import_hook,
76
- is_global_import_hook_installed as _is_global_import_hook_installed,
77
- LazyImporter,
78
- LazyModuleRegistry,
79
- )
80
-
81
- logger = get_logger("xwlazy.facade")
82
-
83
- # Global instances
84
- _lazy_importer = LazyImporter()
85
- _lazy_module_registry = LazyModuleRegistry()
86
-
87
- # =============================================================================
88
- # FACADE CLASS
89
- # =============================================================================
90
-
91
- class LazyModeFacade:
92
- """
93
- Facade class for managing lazy mode configuration and operations.
94
-
95
- This class provides a unified interface to all lazy loading functionality.
96
- """
97
-
98
- def __init__(self):
99
- self._enabled = False
100
- self._strategy = "on_demand"
101
- self._configs: dict[str, Any] = {}
102
-
103
- def enable(self, strategy: str = "on_demand", **kwargs) -> None:
104
- """Enable lazy mode with specified strategy."""
105
- self._enabled = True
106
- self._strategy = strategy
107
- self._configs.update(kwargs)
108
- logger.info(f"Lazy mode enabled with strategy: {strategy}")
109
-
110
- def disable(self) -> None:
111
- """Disable lazy mode and cleanup resources."""
112
- self._enabled = False
113
- logger.info("Lazy mode disabled")
114
-
115
- def is_enabled(self) -> bool:
116
- """Check if lazy mode is currently enabled."""
117
- return self._enabled
118
-
119
- def get_stats(self) -> dict[str, Any]:
120
- """Get lazy mode performance statistics."""
121
- return {
122
- "enabled": self._enabled,
123
- "strategy": self._strategy,
124
- "configs": self._configs.copy(),
125
- }
126
-
127
- # Global facade instance
128
- _lazy_facade = LazyModeFacade()
129
-
130
- # =============================================================================
131
- # FACADE FUNCTIONS
132
- # =============================================================================
133
-
134
- def enable_lazy_mode(strategy: str = "on_demand", **kwargs) -> None:
135
- """Enable lazy mode with specified strategy."""
136
- _lazy_facade.enable(strategy, **kwargs)
137
-
138
- def disable_lazy_mode() -> None:
139
- """Disable lazy mode and cleanup resources."""
140
- _lazy_facade.disable()
141
-
142
- def is_lazy_mode_enabled() -> bool:
143
- """Check if lazy mode is currently enabled."""
144
- return _lazy_facade.is_enabled()
145
-
146
- def get_lazy_mode_stats() -> dict[str, Any]:
147
- """Get lazy mode performance statistics."""
148
- return _lazy_facade.get_stats()
149
-
150
- def configure_lazy_mode(package_name: str, config: LazyModeConfig) -> None:
151
- """Configure lazy mode for a specific package."""
152
- # Use set() method with mode_config parameter
153
- LazyInstallConfig.set(package_name, True, mode_config=config)
154
- logger.info(f"Configured lazy mode for {package_name}")
155
-
156
- def preload_modules(package_name: str, modules: list[str]) -> None:
157
- """Preload specified modules for a package."""
158
- for module_name in modules:
159
- _lazy_importer.preload_module(module_name)
160
- logger.info(f"Preloaded {len(modules)} modules for {package_name}")
161
-
162
- def optimize_lazy_mode(package_name: str) -> None:
163
- """Optimize lazy mode configuration for a package."""
164
- _lazy_module_registry.preload_frequently_used()
165
- logger.info(f"Optimization completed for {package_name}")
166
-
167
- # =============================================================================
168
- # ONE-LINE ACTIVATION API
169
- # =============================================================================
170
-
171
- def auto_enable_lazy(package_name: Optional[str] = None, mode: str = "smart") -> bool:
172
- """
173
- Auto-enable lazy mode for a package - ONE LINE ACTIVATION!
174
-
175
- Usage in any library's __init__.py:
176
- from exonware.xwlazy import auto_enable_lazy
177
- auto_enable_lazy(__package__)
178
-
179
- Args:
180
- package_name: Package name (auto-detected if None)
181
- mode: Lazy mode ("smart", "lite", "full", "clean", "temporary")
182
-
183
- Returns:
184
- True if enabled, False otherwise
185
- """
186
- import inspect
187
-
188
- # Auto-detect package name from caller
189
- if package_name is None:
190
- try:
191
- frame = inspect.currentframe().f_back
192
- package_name = (frame.f_globals.get('__package__') or
193
- frame.f_globals.get('__name__', '').split('.')[0])
194
- except Exception:
195
- logger.warning("Could not auto-detect package name")
196
- return False
197
-
198
- if not package_name:
199
- logger.warning("Package name is required")
200
- return False
201
-
202
- try:
203
- # Get preset mode configuration
204
- config = get_preset_mode(mode)
205
- if config is None:
206
- logger.warning(f"Unknown mode: {mode}, using 'smart'")
207
- config = get_preset_mode("smart")
208
-
209
- # Register package for lazy loading/installation
210
- _register_lazy_package(package_name, config)
211
-
212
- # Enable lazy install for this package with mode config
213
- # Pass mode_config through set() method (not a separate set_mode_config method)
214
- LazyInstallConfig.set(
215
- package_name,
216
- True,
217
- mode=mode,
218
- mode_config=config
219
- )
220
-
221
- # Install global import hook if not already installed
222
- if not _is_global_import_hook_installed():
223
- _install_global_import_hook()
224
-
225
- # Also install meta_path hook for compatibility
226
- _install_import_hook(package_name)
227
-
228
- logger.info(f"✅ Auto-enabled lazy mode for package: {package_name} (mode: {mode})")
229
- return True
230
- except Exception as e:
231
- logger.error(f"Failed to auto-enable lazy mode for {package_name}: {e}")
232
- return False
233
-
234
- def attach(package_name: str, submodules: Optional[list[str]] = None, submod_attrs: Optional[dict[str, list[str]]] = None):
235
- """
236
- Attach lazily loaded submodules and attributes (lazy-loader compatible API).
237
-
238
- Returns (__getattr__, __dir__, __all__) for lazy loading.
239
-
240
- Usage:
241
- __getattr__, __dir__, __all__ = lazy.attach(__name__, ['submodule1'], {'module': ['attr1', 'attr2']})
242
-
243
- Args:
244
- package_name: Package name (typically __name__)
245
- submodules: List of submodule names to attach
246
- submod_attrs: Dict mapping submodule -> list of attributes/functions
247
-
248
- Returns:
249
- Tuple of (__getattr__, __dir__, __all__)
250
- """
251
- import importlib
252
-
253
- if submod_attrs is None:
254
- submod_attrs = {}
255
- if submodules is None:
256
- submodules = []
257
-
258
- submodules_set = set(submodules)
259
- attr_to_modules = {
260
- attr: mod for mod, attrs in submod_attrs.items() for attr in attrs
261
- }
262
-
263
- __all__ = sorted(submodules_set | attr_to_modules.keys())
264
-
265
- def __getattr__(name: str) -> Any:
266
- """Lazy load submodule or attribute on first access."""
267
- if name in submodules_set:
268
- return importlib.import_module(f"{package_name}.{name}")
269
- elif name in attr_to_modules:
270
- submod_path = f"{package_name}.{attr_to_modules[name]}"
271
- submod = importlib.import_module(submod_path)
272
- attr = getattr(submod, name)
273
-
274
- # If attribute lives in a file with same name as attribute,
275
- # ensure attribute (not module) is accessible
276
- if name == attr_to_modules[name]:
277
- pkg = sys.modules[package_name]
278
- pkg.__dict__[name] = attr
279
-
280
- return attr
281
- else:
282
- raise AttributeError(f"module {package_name!r} has no attribute {name!r}")
283
-
284
- def __dir__() -> list[str]:
285
- """Return list of available attributes."""
286
- return __all__.copy()
287
-
288
- # Eager import if EAGER_IMPORT env var is set (for debugging)
289
- if os.environ.get("EAGER_IMPORT", ""):
290
- for attr in set(attr_to_modules.keys()) | submodules_set:
291
- __getattr__(attr)
292
-
293
- return __getattr__, __dir__, __all__.copy()
294
-
295
- # =============================================================================
296
- # PUBLIC API FUNCTIONS - Installation
297
- # =============================================================================
298
-
299
- def enable_lazy_install(package_name: str) -> None:
300
- """Enable lazy installation for a package."""
301
- LazyInstallConfig.set(package_name, True)
302
-
303
- def disable_lazy_install(package_name: str) -> None:
304
- """Disable lazy installation for a package."""
305
- LazyInstallConfig.set(package_name, False)
306
-
307
- def is_lazy_install_enabled(package_name: str) -> bool:
308
- """Check if lazy installation is enabled for a package."""
309
- return LazyInstallConfig.is_enabled(package_name)
310
-
311
- def set_lazy_install_mode(package_name: str, mode: LazyInstallMode) -> None:
312
- """Set lazy installation mode for a package."""
313
- LazyInstallConfig.set_install_mode(package_name, mode)
314
-
315
- def get_lazy_install_mode(package_name: str) -> LazyInstallMode:
316
- """Get lazy installation mode for a package."""
317
- return LazyInstallConfig.get_install_mode(package_name)
318
-
319
- def install_missing_package(package_name: str, module_name: str, installer_package: str = 'default') -> bool:
320
- """Install a missing package for a module."""
321
- try:
322
- installer = LazyInstallerRegistry.get_instance(installer_package)
323
- if not installer.is_enabled():
324
- logger.debug(f"Lazy installation disabled for {installer_package}")
325
- return False
326
- return installer.install_package(package_name, module_name)
327
- except Exception as e:
328
- logger.error(f"Failed to install package {package_name} for {installer_package}: {e}")
329
- return False
330
-
331
- def install_and_import(module_name: str, package_name: str = None, installer_package: str = 'default') -> tuple[Optional[ModuleType], bool]:
332
- """Install package and import module."""
333
- try:
334
- installer = LazyInstallerRegistry.get_instance(installer_package)
335
- if not installer.is_enabled():
336
- logger.debug(f"Lazy installation disabled for {installer_package}")
337
- return None, False
338
- return installer.install_and_import(module_name, package_name)
339
- except Exception as e:
340
- logger.error(f"Failed to install and import {module_name} for {installer_package}: {e}")
341
- return None, False
342
-
343
- def get_lazy_install_stats(package_name: str) -> dict[str, Any]:
344
- """Get installation statistics for a package."""
345
- try:
346
- installer = LazyInstallerRegistry.get_instance(package_name)
347
- return installer.get_stats()
348
- except Exception as e:
349
- logger.error(f"Failed to get stats for {package_name}: {e}")
350
- return {
351
- 'enabled': False,
352
- 'mode': 'unknown',
353
- 'package_name': package_name,
354
- 'installed_packages': [],
355
- 'failed_packages': [],
356
- 'total_installed': 0,
357
- 'total_failed': 0,
358
- }
359
-
360
- def get_all_lazy_install_stats() -> dict[str, dict[str, Any]]:
361
- """Get installation statistics for all packages."""
362
- try:
363
- all_instances = LazyInstallerRegistry.get_all_instances()
364
- return {pkg_name: installer.get_stats() for pkg_name, installer in all_instances.items()}
365
- except Exception as e:
366
- logger.error(f"Failed to get all stats: {e}")
367
- return {}
368
-
369
- def lazy_import_with_install(module_name: str, package_name: str = None, installer_package: str = 'default') -> tuple[Optional[ModuleType], bool]:
370
- """Lazy import with automatic installation."""
371
- try:
372
- installer = LazyInstallerRegistry.get_instance(installer_package)
373
- if not installer.is_enabled():
374
- logger.debug(f"Lazy installation disabled for {installer_package}")
375
- return None, False
376
- return installer.install_and_import(module_name, package_name)
377
- except Exception as e:
378
- logger.error(f"Failed to lazy import with install {module_name} for {installer_package}: {e}")
379
- return None, False
380
-
381
- def xwimport(module_name: str, package_name: str = None, installer_package: str = 'default') -> Any:
382
- """Simple lazy import with automatic installation."""
383
- module, available = lazy_import_with_install(module_name, package_name, installer_package)
384
- if not available:
385
- raise ImportError(f"Module {module_name} is not available and could not be installed")
386
- return module
387
-
388
- # =============================================================================
389
- # HOOK FUNCTIONS
390
- # =============================================================================
391
-
392
- def install_import_hook(package_name: str = 'default') -> None:
393
- """Install performant import hook for automatic lazy installation."""
394
- try:
395
- _install_import_hook(package_name)
396
- logger.debug(f"Import hook installed for {package_name}")
397
- except Exception as e:
398
- logger.error(f"Failed to install import hook for {package_name}: {e}")
399
- raise
400
-
401
- def uninstall_import_hook(package_name: str = 'default') -> None:
402
- """Uninstall import hook for a package."""
403
- try:
404
- _uninstall_import_hook(package_name)
405
- logger.debug(f"Import hook uninstalled for {package_name}")
406
- except Exception as e:
407
- logger.error(f"Failed to uninstall import hook for {package_name}: {e}")
408
- raise
409
-
410
- def is_import_hook_installed(package_name: str = 'default') -> bool:
411
- """Check if import hook is installed for a package."""
412
- try:
413
- return _is_import_hook_installed(package_name)
414
- except Exception:
415
- return False
416
-
417
- # =============================================================================
418
- # LAZY LOADING FUNCTIONS
419
- # =============================================================================
420
-
421
- def enable_lazy_imports(mode: LazyLoadMode = LazyLoadMode.AUTO, package_name: Optional[str] = None) -> None:
422
- """
423
- Enable lazy imports.
424
-
425
- This is a global setting that applies to all packages. The package_name
426
- parameter is optional and used only for logging purposes.
427
-
428
- Args:
429
- mode: The lazy load mode to use (default: LazyLoadMode.AUTO)
430
- package_name: Optional package name for logging purposes
431
- """
432
- try:
433
- _lazy_importer.enable(mode)
434
- # Note: _patch_import_module removed - using sys.meta_path hooks instead
435
- if package_name:
436
- logger.debug(f"Lazy imports enabled for {package_name} with mode {mode}")
437
- else:
438
- logger.debug(f"Lazy imports enabled with mode {mode}")
439
- except Exception as e:
440
- if package_name:
441
- logger.error(f"Failed to enable lazy imports for {package_name}: {e}")
442
- else:
443
- logger.error(f"Failed to enable lazy imports: {e}")
444
- raise
445
-
446
- def disable_lazy_imports(package_name: Optional[str] = None) -> None:
447
- """
448
- Disable lazy imports.
449
-
450
- This is a global setting that applies to all packages. The package_name
451
- parameter is optional and used only for logging purposes.
452
-
453
- Args:
454
- package_name: Optional package name for logging purposes
455
- """
456
- try:
457
- _lazy_importer.disable()
458
- # Also unpatch import_module (from archive)
459
- from .module.importer_engine import _unpatch_import_module
460
- _unpatch_import_module()
461
- if package_name:
462
- logger.info(f"Lazy imports disabled for {package_name}")
463
- else:
464
- logger.info("Lazy imports disabled")
465
- except Exception as e:
466
- if package_name:
467
- logger.error(f"Failed to disable lazy imports for {package_name}: {e}")
468
- else:
469
- logger.error(f"Failed to disable lazy imports: {e}")
470
- raise
471
-
472
- def is_lazy_import_enabled(package_name: Optional[str] = None) -> bool:
473
- """
474
- Check if lazy imports are enabled.
475
-
476
- This checks a global setting that applies to all packages. The package_name
477
- parameter is optional and used only for logging purposes.
478
-
479
- Args:
480
- package_name: Optional package name for logging purposes
481
-
482
- Returns:
483
- True if lazy imports are enabled globally
484
- """
485
- try:
486
- return _lazy_importer.is_enabled()
487
- except (AttributeError, RuntimeError) as e:
488
- logger.debug(f"Error checking lazy import status: {e}")
489
- return False
490
- except Exception as e:
491
- # Unexpected errors - log but return False for safety
492
- logger.warning(f"Unexpected error checking lazy import status: {e}")
493
- return False
494
-
495
- def lazy_import(module_name: str, package_name: str = None) -> Optional[ModuleType]:
496
- """Lazy import a module."""
497
- try:
498
- return _lazy_importer.import_module(module_name, package_name)
499
- except Exception as e:
500
- logger.error(f"Failed to lazy import {module_name}: {e}")
501
- return None
502
-
503
- def register_lazy_module(module_name: str, package_name: str = None, module_path: str = None) -> None:
504
- """Register a lazy module loader."""
505
- try:
506
- if module_path is None:
507
- module_path = module_name
508
- _lazy_importer.register_lazy_module(module_name, module_path)
509
- # Also register in global registry (from archive)
510
- _lazy_module_registry.register_module(module_name, module_path)
511
- logger.info(f"Lazy module registered: {module_name}")
512
- except Exception as e:
513
- logger.error(f"Failed to register lazy module {module_name}: {e}")
514
- raise
515
-
516
- def preload_module(module_name: str, package_name: str = None) -> None:
517
- """Preload a lazy module."""
518
- try:
519
- success = _lazy_importer.preload_module(module_name)
520
- if success:
521
- logger.info(f"Preload completed: {module_name}")
522
- else:
523
- logger.warning(f"Preload failed for {module_name}")
524
- except Exception as e:
525
- logger.error(f"Failed to preload module {module_name}: {e}")
526
- raise
527
-
528
- def get_lazy_module(module_name: str, package_name: str = None) -> Optional[ModuleType]:
529
- """Get a lazy module if loaded."""
530
- # Check if module is already loaded in importer
531
- stats = _lazy_importer.get_stats()
532
- if module_name in stats.get('loaded_modules', []):
533
- # Module is loaded, return it via import (safe since it's cached)
534
- try:
535
- import importlib
536
- return importlib.import_module(module_name)
537
- except ImportError:
538
- pass
539
-
540
- # Fallback to registry
541
- try:
542
- loader = _lazy_module_registry.get_module(module_name)
543
- if loader.is_loaded():
544
- return loader.load_module()
545
- except KeyError:
546
- pass
547
-
548
- # Check sys.modules as final fallback
549
- import sys
550
- return sys.modules.get(module_name)
551
-
552
- def get_loading_stats(package_name: str) -> dict[str, Any]:
553
- """Get loading statistics for a package."""
554
- try:
555
- return _lazy_module_registry.get_stats()
556
- except Exception as e:
557
- logger.error(f"Failed to get loading stats for {package_name}: {e}")
558
- return {
559
- 'total_registered': 0,
560
- 'loaded_count': 0,
561
- 'unloaded_count': 0,
562
- 'access_counts': {},
563
- 'load_times': {},
564
- }
565
-
566
- def preload_frequently_used(package_name: str) -> None:
567
- """Preload frequently used modules for a package."""
568
- try:
569
- _lazy_module_registry.preload_frequently_used()
570
- logger.info(f"Preload frequently used completed for {package_name}")
571
- except Exception as e:
572
- logger.error(f"Failed to preload frequently used for {package_name}: {e}")
573
-
574
- def get_lazy_import_stats(package_name: str) -> dict[str, Any]:
575
- """Get lazy import statistics for a package."""
576
- try:
577
- return _lazy_importer.get_stats()
578
- except Exception as e:
579
- logger.error(f"Failed to get lazy import stats for {package_name}: {e}")
580
- return {
581
- 'enabled': False,
582
- 'registered_modules': [],
583
- 'loaded_modules': [],
584
- 'access_counts': {},
585
- 'total_registered': 0,
586
- 'total_loaded': 0,
587
- }
588
-
589
- # =============================================================================
590
- # CONFIGURATION FUNCTIONS
591
- # =============================================================================
592
-
593
- def config_package_lazy_install_enabled(
594
- package_name: str,
595
- enabled: bool = None,
596
- mode: str = "auto",
597
- install_hook: bool = True,
598
- load_mode: Optional[LazyLoadMode] = None,
599
- install_mode: Optional[LazyInstallMode] = None,
600
- mode_config: Optional[LazyModeConfig] = None,
601
- # Strategy parameters
602
- execution_strategy: Optional[Any] = None,
603
- timing_strategy: Optional[Any] = None,
604
- discovery_strategy: Optional[Any] = None,
605
- policy_strategy: Optional[Any] = None,
606
- mapping_strategy: Optional[Any] = None,
607
- ) -> bool:
608
- """
609
- Configure lazy installation for a package.
610
-
611
- Args:
612
- package_name: Package name to configure
613
- enabled: Whether lazy installation is enabled (None = auto-detect)
614
- mode: Installation mode string (e.g., "smart", "full", "clean")
615
- install_hook: Whether to install the import hook
616
- load_mode: Optional explicit load mode
617
- install_mode: Optional explicit install mode
618
- mode_config: Optional full mode configuration
619
- execution_strategy: Optional custom execution strategy instance
620
- timing_strategy: Optional custom timing strategy instance
621
- discovery_strategy: Optional custom discovery strategy instance
622
- policy_strategy: Optional custom policy strategy instance
623
- mapping_strategy: Optional custom mapping strategy instance
624
-
625
- Returns:
626
- True if enabled, False otherwise
627
- """
628
- try:
629
- # Store strategies if provided
630
- from .package.services.strategy_registry import StrategyRegistry
631
- if execution_strategy is not None:
632
- StrategyRegistry.set_package_strategy(package_name, 'execution', execution_strategy)
633
- if timing_strategy is not None:
634
- StrategyRegistry.set_package_strategy(package_name, 'timing', timing_strategy)
635
- if discovery_strategy is not None:
636
- StrategyRegistry.set_package_strategy(package_name, 'discovery', discovery_strategy)
637
- if policy_strategy is not None:
638
- StrategyRegistry.set_package_strategy(package_name, 'policy', policy_strategy)
639
- if mapping_strategy is not None:
640
- StrategyRegistry.set_package_strategy(package_name, 'mapping', mapping_strategy)
641
-
642
- manual_override = enabled is not None
643
- if enabled is None:
644
- enabled = _detect_lazy_installation(package_name)
645
-
646
- # Check meta info for mode override
647
- if mode == "auto" and enabled:
648
- meta_mode = _detect_meta_info_mode(package_name)
649
- if meta_mode:
650
- mode = meta_mode
651
-
652
- # Resolve preset mode if provided
653
- if load_mode is None and install_mode is None and mode_config is None:
654
- preset = get_preset_mode(mode)
655
- if preset:
656
- mode_config = preset
657
-
658
- LazyInstallConfig.set(
659
- package_name,
660
- enabled,
661
- mode,
662
- install_hook=install_hook,
663
- manual=manual_override,
664
- load_mode=load_mode,
665
- install_mode=install_mode,
666
- mode_config=mode_config,
667
- )
668
-
669
- # Register package for global __import__ hook (for module-level imports)
670
- if enabled:
671
- try:
672
- from .module.importer_engine import register_lazy_package, install_global_import_hook
673
- # Register package for global hook
674
- register_lazy_package(package_name, mode_config)
675
- # Install global hook if not already installed
676
- install_global_import_hook()
677
- except Exception as global_hook_error:
678
- logger.warning(f"Failed to register package for global hook {package_name}: {global_hook_error}")
679
-
680
- # Install meta_path hook if requested and enabled
681
- if install_hook and enabled:
682
- try:
683
- install_import_hook(package_name)
684
- except Exception as hook_error:
685
- logger.warning(f"Failed to install import hook for {package_name}: {hook_error}")
686
-
687
- result = LazyInstallConfig.is_enabled(package_name)
688
- logger.debug(f"Configured lazy installation for {package_name}: enabled={result}, mode={mode}")
689
- return result
690
- except Exception as e:
691
- logger.error(f"Failed to configure lazy installation for {package_name}: {e}")
692
- raise
693
-
694
- def config_module_lazy_load_enabled(
695
- package_name: str,
696
- enabled: bool = True,
697
- load_mode: Optional[LazyLoadMode] = None,
698
- # Strategy parameters
699
- helper_strategy: Optional[Any] = None,
700
- manager_strategy: Optional[Any] = None,
701
- caching_strategy: Optional[Any] = None,
702
- ) -> bool:
703
- """
704
- Configure lazy loading for modules in a package.
705
-
706
- Args:
707
- package_name: Package name to configure
708
- enabled: Whether lazy loading is enabled (default: True)
709
- load_mode: Optional explicit load mode
710
- helper_strategy: Optional custom helper strategy instance
711
- manager_strategy: Optional custom manager strategy instance
712
- caching_strategy: Optional custom caching strategy instance
713
-
714
- Returns:
715
- True if enabled, False otherwise
716
- """
717
- try:
718
- # Store strategies if provided
719
- from .package.services.strategy_registry import StrategyRegistry
720
- if helper_strategy is not None:
721
- StrategyRegistry.set_module_strategy(package_name, 'helper', helper_strategy)
722
- if manager_strategy is not None:
723
- StrategyRegistry.set_module_strategy(package_name, 'manager', manager_strategy)
724
- if caching_strategy is not None:
725
- StrategyRegistry.set_module_strategy(package_name, 'caching', caching_strategy)
726
-
727
- # Enable lazy imports if requested
728
- if enabled:
729
- if load_mode is None:
730
- load_mode = LazyLoadMode.AUTO
731
- enable_lazy_imports(load_mode, package_name=package_name)
732
- else:
733
- disable_lazy_imports(package_name=package_name)
734
-
735
- logger.info(f"Configured lazy loading for {package_name}: enabled={enabled}, load_mode={load_mode}")
736
- return enabled
737
- except Exception as e:
738
- logger.error(f"Failed to configure lazy loading for {package_name}: {e}")
739
- raise
740
-
741
- def sync_manifest_configuration(package_name: str) -> None:
742
- """
743
- Sync configuration from manifest for a specific package.
744
-
745
- This syncs all manifest settings including:
746
- - Dependencies
747
- - Watched prefixes
748
- - Class wrap prefixes (registered as package class hints)
749
- - Async configuration
750
- """
751
- try:
752
- from .module.importer_engine import _set_package_class_hints
753
-
754
- from .package.services.manifest import _normalize_package_name, get_manifest_loader as _get_manifest_loader
755
- package_key = _normalize_package_name(package_name)
756
-
757
- # Get the loader instance - this ensures we use the same instance throughout
758
- # This is critical for tests that patch get_manifest_loader
759
- loader = _get_manifest_loader()
760
-
761
- # Sync manifest configuration using the loader instance directly
762
- # This ensures we use the same loader instance that we'll use to get the manifest
763
- loader.sync_manifest_configuration(package_name)
764
-
765
- # Register class wrap prefixes from manifest as package class hints
766
- # After sync, the manifest cache is cleared, so get_manifest will reload it
767
- manifest = loader.get_manifest(package_key)
768
- if manifest and manifest.class_wrap_prefixes:
769
- _set_package_class_hints(package_key, manifest.class_wrap_prefixes)
770
-
771
- logger.debug(f"Manifest configuration synced for {package_name}")
772
- except Exception as e:
773
- logger.error(f"Failed to sync manifest configuration for {package_name}: {e}")
774
- raise
775
-
776
- def refresh_lazy_manifests() -> None:
777
- """Refresh all lazy manifest caches."""
778
- try:
779
- refresh_manifest_cache()
780
- logger.info("Refreshed all lazy manifest caches")
781
- except Exception as e:
782
- logger.error(f"Failed to refresh lazy manifest caches: {e}")
783
- raise
784
-
785
- # =============================================================================
786
- # SECURITY & POLICY FUNCTIONS
787
- # =============================================================================
788
-
789
- def set_package_allow_list(package_name: str, allowed_packages: list[str]) -> None:
790
- """Set allow list for a package."""
791
- try:
792
- LazyInstallPolicy.set_allow_list(package_name, allowed_packages)
793
- logger.debug(f"Set allow list for {package_name}: {allowed_packages}")
794
- except Exception as e:
795
- logger.error(f"Failed to set allow list for {package_name}: {e}")
796
- raise
797
-
798
- def set_package_deny_list(package_name: str, denied_packages: list[str]) -> None:
799
- """Set deny list for a package."""
800
- try:
801
- LazyInstallPolicy.set_deny_list(package_name, denied_packages)
802
- logger.debug(f"Set deny list for {package_name}: {denied_packages}")
803
- except Exception as e:
804
- logger.error(f"Failed to set deny list for {package_name}: {e}")
805
- raise
806
-
807
- def add_to_package_allow_list(package_name: str, allowed_package: str) -> None:
808
- """Add single package to allow list."""
809
- try:
810
- LazyInstallPolicy.add_to_allow_list(package_name, allowed_package)
811
- logger.debug(f"Added {allowed_package} to allow list for {package_name}")
812
- except Exception as e:
813
- logger.error(f"Failed to add {allowed_package} to allow list for {package_name}: {e}")
814
- raise
815
-
816
- def add_to_package_deny_list(package_name: str, denied_package: str) -> None:
817
- """Add single package to deny list."""
818
- try:
819
- LazyInstallPolicy.add_to_deny_list(package_name, denied_package)
820
- logger.debug(f"Added {denied_package} to deny list for {package_name}")
821
- except Exception as e:
822
- logger.error(f"Failed to add {denied_package} to deny list for {package_name}: {e}")
823
- raise
824
-
825
- def set_package_index_url(package_name: str, index_url: str) -> None:
826
- """Set package index URL for a package."""
827
- try:
828
- LazyInstallPolicy.set_index_url(package_name, index_url)
829
- logger.debug(f"Set index URL for {package_name}: {index_url}")
830
- except Exception as e:
831
- logger.error(f"Failed to set index URL for {package_name}: {e}")
832
- raise
833
-
834
- def set_package_extra_index_urls(package_name: str, extra_index_urls: list[str]) -> None:
835
- """Set extra index URLs for a package."""
836
- try:
837
- LazyInstallPolicy.set_extra_index_urls(package_name, extra_index_urls)
838
- logger.debug(f"Set extra index URLs for {package_name}: {extra_index_urls}")
839
- except Exception as e:
840
- logger.error(f"Failed to set extra index URLs for {package_name}: {e}")
841
- raise
842
-
843
- def add_package_trusted_host(package_name: str, host: str) -> None:
844
- """Add trusted host for a package."""
845
- try:
846
- LazyInstallPolicy.add_trusted_host(package_name, host)
847
- logger.debug(f"Added trusted host {host} for {package_name}")
848
- except Exception as e:
849
- logger.error(f"Failed to add trusted host {host} for {package_name}: {e}")
850
- raise
851
-
852
- def set_package_lockfile(package_name: str, lockfile_path: str) -> None:
853
- """Set lockfile path for a package."""
854
- try:
855
- LazyInstallPolicy.set_lockfile_path(package_name, lockfile_path)
856
- logger.debug(f"Set lockfile path for {package_name}: {lockfile_path}")
857
- except Exception as e:
858
- logger.error(f"Failed to set lockfile path for {package_name}: {e}")
859
- raise
860
-
861
- def generate_package_sbom(package_name: str, output_path: Optional[str] = None) -> dict[str, Any]:
862
- """Generate SBOM for a package."""
863
- try:
864
- installer = LazyInstallerRegistry.get_instance(package_name)
865
- sbom = installer.generate_sbom()
866
- if output_path:
867
- installer.export_sbom(output_path)
868
- return sbom
869
- except Exception as e:
870
- logger.error(f"Failed to generate SBOM for {package_name}: {e}")
871
- return {
872
- "metadata": {
873
- "format": "xwlazy-sbom",
874
- "version": "1.0",
875
- "error": str(e)
876
- },
877
- "packages": []
878
- }
879
-
880
- def check_externally_managed_environment(package_name: str = 'default') -> bool:
881
- """Check if environment is externally managed."""
882
- try:
883
- return _is_externally_managed()
884
- except Exception as e:
885
- logger.error(f"Failed to check externally managed environment: {e}")
886
- return False
887
-
888
- def register_lazy_module_prefix(prefix: str) -> None:
889
- """Register a module prefix mapping."""
890
- try:
891
- _register_lazy_module_prefix(prefix)
892
- logger.debug(f"Registered lazy module prefix: {prefix}")
893
- except Exception as e:
894
- logger.error(f"Failed to register lazy module prefix {prefix}: {e}")
895
- raise
896
-
897
- def register_lazy_module_methods(prefix: str, methods: tuple[str, ...]) -> None:
898
- """Register methods for a lazy module."""
899
- try:
900
- _register_lazy_module_methods(prefix, methods)
901
- logger.debug(f"Registered lazy module methods for prefix {prefix}: {methods}")
902
- except Exception as e:
903
- logger.error(f"Failed to register lazy module methods for {prefix}: {e}")
904
- raise
905
-
906
- # =============================================================================
907
- # MODULE REGISTRATION DOMAIN - Internal Utilities
908
- # =============================================================================
909
-
910
- # Note: Internal utility functions are available from hooks.finder module
911
- # They are used internally by the lazy loading system and don't need facade wrappers
912
-
913
- # =============================================================================
914
- # KEYWORD-BASED DETECTION FUNCTIONS
915
- # =============================================================================
916
-
917
- def enable_keyword_detection(enabled: bool = True, keyword: Optional[str] = None, package_name: Optional[str] = None) -> None:
918
- """
919
- Enable keyword-based package detection.
920
-
921
- This is a global setting that applies to all packages. The package_name
922
- parameter is optional and used only for logging purposes.
923
-
924
- Args:
925
- enabled: Whether to enable keyword detection (default: True)
926
- keyword: Custom keyword to check (default: "xwlazy-enabled")
927
- package_name: Optional package name for logging purposes
928
- """
929
- try:
930
- _enable_keyword_detection(enabled, keyword)
931
- if package_name:
932
- logger.info(f"Keyword detection {'enabled' if enabled else 'disabled'} for {package_name}")
933
- else:
934
- logger.info(f"Keyword detection {'enabled' if enabled else 'disabled'}")
935
- except Exception as e:
936
- if package_name:
937
- logger.error(f"Failed to enable keyword detection for {package_name}: {e}")
938
- else:
939
- logger.error(f"Failed to enable keyword detection: {e}")
940
- raise
941
-
942
- def is_keyword_detection_enabled(package_name: Optional[str] = None) -> bool:
943
- """
944
- Check if keyword detection is enabled.
945
-
946
- This checks a global setting that applies to all packages. The package_name
947
- parameter is optional and used only for logging purposes.
948
-
949
- Args:
950
- package_name: Optional package name for logging purposes
951
-
952
- Returns:
953
- True if keyword detection is enabled globally
954
- """
955
- try:
956
- return _is_keyword_detection_enabled()
957
- except (AttributeError, RuntimeError) as e:
958
- logger.debug(f"Error checking keyword detection status: {e}")
959
- return False
960
- except Exception as e:
961
- # Unexpected errors - log but return False for safety
962
- logger.warning(f"Unexpected error checking keyword detection status: {e}")
963
- return False
964
-
965
- def get_keyword_detection_keyword(package_name: Optional[str] = None) -> Optional[str]:
966
- """
967
- Get keyword used for detection.
968
-
969
- This returns the global keyword setting. The package_name parameter is
970
- optional and used only for logging purposes.
971
-
972
- Args:
973
- package_name: Optional package name for logging purposes
974
-
975
- Returns:
976
- The keyword being checked for auto-detection
977
- """
978
- try:
979
- return _get_keyword_detection_keyword()
980
- except Exception as e:
981
- logger.error(f"Failed to get keyword detection keyword: {e}")
982
- return None
983
-
984
- def check_package_keywords(package_name: Optional[str] = None, keywords: Optional[list[str]] = None) -> bool:
985
- """
986
- Check if a package (or any package) has the specified keyword in its metadata.
987
-
988
- Args:
989
- package_name: The package name to check (or None to check all packages)
990
- keywords: Optional list of keywords to check (uses first keyword if provided)
991
-
992
- Returns:
993
- True if the keyword is found in the package's metadata
994
- """
995
- try:
996
- keyword = keywords[0] if keywords else None
997
- return _check_package_keywords(package_name, keyword)
998
- except Exception as e:
999
- if package_name:
1000
- logger.error(f"Failed to check package keywords for {package_name}: {e}")
1001
- else:
1002
- logger.error(f"Failed to check package keywords: {e}")
1003
- return False
1004
-
1005
- # =============================================================================
1006
- # DISCOVERY FUNCTIONS
1007
- # =============================================================================
1008
-
1009
- def get_lazy_discovery(package_name: str = 'default') -> Optional[APackageHelper]:
1010
- """Get discovery instance for a package."""
1011
- try:
1012
- return _get_lazy_discovery()
1013
- except Exception as e:
1014
- logger.error(f"Failed to get discovery instance for {package_name}: {e}")
1015
- return None
1016
-
1017
- def discover_dependencies(package_name: str = 'default') -> dict[str, str]:
1018
- """Discover dependencies for a package."""
1019
- try:
1020
- discovery = _get_lazy_discovery()
1021
- if discovery:
1022
- return discovery.discover_all_dependencies()
1023
- except Exception as e:
1024
- logger.error(f"Failed to discover dependencies for {package_name}: {e}")
1025
- return {}
1026
-
1027
- def export_dependency_mappings(package_name: str = 'default', output_path: Optional[str] = None) -> None:
1028
- """Export dependency mappings to file."""
1029
- try:
1030
- discovery = _get_lazy_discovery()
1031
- if discovery:
1032
- if output_path:
1033
- discovery.export_to_json(output_path)
1034
- else:
1035
- # Default output path
1036
- from pathlib import Path
1037
- output_path = Path.cwd() / f"{package_name}_dependencies.json"
1038
- discovery.export_to_json(str(output_path))
1039
- logger.info(f"Dependency mappings exported for {package_name} to {output_path}")
1040
- else:
1041
- logger.warning(f"No discovery instance available for {package_name}")
1042
- except Exception as e:
1043
- logger.error(f"Failed to export dependency mappings for {package_name}: {e}")
1044
- raise
1045
-
1046
- # =============================================================================
1047
- # PUBLIC API EXPORTS
1048
- # =============================================================================
1049
-
1050
- __all__ = [
1051
- # Facade class
1052
- 'LazyModeFacade',
1053
- # Facade functions
1054
- 'enable_lazy_mode',
1055
- 'disable_lazy_mode',
1056
- 'is_lazy_mode_enabled',
1057
- 'get_lazy_mode_stats',
1058
- 'configure_lazy_mode',
1059
- 'preload_modules',
1060
- 'optimize_lazy_mode',
1061
- # One-line activation API
1062
- 'auto_enable_lazy',
1063
- # Lazy-loader compatible API
1064
- 'attach',
1065
- # Public API functions
1066
- 'enable_lazy_install',
1067
- 'disable_lazy_install',
1068
- 'is_lazy_install_enabled',
1069
- 'set_lazy_install_mode',
1070
- 'get_lazy_install_mode',
1071
- 'install_missing_package',
1072
- 'install_and_import',
1073
- 'get_lazy_install_stats',
1074
- 'get_all_lazy_install_stats',
1075
- 'lazy_import_with_install',
1076
- 'xwimport',
1077
- # Hook functions
1078
- 'install_import_hook',
1079
- 'uninstall_import_hook',
1080
- 'is_import_hook_installed',
1081
- # Lazy loading functions
1082
- 'enable_lazy_imports',
1083
- 'disable_lazy_imports',
1084
- 'is_lazy_import_enabled',
1085
- 'lazy_import',
1086
- 'register_lazy_module',
1087
- 'preload_module',
1088
- 'get_lazy_module',
1089
- 'get_loading_stats',
1090
- 'preload_frequently_used',
1091
- 'get_lazy_import_stats',
1092
- # Configuration
1093
- 'config_package_lazy_install_enabled',
1094
- 'config_module_lazy_load_enabled',
1095
- 'sync_manifest_configuration',
1096
- 'refresh_lazy_manifests',
1097
- # Security & Policy
1098
- 'set_package_allow_list',
1099
- 'set_package_deny_list',
1100
- 'add_to_package_allow_list',
1101
- 'add_to_package_deny_list',
1102
- 'set_package_index_url',
1103
- 'set_package_extra_index_urls',
1104
- 'add_package_trusted_host',
1105
- 'set_package_lockfile',
1106
- 'generate_package_sbom',
1107
- 'check_externally_managed_environment',
1108
- 'register_lazy_module_prefix',
1109
- 'register_lazy_module_methods',
1110
- # Keyword-based detection
1111
- 'enable_keyword_detection',
1112
- 'is_keyword_detection_enabled',
1113
- 'get_keyword_detection_keyword',
1114
- 'check_package_keywords',
1115
- # Discovery functions
1116
- 'get_lazy_discovery',
1117
- 'discover_dependencies',
1118
- 'export_dependency_mappings',
1119
- # Helper classes
1120
- 'XWPackageHelper',
1121
- 'XWModuleHelper',
1122
- ]
1123
-
1124
- # =============================================================================
1125
- # CONCRETE HELPER IMPLEMENTATIONS (Simple API Pattern)
1126
- # =============================================================================
1127
-
1128
- # XWPackageHelper moved to package/facade.py
1129
- # This is now just an alias (defined above)
1130
- # Removed duplicate class definition - use the one from package/facade.py
1131
- # XWModuleHelper moved to module/facade.py
1132
- # This is now just an alias (defined above)
1133
- # Removed duplicate class definition - use the one from module/facade.py
1134
-
1135
- # Global helper instances
1136
- _package_helper = XWPackageHelper()
1137
- _module_helper = XWModuleHelper()