exonware-xwlazy 0.1.0.10__py3-none-any.whl → 0.1.0.19__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 (89) hide show
  1. exonware/__init__.py +22 -0
  2. exonware/xwlazy/__init__.py +0 -0
  3. exonware/xwlazy/common/__init__.py +47 -0
  4. exonware/xwlazy/common/base.py +58 -0
  5. exonware/xwlazy/common/cache.py +506 -0
  6. exonware/xwlazy/common/logger.py +268 -0
  7. exonware/xwlazy/common/services/__init__.py +72 -0
  8. exonware/xwlazy/common/services/dependency_mapper.py +234 -0
  9. exonware/xwlazy/common/services/install_async_utils.py +169 -0
  10. exonware/xwlazy/common/services/install_cache_utils.py +257 -0
  11. exonware/xwlazy/common/services/keyword_detection.py +292 -0
  12. exonware/xwlazy/common/services/spec_cache.py +173 -0
  13. exonware/xwlazy/common/services/state_manager.py +86 -0
  14. exonware/xwlazy/common/strategies/__init__.py +28 -0
  15. exonware/xwlazy/common/strategies/caching_dict.py +45 -0
  16. exonware/xwlazy/common/strategies/caching_installation.py +89 -0
  17. exonware/xwlazy/common/strategies/caching_lfu.py +67 -0
  18. exonware/xwlazy/common/strategies/caching_lru.py +64 -0
  19. exonware/xwlazy/common/strategies/caching_multitier.py +60 -0
  20. exonware/xwlazy/common/strategies/caching_ttl.py +60 -0
  21. exonware/xwlazy/config.py +195 -0
  22. exonware/xwlazy/contracts.py +1410 -0
  23. exonware/xwlazy/defs.py +397 -0
  24. exonware/xwlazy/errors.py +284 -0
  25. exonware/xwlazy/facade.py +1049 -0
  26. exonware/xwlazy/module/__init__.py +18 -0
  27. exonware/xwlazy/module/base.py +569 -0
  28. exonware/xwlazy/module/data.py +17 -0
  29. exonware/xwlazy/module/facade.py +247 -0
  30. exonware/xwlazy/module/importer_engine.py +2161 -0
  31. exonware/xwlazy/module/strategies/__init__.py +22 -0
  32. exonware/xwlazy/module/strategies/module_helper_lazy.py +94 -0
  33. exonware/xwlazy/module/strategies/module_helper_simple.py +66 -0
  34. exonware/xwlazy/module/strategies/module_manager_advanced.py +112 -0
  35. exonware/xwlazy/module/strategies/module_manager_simple.py +96 -0
  36. exonware/xwlazy/package/__init__.py +18 -0
  37. exonware/xwlazy/package/base.py +807 -0
  38. exonware/xwlazy/package/conf.py +331 -0
  39. exonware/xwlazy/package/data.py +17 -0
  40. exonware/xwlazy/package/facade.py +481 -0
  41. exonware/xwlazy/package/services/__init__.py +84 -0
  42. exonware/xwlazy/package/services/async_install_handle.py +89 -0
  43. exonware/xwlazy/package/services/config_manager.py +246 -0
  44. exonware/xwlazy/package/services/discovery.py +374 -0
  45. exonware/xwlazy/package/services/host_packages.py +149 -0
  46. exonware/xwlazy/package/services/install_async.py +278 -0
  47. exonware/xwlazy/package/services/install_cache.py +146 -0
  48. exonware/xwlazy/package/services/install_interactive.py +60 -0
  49. exonware/xwlazy/package/services/install_policy.py +158 -0
  50. exonware/xwlazy/package/services/install_registry.py +56 -0
  51. exonware/xwlazy/package/services/install_result.py +17 -0
  52. exonware/xwlazy/package/services/install_sbom.py +154 -0
  53. exonware/xwlazy/package/services/install_utils.py +83 -0
  54. exonware/xwlazy/package/services/installer_engine.py +408 -0
  55. exonware/xwlazy/package/services/lazy_installer.py +720 -0
  56. exonware/xwlazy/package/services/manifest.py +506 -0
  57. exonware/xwlazy/package/services/strategy_registry.py +188 -0
  58. exonware/xwlazy/package/strategies/__init__.py +57 -0
  59. exonware/xwlazy/package/strategies/package_discovery_file.py +130 -0
  60. exonware/xwlazy/package/strategies/package_discovery_hybrid.py +85 -0
  61. exonware/xwlazy/package/strategies/package_discovery_manifest.py +102 -0
  62. exonware/xwlazy/package/strategies/package_execution_async.py +114 -0
  63. exonware/xwlazy/package/strategies/package_execution_cached.py +91 -0
  64. exonware/xwlazy/package/strategies/package_execution_pip.py +100 -0
  65. exonware/xwlazy/package/strategies/package_execution_wheel.py +107 -0
  66. exonware/xwlazy/package/strategies/package_mapping_discovery_first.py +101 -0
  67. exonware/xwlazy/package/strategies/package_mapping_hybrid.py +106 -0
  68. exonware/xwlazy/package/strategies/package_mapping_manifest_first.py +101 -0
  69. exonware/xwlazy/package/strategies/package_policy_allow_list.py +58 -0
  70. exonware/xwlazy/package/strategies/package_policy_deny_list.py +58 -0
  71. exonware/xwlazy/package/strategies/package_policy_permissive.py +47 -0
  72. exonware/xwlazy/package/strategies/package_timing_clean.py +68 -0
  73. exonware/xwlazy/package/strategies/package_timing_full.py +67 -0
  74. exonware/xwlazy/package/strategies/package_timing_smart.py +69 -0
  75. exonware/xwlazy/package/strategies/package_timing_temporary.py +67 -0
  76. exonware/xwlazy/runtime/__init__.py +18 -0
  77. exonware/xwlazy/runtime/adaptive_learner.py +131 -0
  78. exonware/xwlazy/runtime/base.py +276 -0
  79. exonware/xwlazy/runtime/facade.py +95 -0
  80. exonware/xwlazy/runtime/intelligent_selector.py +173 -0
  81. exonware/xwlazy/runtime/metrics.py +64 -0
  82. exonware/xwlazy/runtime/performance.py +39 -0
  83. exonware/xwlazy/version.py +2 -2
  84. exonware_xwlazy-0.1.0.19.dist-info/METADATA +456 -0
  85. exonware_xwlazy-0.1.0.19.dist-info/RECORD +87 -0
  86. exonware_xwlazy-0.1.0.10.dist-info/METADATA +0 -0
  87. exonware_xwlazy-0.1.0.10.dist-info/RECORD +0 -6
  88. {exonware_xwlazy-0.1.0.10.dist-info → exonware_xwlazy-0.1.0.19.dist-info}/WHEEL +0 -0
  89. {exonware_xwlazy-0.1.0.10.dist-info → exonware_xwlazy-0.1.0.19.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,89 @@
1
+ """
2
+ Installation Cache Strategy - Wrapper for existing InstallationCache.
3
+
4
+ Company: eXonware.com
5
+ Author: Eng. Muhammad AlShehri
6
+ Email: connect@exonware.com
7
+ Version: 0.1.0.19
8
+ Generation Date: 15-Nov-2025
9
+
10
+ Wraps existing InstallationCache to implement ICachingStrategy interface.
11
+ """
12
+
13
+ from typing import Optional, Any
14
+ from pathlib import Path
15
+ from ..cache import InstallationCache
16
+ from ..base import ACachingStrategy
17
+ from ...package.data import PackageData
18
+
19
+
20
+ class InstallationCacheWrapper(ACachingStrategy):
21
+ """
22
+ Installation cache strategy wrapper.
23
+
24
+ Wraps existing InstallationCache to implement ICachingStrategy interface.
25
+ Used for package installation status caching.
26
+ """
27
+
28
+ def __init__(self, cache_file: Optional[Path] = None):
29
+ """
30
+ Initialize installation cache wrapper.
31
+
32
+ Args:
33
+ cache_file: Optional path to cache file
34
+ """
35
+ self._cache = InstallationCache(cache_file)
36
+
37
+ def get(self, key: str) -> Optional[Any]:
38
+ """
39
+ Get package from cache.
40
+
41
+ Args:
42
+ key: Package name
43
+
44
+ Returns:
45
+ PackageData if found, None otherwise
46
+ """
47
+ if self._cache.is_installed(key):
48
+ version = self._cache.get_version(key)
49
+ return PackageData(
50
+ name=key,
51
+ installed=True,
52
+ version=version
53
+ )
54
+ return None
55
+
56
+ def set(self, key: str, value: Any) -> None:
57
+ """
58
+ Cache a package.
59
+
60
+ Args:
61
+ key: Package name
62
+ value: PackageData or dict with installed/version info
63
+ """
64
+ if isinstance(value, PackageData):
65
+ if value.installed:
66
+ self._cache.mark_installed(key, value.version)
67
+ else:
68
+ self._cache.mark_uninstalled(key)
69
+ elif isinstance(value, dict):
70
+ if value.get('installed', False):
71
+ self._cache.mark_installed(key, value.get('version'))
72
+ else:
73
+ self._cache.mark_uninstalled(key)
74
+
75
+ def invalidate(self, key: str) -> None:
76
+ """
77
+ Invalidate cached package.
78
+
79
+ Args:
80
+ key: Package name
81
+ """
82
+ self._cache.mark_uninstalled(key)
83
+
84
+ def clear(self) -> None:
85
+ """Clear all cached packages."""
86
+ # InstallationCache doesn't have clear, so we'd need to extend it
87
+ # For now, just mark all as uninstalled (would need cache iteration)
88
+ pass
89
+
@@ -0,0 +1,67 @@
1
+ """
2
+ LFU Cache Strategy - Least Frequently Used eviction.
3
+
4
+ Company: eXonware.com
5
+ Author: Eng. Muhammad AlShehri
6
+ Email: connect@exonware.com
7
+ Version: 0.1.0.19
8
+ Generation Date: 15-Nov-2025
9
+
10
+ LFU cache implementation with size limit.
11
+ Works with ANY data type (modules, packages, etc.).
12
+ """
13
+
14
+ from typing import Dict, Optional, Any
15
+ from collections import Counter
16
+ from ...common.base import ACachingStrategy
17
+
18
+
19
+ class LFUCache(ACachingStrategy):
20
+ """
21
+ LFU (Least Frequently Used) cache with size limit.
22
+
23
+ Evicts least frequently accessed items when cache is full.
24
+ Good for access pattern-based caching.
25
+ """
26
+
27
+ def __init__(self, max_size: int = 1000):
28
+ """
29
+ Initialize LFU cache.
30
+
31
+ Args:
32
+ max_size: Maximum number of items in cache
33
+ """
34
+ self._cache: Dict[str, Any] = {}
35
+ self._freq: Counter[str] = Counter()
36
+ self._max_size = max_size
37
+
38
+ def get(self, key: str) -> Optional[Any]:
39
+ """Get value from cache (increments frequency)."""
40
+ if key in self._cache:
41
+ self._freq[key] += 1
42
+ return self._cache[key]
43
+ return None
44
+
45
+ def set(self, key: str, value: Any) -> None:
46
+ """Set value in cache (evicts least frequent if full)."""
47
+ if key not in self._cache and len(self._cache) >= self._max_size:
48
+ # Evict least frequent
49
+ if self._freq:
50
+ least_frequent = min(self._freq.items(), key=lambda x: x[1])[0]
51
+ self._cache.pop(least_frequent, None)
52
+ self._freq.pop(least_frequent, None)
53
+
54
+ self._cache[key] = value
55
+ if key not in self._freq:
56
+ self._freq[key] = 0
57
+
58
+ def invalidate(self, key: str) -> None:
59
+ """Invalidate cached value."""
60
+ self._cache.pop(key, None)
61
+ self._freq.pop(key, None)
62
+
63
+ def clear(self) -> None:
64
+ """Clear all cached values."""
65
+ self._cache.clear()
66
+ self._freq.clear()
67
+
@@ -0,0 +1,64 @@
1
+ """
2
+ LRU Cache Strategy - Least Recently Used eviction.
3
+
4
+ Company: eXonware.com
5
+ Author: Eng. Muhammad AlShehri
6
+ Email: connect@exonware.com
7
+ Version: 0.1.0.19
8
+ Generation Date: 15-Nov-2025
9
+
10
+ LRU cache implementation with size limit.
11
+ Works with ANY data type (modules, packages, etc.).
12
+ """
13
+
14
+ from typing import Optional, Any
15
+ from collections import OrderedDict
16
+ from ...common.base import ACachingStrategy
17
+
18
+
19
+ class LRUCache(ACachingStrategy):
20
+ """
21
+ LRU (Least Recently Used) cache with size limit.
22
+
23
+ Evicts least recently used items when cache is full.
24
+ Good for general-purpose caching.
25
+ """
26
+
27
+ def __init__(self, max_size: int = 1000):
28
+ """
29
+ Initialize LRU cache.
30
+
31
+ Args:
32
+ max_size: Maximum number of items in cache
33
+ """
34
+ self._cache: OrderedDict[str, Any] = OrderedDict()
35
+ self._max_size = max_size
36
+
37
+ def get(self, key: str) -> Optional[Any]:
38
+ """Get value from cache (moves to end for LRU)."""
39
+ if key in self._cache:
40
+ # Move to end (most recently used)
41
+ self._cache.move_to_end(key)
42
+ return self._cache[key]
43
+ return None
44
+
45
+ def set(self, key: str, value: Any) -> None:
46
+ """Set value in cache (evicts oldest if full)."""
47
+ if key in self._cache:
48
+ # Update existing - move to end
49
+ self._cache.move_to_end(key)
50
+ else:
51
+ # New entry - check size limit
52
+ if len(self._cache) >= self._max_size:
53
+ # Remove oldest (first item)
54
+ self._cache.popitem(last=False)
55
+ self._cache[key] = value
56
+
57
+ def invalidate(self, key: str) -> None:
58
+ """Invalidate cached value."""
59
+ self._cache.pop(key, None)
60
+
61
+ def clear(self) -> None:
62
+ """Clear all cached values."""
63
+ self._cache.clear()
64
+
@@ -0,0 +1,60 @@
1
+ """
2
+ Multi-Tier Cache Strategy - Wrapper for existing MultiTierCache.
3
+
4
+ Company: eXonware.com
5
+ Author: Eng. Muhammad AlShehri
6
+ Email: connect@exonware.com
7
+ Version: 0.1.0.19
8
+ Generation Date: 15-Nov-2025
9
+
10
+ Wraps existing MultiTierCache to implement ICaching interface.
11
+ Works with ANY data type (modules, packages, etc.).
12
+ """
13
+
14
+ from typing import Optional, Any
15
+ from pathlib import Path
16
+ from ...common.cache import MultiTierCache
17
+ from ...common.base import ACachingStrategy
18
+
19
+
20
+ class MultiTierCacheStrategy(ACachingStrategy):
21
+ """
22
+ Multi-tier cache strategy (L1 memory + L2 disk + L3 predictive).
23
+
24
+ Wraps existing MultiTierCache to implement ICachingStrategy interface.
25
+ High-performance caching with multiple tiers.
26
+ """
27
+
28
+ def __init__(self, l1_size: int = 1000, l2_dir: Optional[Path] = None, enable_l3: bool = True):
29
+ """
30
+ Initialize multi-tier cache.
31
+
32
+ Args:
33
+ l1_size: Maximum size of L1 (memory) cache
34
+ l2_dir: Directory for L2 (disk) cache
35
+ enable_l3: Enable L3 (predictive) cache
36
+ """
37
+ self._cache = MultiTierCache(l1_size=l1_size, l2_dir=l2_dir, enable_l3=enable_l3)
38
+
39
+ def get(self, key: str) -> Optional[Any]:
40
+ """Get value from cache (L1 -> L2 -> L3)."""
41
+ return self._cache.get(key)
42
+
43
+ def set(self, key: str, value: Any) -> None:
44
+ """Set value in cache (L1 + L2 batched)."""
45
+ self._cache.set(key, value)
46
+
47
+ def invalidate(self, key: str) -> None:
48
+ """Invalidate cached value."""
49
+ # MultiTierCache doesn't have invalidate, so we set to None
50
+ # Or we could extend MultiTierCache to add invalidate
51
+ self._cache.set(key, None)
52
+
53
+ def clear(self) -> None:
54
+ """Clear all cached values."""
55
+ self._cache.clear()
56
+
57
+ def shutdown(self) -> None:
58
+ """Shutdown cache (flush L2, cleanup threads)."""
59
+ self._cache.shutdown()
60
+
@@ -0,0 +1,60 @@
1
+ """
2
+ TTL Cache Strategy - Time-To-Live expiration.
3
+
4
+ Company: eXonware.com
5
+ Author: Eng. Muhammad AlShehri
6
+ Email: connect@exonware.com
7
+ Version: 0.1.0.19
8
+ Generation Date: 15-Nov-2025
9
+
10
+ TTL cache implementation with expiration.
11
+ Works with ANY data type (modules, packages, etc.).
12
+ """
13
+
14
+ import time
15
+ from typing import Dict, Optional, Any, Tuple
16
+ from ...common.base import ACachingStrategy
17
+
18
+
19
+ class TTLCache(ACachingStrategy):
20
+ """
21
+ TTL (Time-To-Live) cache with expiration.
22
+
23
+ Automatically expires entries after TTL seconds.
24
+ Good for time-sensitive data.
25
+ """
26
+
27
+ def __init__(self, ttl_seconds: float = 3600.0):
28
+ """
29
+ Initialize TTL cache.
30
+
31
+ Args:
32
+ ttl_seconds: Time-to-live in seconds (default: 1 hour)
33
+ """
34
+ self._cache: Dict[str, Tuple[Any, float]] = {} # (value, expiry_time)
35
+ self._ttl = ttl_seconds
36
+
37
+ def get(self, key: str) -> Optional[Any]:
38
+ """Get value from cache (returns None if expired)."""
39
+ if key in self._cache:
40
+ value, expiry = self._cache[key]
41
+ if time.time() < expiry:
42
+ return value
43
+ else:
44
+ # Expired - remove
45
+ del self._cache[key]
46
+ return None
47
+
48
+ def set(self, key: str, value: Any) -> None:
49
+ """Set value in cache with TTL."""
50
+ expiry = time.time() + self._ttl
51
+ self._cache[key] = (value, expiry)
52
+
53
+ def invalidate(self, key: str) -> None:
54
+ """Invalidate cached value."""
55
+ self._cache.pop(key, None)
56
+
57
+ def clear(self) -> None:
58
+ """Clear all cached values."""
59
+ self._cache.clear()
60
+
@@ -0,0 +1,195 @@
1
+ """
2
+ #exonware/xwlazy/src/exonware/xwlazy/config.py
3
+
4
+ Company: eXonware.com
5
+ Author: Eng. Muhammad AlShehri
6
+ Email: connect@exonware.com
7
+ Version: 0.1.0.19
8
+ Generation Date: 10-Oct-2025
9
+
10
+ Configuration for Lazy Loading System
11
+
12
+ This module defines configuration classes for the lazy loading system
13
+ following GUIDE_ARCH.md structure.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Optional, Any, Dict
19
+
20
+ # Import LazyConfig dataclass from defs.py
21
+ from .defs import LazyConfig as _LazyConfigBase
22
+
23
+
24
+ # Extend LazyConfig with methods (dataclass is in defs.py)
25
+ class LazyConfig(_LazyConfigBase):
26
+ """Bridge configuration settings with the lazy package implementation."""
27
+
28
+ def __post_init__(self) -> None:
29
+ """Normalize package names."""
30
+ super().__post_init__()
31
+
32
+ # High-level API -----------------------------------------------------
33
+ @property
34
+ def lazy_import(self) -> bool:
35
+ """Return whether lazy mode is currently active."""
36
+ # Import from facade
37
+ from .facade import is_lazy_mode_enabled
38
+ return is_lazy_mode_enabled()
39
+
40
+ @lazy_import.setter
41
+ def lazy_import(self, value: bool) -> None:
42
+ self.set_lazy_import(bool(value))
43
+
44
+ def set_lazy_import(
45
+ self,
46
+ enabled: bool,
47
+ *,
48
+ lazy_imports: bool = True,
49
+ lazy_install: bool = True,
50
+ install_hook: bool = True,
51
+ mode: str = "auto",
52
+ ) -> None:
53
+ """
54
+ Toggle lazy mode with optional fine-grained controls.
55
+
56
+ Includes re-hooking support: If lazy is enabled and install_hook is True,
57
+ ensures the import hook is installed even if it wasn't installed initially.
58
+ """
59
+ # Import from facade
60
+ from .facade import (
61
+ config_package_lazy_install_enabled,
62
+ disable_lazy_mode,
63
+ enable_lazy_mode,
64
+ is_import_hook_installed,
65
+ install_import_hook,
66
+ )
67
+
68
+ if enabled:
69
+ self._configure_packages(True, mode=mode, install_hook=install_hook)
70
+ enable_lazy_mode(
71
+ package_name=self.packages[0],
72
+ enable_lazy_imports=lazy_imports,
73
+ enable_lazy_install=lazy_install,
74
+ install_hook=install_hook,
75
+ lazy_install_mode=mode,
76
+ )
77
+ # Re-hook: Install hook if lazy is enabled and hook not already installed
78
+ # Root cause: Hook not installed when lazy enabled after package load
79
+ # Priority impact: Usability (#2) - Users expect lazy to work when enabled
80
+ if install_hook:
81
+ self._ensure_hook_installed()
82
+ else:
83
+ disable_lazy_mode()
84
+ self._configure_packages(False, install_hook=False)
85
+
86
+ def enable(
87
+ self,
88
+ *,
89
+ lazy_imports: bool = True,
90
+ lazy_install: bool = True,
91
+ install_hook: bool = True,
92
+ mode: str = "auto",
93
+ ) -> None:
94
+ """Enable lazy mode using the provided options."""
95
+ self.set_lazy_import(
96
+ True,
97
+ lazy_imports=lazy_imports,
98
+ lazy_install=lazy_install,
99
+ install_hook=install_hook,
100
+ mode=mode,
101
+ )
102
+
103
+ def disable(self) -> None:
104
+ """Disable lazy mode entirely."""
105
+ self.set_lazy_import(False)
106
+
107
+ # DX: Status check methods -------------------------------------------
108
+ def get_lazy_status(self) -> dict:
109
+ """
110
+ Get detailed lazy installation status (DX enhancement).
111
+
112
+ Returns:
113
+ Dictionary with lazy mode status information
114
+ """
115
+ # Import from facade
116
+ from .facade import (
117
+ is_import_hook_installed,
118
+ is_lazy_install_enabled,
119
+ )
120
+
121
+ try:
122
+ primary_package = self.packages[0] if self.packages else "default"
123
+ return {
124
+ 'enabled': self.lazy_import,
125
+ 'hook_installed': is_import_hook_installed(primary_package),
126
+ 'lazy_install_enabled': is_lazy_install_enabled(primary_package),
127
+ 'active': self.lazy_import and is_import_hook_installed(primary_package)
128
+ }
129
+ except Exception:
130
+ return {
131
+ 'enabled': self.lazy_import,
132
+ 'hook_installed': False,
133
+ 'lazy_install_enabled': False,
134
+ 'active': False,
135
+ 'error': 'Could not check hook status'
136
+ }
137
+
138
+ def is_lazy_active(self) -> bool:
139
+ """
140
+ Check if lazy mode is active (DX enhancement).
141
+
142
+ Returns:
143
+ True if lazy mode is enabled and hook is installed
144
+ """
145
+ # Import from facade
146
+ from .facade import is_import_hook_installed
147
+
148
+ try:
149
+ primary_package = self.packages[0] if self.packages else "default"
150
+ return self.lazy_import and is_import_hook_installed(primary_package)
151
+ except Exception:
152
+ return False
153
+
154
+ # Internal helpers ---------------------------------------------------
155
+ def _configure_packages(
156
+ self,
157
+ enabled: bool,
158
+ *,
159
+ mode: str = "auto",
160
+ install_hook: bool = True,
161
+ ) -> None:
162
+ # Import from facade
163
+ from .facade import config_package_lazy_install_enabled
164
+
165
+ for package in self.packages:
166
+ config_package_lazy_install_enabled(
167
+ package,
168
+ enabled,
169
+ mode,
170
+ install_hook=install_hook,
171
+ )
172
+
173
+ def _ensure_hook_installed(self) -> None:
174
+ """
175
+ Ensure import hook is installed for primary package.
176
+
177
+ Re-hooking support: Install hook if not already installed.
178
+ """
179
+ # Import from facade
180
+ from .facade import (
181
+ is_import_hook_installed,
182
+ install_import_hook,
183
+ )
184
+
185
+ try:
186
+ primary_package = self.packages[0] if self.packages else "default"
187
+ if not is_import_hook_installed(primary_package):
188
+ install_import_hook(primary_package)
189
+ except Exception:
190
+ # Fail silently - hook installation failure shouldn't break package
191
+ pass
192
+
193
+
194
+ DEFAULT_LAZY_CONFIG = LazyConfig()
195
+