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,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Package Services
|
|
3
|
+
|
|
4
|
+
Supporting services for package operations (not strategies).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .install_result import InstallStatus, InstallResult
|
|
8
|
+
from .install_policy import LazyInstallPolicy
|
|
9
|
+
from .install_utils import get_trigger_file, is_externally_managed, check_pip_audit_available
|
|
10
|
+
from .install_registry import LazyInstallerRegistry
|
|
11
|
+
from .installer_engine import InstallerEngine
|
|
12
|
+
from .async_install_handle import AsyncInstallHandle
|
|
13
|
+
from .lazy_installer import LazyInstaller
|
|
14
|
+
from .strategy_registry import StrategyRegistry
|
|
15
|
+
|
|
16
|
+
# Config and manifest services
|
|
17
|
+
from .config_manager import LazyInstallConfig
|
|
18
|
+
from .manifest import (
|
|
19
|
+
PackageManifest,
|
|
20
|
+
LazyManifestLoader,
|
|
21
|
+
get_manifest_loader,
|
|
22
|
+
refresh_manifest_cache,
|
|
23
|
+
sync_manifest_configuration,
|
|
24
|
+
_normalize_prefix,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Discovery service
|
|
28
|
+
from .discovery import LazyDiscovery, get_lazy_discovery
|
|
29
|
+
|
|
30
|
+
# State management and keyword detection (moved to common/services)
|
|
31
|
+
from ...common.services import (
|
|
32
|
+
LazyStateManager,
|
|
33
|
+
enable_keyword_detection,
|
|
34
|
+
is_keyword_detection_enabled,
|
|
35
|
+
get_keyword_detection_keyword,
|
|
36
|
+
check_package_keywords,
|
|
37
|
+
_detect_lazy_installation,
|
|
38
|
+
_detect_meta_info_mode,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Host package registration
|
|
42
|
+
from .host_packages import (
|
|
43
|
+
register_host_package,
|
|
44
|
+
refresh_host_package,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
# Install services
|
|
49
|
+
'InstallStatus',
|
|
50
|
+
'InstallResult',
|
|
51
|
+
'LazyInstallPolicy',
|
|
52
|
+
'LazyInstallerRegistry',
|
|
53
|
+
'InstallerEngine',
|
|
54
|
+
'AsyncInstallHandle',
|
|
55
|
+
'LazyInstaller',
|
|
56
|
+
'StrategyRegistry',
|
|
57
|
+
'get_trigger_file',
|
|
58
|
+
'is_externally_managed',
|
|
59
|
+
'check_pip_audit_available',
|
|
60
|
+
# Config and manifest
|
|
61
|
+
'LazyInstallConfig',
|
|
62
|
+
'PackageManifest',
|
|
63
|
+
'LazyManifestLoader',
|
|
64
|
+
'get_manifest_loader',
|
|
65
|
+
'refresh_manifest_cache',
|
|
66
|
+
'sync_manifest_configuration',
|
|
67
|
+
'_normalize_prefix',
|
|
68
|
+
# Discovery
|
|
69
|
+
'LazyDiscovery',
|
|
70
|
+
'get_lazy_discovery',
|
|
71
|
+
# State management
|
|
72
|
+
'LazyStateManager',
|
|
73
|
+
# Keyword detection
|
|
74
|
+
'enable_keyword_detection',
|
|
75
|
+
'is_keyword_detection_enabled',
|
|
76
|
+
'get_keyword_detection_keyword',
|
|
77
|
+
'check_package_keywords',
|
|
78
|
+
'_detect_lazy_installation',
|
|
79
|
+
'_detect_meta_info_mode',
|
|
80
|
+
# Host package registration
|
|
81
|
+
'register_host_package',
|
|
82
|
+
'refresh_host_package',
|
|
83
|
+
]
|
|
84
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Async Install Handle
|
|
3
|
+
|
|
4
|
+
Company: eXonware.com
|
|
5
|
+
Author: Eng. Muhammad AlShehri
|
|
6
|
+
Email: connect@exonware.com
|
|
7
|
+
|
|
8
|
+
Generation Date: 15-Nov-2025
|
|
9
|
+
|
|
10
|
+
Lightweight handle for background installation jobs.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
from typing import Optional, Any
|
|
15
|
+
|
|
16
|
+
class AsyncInstallHandle:
|
|
17
|
+
"""Lightweight handle for background installation jobs."""
|
|
18
|
+
|
|
19
|
+
__slots__ = ("_task_or_future", "module_name", "package_name", "installer_package")
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
task_or_future: Any, # Can be Future or asyncio.Task
|
|
24
|
+
module_name: str,
|
|
25
|
+
package_name: str,
|
|
26
|
+
installer_package: str,
|
|
27
|
+
) -> None:
|
|
28
|
+
self._task_or_future = task_or_future
|
|
29
|
+
self.module_name = module_name
|
|
30
|
+
self.package_name = package_name
|
|
31
|
+
self.installer_package = installer_package
|
|
32
|
+
|
|
33
|
+
def wait(self, timeout: Optional[float] = None) -> bool:
|
|
34
|
+
"""
|
|
35
|
+
Wait for installation to complete.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
timeout: Optional timeout in seconds
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
True if installation succeeded, False otherwise
|
|
42
|
+
"""
|
|
43
|
+
try:
|
|
44
|
+
# Handle concurrent.futures.Future (from asyncio.run_coroutine_threadsafe)
|
|
45
|
+
if hasattr(self._task_or_future, 'result'):
|
|
46
|
+
result = self._task_or_future.result(timeout=timeout)
|
|
47
|
+
return bool(result)
|
|
48
|
+
# Handle asyncio.Task
|
|
49
|
+
elif hasattr(self._task_or_future, 'done'):
|
|
50
|
+
if timeout is None:
|
|
51
|
+
# Use asyncio.wait_for if we have a loop
|
|
52
|
+
try:
|
|
53
|
+
loop = asyncio.get_event_loop()
|
|
54
|
+
if loop.is_running():
|
|
55
|
+
# Can't wait in running loop, return False
|
|
56
|
+
return False
|
|
57
|
+
except RuntimeError:
|
|
58
|
+
pass
|
|
59
|
+
# Create new event loop to wait
|
|
60
|
+
return asyncio.run(self._wait_task())
|
|
61
|
+
else:
|
|
62
|
+
return asyncio.run(asyncio.wait_for(self._wait_task(), timeout=timeout))
|
|
63
|
+
return False
|
|
64
|
+
except Exception:
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
async def _wait_task(self) -> bool:
|
|
68
|
+
"""Async helper to wait for task."""
|
|
69
|
+
if hasattr(self._task_or_future, 'done'):
|
|
70
|
+
await self._task_or_future
|
|
71
|
+
return bool(self._task_or_future.result() if hasattr(self._task_or_future, 'result') else True)
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def done(self) -> bool:
|
|
76
|
+
"""
|
|
77
|
+
Check if installation is complete.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
True if installation is complete
|
|
81
|
+
"""
|
|
82
|
+
if hasattr(self._task_or_future, 'done'):
|
|
83
|
+
return self._task_or_future.done()
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
__all__ = ['AsyncInstallHandle']
|
|
87
|
+
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration management for lazy loading system.
|
|
3
|
+
|
|
4
|
+
This module contains LazyInstallConfig which manages per-package lazy installation
|
|
5
|
+
configuration. Extracted from lazy_core.py Section 5.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Optional
|
|
9
|
+
from ...common.services import LazyStateManager
|
|
10
|
+
from ...defs import LazyLoadMode, LazyInstallMode, LazyModeConfig
|
|
11
|
+
from ...defs import get_preset_mode
|
|
12
|
+
|
|
13
|
+
# Lazy import to avoid circular dependency
|
|
14
|
+
def _get_logger():
|
|
15
|
+
"""Get logger (lazy import to avoid circular dependency)."""
|
|
16
|
+
from ...common.logger import get_logger
|
|
17
|
+
return get_logger("xwlazy.config")
|
|
18
|
+
|
|
19
|
+
def _get_log_event():
|
|
20
|
+
"""Get log_event function (lazy import to avoid circular dependency)."""
|
|
21
|
+
from ...common.logger import log_event
|
|
22
|
+
return log_event
|
|
23
|
+
|
|
24
|
+
logger = None # Will be initialized on first use
|
|
25
|
+
_log = None # Will be initialized on first use
|
|
26
|
+
|
|
27
|
+
# Mode enum mapping - extracted from lazy_core.py
|
|
28
|
+
_MODE_ENUM_MAP = {
|
|
29
|
+
# Core v1.0 modes
|
|
30
|
+
"none": LazyInstallMode.NONE,
|
|
31
|
+
"smart": LazyInstallMode.SMART,
|
|
32
|
+
"full": LazyInstallMode.FULL,
|
|
33
|
+
"clean": LazyInstallMode.CLEAN,
|
|
34
|
+
"temporary": LazyInstallMode.TEMPORARY,
|
|
35
|
+
"size_aware": LazyInstallMode.SIZE_AWARE,
|
|
36
|
+
# Special purpose modes
|
|
37
|
+
"interactive": LazyInstallMode.INTERACTIVE,
|
|
38
|
+
"warn": LazyInstallMode.WARN,
|
|
39
|
+
"disabled": LazyInstallMode.DISABLED,
|
|
40
|
+
"dry_run": LazyInstallMode.DRY_RUN,
|
|
41
|
+
# Legacy aliases
|
|
42
|
+
"auto": LazyInstallMode.SMART,
|
|
43
|
+
"on_demand": LazyInstallMode.SMART,
|
|
44
|
+
"on-demand": LazyInstallMode.SMART,
|
|
45
|
+
"lazy": LazyInstallMode.SMART,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class LazyInstallConfig:
|
|
49
|
+
"""Global configuration for lazy installation per package."""
|
|
50
|
+
_configs: Dict[str, bool] = {}
|
|
51
|
+
_modes: Dict[str, str] = {}
|
|
52
|
+
_load_modes: Dict[str, LazyLoadMode] = {}
|
|
53
|
+
_install_modes: Dict[str, LazyInstallMode] = {}
|
|
54
|
+
_mode_configs: Dict[str, LazyModeConfig] = {}
|
|
55
|
+
_initialized: Dict[str, bool] = {}
|
|
56
|
+
_manual_overrides: Dict[str, bool] = {}
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def set(
|
|
60
|
+
cls,
|
|
61
|
+
package_name: str,
|
|
62
|
+
enabled: bool,
|
|
63
|
+
mode: str = "auto",
|
|
64
|
+
install_hook: bool = True,
|
|
65
|
+
manual: bool = False,
|
|
66
|
+
load_mode: Optional[LazyLoadMode] = None,
|
|
67
|
+
install_mode: Optional[LazyInstallMode] = None,
|
|
68
|
+
mode_config: Optional[LazyModeConfig] = None,
|
|
69
|
+
) -> None:
|
|
70
|
+
"""Enable or disable lazy installation for a specific package."""
|
|
71
|
+
package_key = package_name.lower()
|
|
72
|
+
state_manager = LazyStateManager(package_name)
|
|
73
|
+
|
|
74
|
+
if manual:
|
|
75
|
+
cls._manual_overrides[package_key] = True
|
|
76
|
+
state_manager.set_manual_state(enabled)
|
|
77
|
+
elif cls._manual_overrides.get(package_key):
|
|
78
|
+
global logger
|
|
79
|
+
if logger is None:
|
|
80
|
+
logger = _get_logger()
|
|
81
|
+
logger.debug(
|
|
82
|
+
f"Lazy install config for {package_key} already overridden manually; skipping auto configuration."
|
|
83
|
+
)
|
|
84
|
+
return
|
|
85
|
+
else:
|
|
86
|
+
state_manager.set_manual_state(None)
|
|
87
|
+
|
|
88
|
+
cls._configs[package_key] = enabled
|
|
89
|
+
cls._modes[package_key] = mode
|
|
90
|
+
|
|
91
|
+
# Handle two-dimensional mode configuration
|
|
92
|
+
if mode_config:
|
|
93
|
+
cls._mode_configs[package_key] = mode_config
|
|
94
|
+
cls._load_modes[package_key] = mode_config.load_mode
|
|
95
|
+
cls._install_modes[package_key] = mode_config.install_mode
|
|
96
|
+
elif load_mode is not None or install_mode is not None:
|
|
97
|
+
# Explicit mode specification
|
|
98
|
+
if load_mode is None:
|
|
99
|
+
load_mode = LazyLoadMode.AUTO # Default
|
|
100
|
+
if install_mode is None:
|
|
101
|
+
install_mode = _MODE_ENUM_MAP.get(mode.lower(), LazyInstallMode.SMART)
|
|
102
|
+
cls._load_modes[package_key] = load_mode
|
|
103
|
+
cls._install_modes[package_key] = install_mode
|
|
104
|
+
cls._mode_configs[package_key] = LazyModeConfig(
|
|
105
|
+
load_mode=load_mode,
|
|
106
|
+
install_mode=install_mode
|
|
107
|
+
)
|
|
108
|
+
else:
|
|
109
|
+
# Legacy mode string - try to resolve to preset or default
|
|
110
|
+
preset = get_preset_mode(mode)
|
|
111
|
+
if preset:
|
|
112
|
+
cls._mode_configs[package_key] = preset
|
|
113
|
+
cls._load_modes[package_key] = preset.load_mode
|
|
114
|
+
cls._install_modes[package_key] = preset.install_mode
|
|
115
|
+
else:
|
|
116
|
+
# Fallback to legacy behavior
|
|
117
|
+
install_mode_enum = _MODE_ENUM_MAP.get(mode.lower(), LazyInstallMode.SMART)
|
|
118
|
+
cls._load_modes[package_key] = LazyLoadMode.AUTO
|
|
119
|
+
cls._install_modes[package_key] = install_mode_enum
|
|
120
|
+
cls._mode_configs[package_key] = LazyModeConfig(
|
|
121
|
+
load_mode=LazyLoadMode.AUTO,
|
|
122
|
+
install_mode=install_mode_enum
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
cls._initialize_package(package_key, enabled, mode, install_hook=install_hook)
|
|
126
|
+
|
|
127
|
+
@classmethod
|
|
128
|
+
def _initialize_package(cls, package_key: str, enabled: bool, mode: str, install_hook: bool = True) -> None:
|
|
129
|
+
"""Initialize lazy installation for a specific package."""
|
|
130
|
+
global logger, _log
|
|
131
|
+
if logger is None:
|
|
132
|
+
logger = _get_logger()
|
|
133
|
+
if _log is None:
|
|
134
|
+
_log = _get_log_event()
|
|
135
|
+
|
|
136
|
+
# Deferred imports to avoid circular dependency
|
|
137
|
+
from .install_registry import LazyInstallerRegistry
|
|
138
|
+
from ...facade import (
|
|
139
|
+
enable_lazy_install,
|
|
140
|
+
disable_lazy_install,
|
|
141
|
+
set_lazy_install_mode,
|
|
142
|
+
enable_lazy_imports,
|
|
143
|
+
install_import_hook,
|
|
144
|
+
uninstall_import_hook,
|
|
145
|
+
is_import_hook_installed,
|
|
146
|
+
sync_manifest_configuration,
|
|
147
|
+
)
|
|
148
|
+
import asyncio
|
|
149
|
+
|
|
150
|
+
if enabled:
|
|
151
|
+
try:
|
|
152
|
+
# Don't call enable_lazy_install() here - it would create infinite recursion
|
|
153
|
+
# The config is already set by LazyInstallConfig.set() above
|
|
154
|
+
|
|
155
|
+
# Use explicitly set install_mode from config, or derive from mode string
|
|
156
|
+
# Check if install_mode was explicitly set by checking if package_key exists in _install_modes
|
|
157
|
+
if package_key in cls._install_modes:
|
|
158
|
+
# install_mode was explicitly set in set() method, don't override it
|
|
159
|
+
mode_enum = cls._install_modes[package_key]
|
|
160
|
+
else:
|
|
161
|
+
# Not explicitly set, derive from mode string
|
|
162
|
+
mode_enum = _MODE_ENUM_MAP.get(mode.lower(), LazyInstallMode.SMART)
|
|
163
|
+
set_lazy_install_mode(package_key, mode_enum)
|
|
164
|
+
|
|
165
|
+
# Get load mode from config
|
|
166
|
+
load_mode = cls.get_load_mode(package_key)
|
|
167
|
+
|
|
168
|
+
# Enable lazy imports with appropriate load mode (skip if NONE mode)
|
|
169
|
+
if load_mode != LazyLoadMode.NONE:
|
|
170
|
+
enable_lazy_imports(load_mode, package_name=package_key)
|
|
171
|
+
|
|
172
|
+
# Enable async for modes that support it
|
|
173
|
+
installer = LazyInstallerRegistry.get_instance(package_key)
|
|
174
|
+
if installer and mode_enum in (LazyInstallMode.SMART, LazyInstallMode.FULL, LazyInstallMode.CLEAN, LazyInstallMode.TEMPORARY):
|
|
175
|
+
installer._async_enabled = True
|
|
176
|
+
installer._ensure_async_loop()
|
|
177
|
+
|
|
178
|
+
# For FULL mode, install all dependencies on start
|
|
179
|
+
if mode_enum == LazyInstallMode.FULL:
|
|
180
|
+
loop = installer._async_loop
|
|
181
|
+
if loop:
|
|
182
|
+
asyncio.run_coroutine_threadsafe(installer.install_all_dependencies(), loop)
|
|
183
|
+
|
|
184
|
+
if install_hook:
|
|
185
|
+
if not is_import_hook_installed(package_key):
|
|
186
|
+
install_import_hook(package_key)
|
|
187
|
+
_log("config", logger.info, f"✅ Lazy installation initialized for {package_key} (install_mode: {mode}, load_mode: {load_mode.value}, hook: installed)")
|
|
188
|
+
else:
|
|
189
|
+
uninstall_import_hook(package_key)
|
|
190
|
+
_log("config", logger.info, f"✅ Lazy installation initialized for {package_key} (install_mode: {mode}, load_mode: {load_mode.value}, hook: disabled)")
|
|
191
|
+
|
|
192
|
+
cls._initialized[package_key] = True
|
|
193
|
+
sync_manifest_configuration(package_key)
|
|
194
|
+
except ImportError as e:
|
|
195
|
+
if logger is None:
|
|
196
|
+
logger = _get_logger()
|
|
197
|
+
logger.warning(f"⚠️ Could not enable lazy install for {package_key}: {e}")
|
|
198
|
+
else:
|
|
199
|
+
try:
|
|
200
|
+
disable_lazy_install(package_key)
|
|
201
|
+
except ImportError:
|
|
202
|
+
pass
|
|
203
|
+
uninstall_import_hook(package_key)
|
|
204
|
+
cls._initialized[package_key] = False
|
|
205
|
+
_log("config", logger.info, f"❌ Lazy installation disabled for {package_key}")
|
|
206
|
+
sync_manifest_configuration(package_key)
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
def is_enabled(cls, package_name: str) -> bool:
|
|
210
|
+
"""Check if lazy installation is enabled for a package."""
|
|
211
|
+
return cls._configs.get(package_name.lower(), False)
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
def get_mode(cls, package_name: str) -> str:
|
|
215
|
+
"""Get the lazy installation mode for a package."""
|
|
216
|
+
return cls._modes.get(package_name.lower(), "auto")
|
|
217
|
+
|
|
218
|
+
@classmethod
|
|
219
|
+
def get_mode_config(cls, package_name: str) -> Optional[LazyModeConfig]:
|
|
220
|
+
"""Get the full mode configuration for a package."""
|
|
221
|
+
return cls._mode_configs.get(package_name.lower())
|
|
222
|
+
|
|
223
|
+
@classmethod
|
|
224
|
+
def get_load_mode(cls, package_name: str) -> LazyLoadMode:
|
|
225
|
+
"""Get the load mode for a package."""
|
|
226
|
+
return cls._load_modes.get(package_name.lower(), LazyLoadMode.NONE)
|
|
227
|
+
|
|
228
|
+
@classmethod
|
|
229
|
+
def get_install_mode(cls, package_name: str) -> LazyInstallMode:
|
|
230
|
+
"""Get the install mode for a package."""
|
|
231
|
+
return cls._install_modes.get(package_name.lower(), LazyInstallMode.NONE)
|
|
232
|
+
|
|
233
|
+
@classmethod
|
|
234
|
+
def set_install_mode(cls, package_name: str, mode: LazyInstallMode) -> None:
|
|
235
|
+
"""Set the install mode for a package."""
|
|
236
|
+
package_key = package_name.lower()
|
|
237
|
+
cls._install_modes[package_key] = mode
|
|
238
|
+
# Update mode config if it exists
|
|
239
|
+
if package_key in cls._mode_configs:
|
|
240
|
+
mode_config = cls._mode_configs[package_key]
|
|
241
|
+
cls._mode_configs[package_key] = LazyModeConfig(
|
|
242
|
+
load_mode=mode_config.load_mode,
|
|
243
|
+
install_mode=mode
|
|
244
|
+
)
|
|
245
|
+
|