exonware-xwlazy 0.1.0.22__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 (90) hide show
  1. exonware/__init__.py +86 -16
  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.22.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/METADATA +6 -6
  6. exonware_xwlazy-1.0.1.2.dist-info/RECORD +8 -0
  7. exonware/xwlazy/__init__.py +0 -367
  8. exonware/xwlazy/common/__init__.py +0 -47
  9. exonware/xwlazy/common/base.py +0 -56
  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 -232
  14. exonware/xwlazy/common/services/install_async_utils.py +0 -165
  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/config.py +0 -193
  27. exonware/xwlazy/contracts.py +0 -1396
  28. exonware/xwlazy/defs.py +0 -378
  29. exonware/xwlazy/errors.py +0 -276
  30. exonware/xwlazy/facade.py +0 -991
  31. exonware/xwlazy/module/__init__.py +0 -18
  32. exonware/xwlazy/module/base.py +0 -565
  33. exonware/xwlazy/module/data.py +0 -17
  34. exonware/xwlazy/module/facade.py +0 -246
  35. exonware/xwlazy/module/importer_engine.py +0 -2117
  36. exonware/xwlazy/module/strategies/__init__.py +0 -22
  37. exonware/xwlazy/module/strategies/module_helper_lazy.py +0 -93
  38. exonware/xwlazy/module/strategies/module_helper_simple.py +0 -65
  39. exonware/xwlazy/module/strategies/module_manager_advanced.py +0 -111
  40. exonware/xwlazy/module/strategies/module_manager_simple.py +0 -95
  41. exonware/xwlazy/package/__init__.py +0 -18
  42. exonware/xwlazy/package/base.py +0 -798
  43. exonware/xwlazy/package/conf.py +0 -324
  44. exonware/xwlazy/package/data.py +0 -17
  45. exonware/xwlazy/package/facade.py +0 -480
  46. exonware/xwlazy/package/services/__init__.py +0 -84
  47. exonware/xwlazy/package/services/async_install_handle.py +0 -87
  48. exonware/xwlazy/package/services/config_manager.py +0 -245
  49. exonware/xwlazy/package/services/discovery.py +0 -370
  50. exonware/xwlazy/package/services/host_packages.py +0 -145
  51. exonware/xwlazy/package/services/install_async.py +0 -277
  52. exonware/xwlazy/package/services/install_cache.py +0 -145
  53. exonware/xwlazy/package/services/install_interactive.py +0 -59
  54. exonware/xwlazy/package/services/install_policy.py +0 -156
  55. exonware/xwlazy/package/services/install_registry.py +0 -54
  56. exonware/xwlazy/package/services/install_result.py +0 -17
  57. exonware/xwlazy/package/services/install_sbom.py +0 -153
  58. exonware/xwlazy/package/services/install_utils.py +0 -79
  59. exonware/xwlazy/package/services/installer_engine.py +0 -406
  60. exonware/xwlazy/package/services/lazy_installer.py +0 -718
  61. exonware/xwlazy/package/services/manifest.py +0 -496
  62. exonware/xwlazy/package/services/strategy_registry.py +0 -186
  63. exonware/xwlazy/package/strategies/__init__.py +0 -57
  64. exonware/xwlazy/package/strategies/package_discovery_file.py +0 -129
  65. exonware/xwlazy/package/strategies/package_discovery_hybrid.py +0 -84
  66. exonware/xwlazy/package/strategies/package_discovery_manifest.py +0 -101
  67. exonware/xwlazy/package/strategies/package_execution_async.py +0 -113
  68. exonware/xwlazy/package/strategies/package_execution_cached.py +0 -90
  69. exonware/xwlazy/package/strategies/package_execution_pip.py +0 -99
  70. exonware/xwlazy/package/strategies/package_execution_wheel.py +0 -106
  71. exonware/xwlazy/package/strategies/package_mapping_discovery_first.py +0 -100
  72. exonware/xwlazy/package/strategies/package_mapping_hybrid.py +0 -105
  73. exonware/xwlazy/package/strategies/package_mapping_manifest_first.py +0 -100
  74. exonware/xwlazy/package/strategies/package_policy_allow_list.py +0 -57
  75. exonware/xwlazy/package/strategies/package_policy_deny_list.py +0 -57
  76. exonware/xwlazy/package/strategies/package_policy_permissive.py +0 -46
  77. exonware/xwlazy/package/strategies/package_timing_clean.py +0 -67
  78. exonware/xwlazy/package/strategies/package_timing_full.py +0 -66
  79. exonware/xwlazy/package/strategies/package_timing_smart.py +0 -68
  80. exonware/xwlazy/package/strategies/package_timing_temporary.py +0 -66
  81. exonware/xwlazy/runtime/__init__.py +0 -18
  82. exonware/xwlazy/runtime/adaptive_learner.py +0 -129
  83. exonware/xwlazy/runtime/base.py +0 -274
  84. exonware/xwlazy/runtime/facade.py +0 -94
  85. exonware/xwlazy/runtime/intelligent_selector.py +0 -170
  86. exonware/xwlazy/runtime/metrics.py +0 -60
  87. exonware/xwlazy/runtime/performance.py +0 -37
  88. exonware_xwlazy-0.1.0.22.dist-info/RECORD +0 -87
  89. {exonware_xwlazy-0.1.0.22.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/WHEEL +0 -0
  90. {exonware_xwlazy-0.1.0.22.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,106 +0,0 @@
1
- """
2
- Wheel Execution Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Wheel execution strategy - install from wheel files.
11
- Uses shared utilities from common/services/install_cache_utils.
12
- """
13
-
14
- import sys
15
- import subprocess
16
- from pathlib import Path
17
- from typing import List, Any, Optional
18
- from ...package.base import AInstallExecutionStrategy
19
- from ...package.services.install_result import InstallResult, InstallStatus
20
- from ...common.services.install_cache_utils import (
21
- get_wheel_path,
22
- ensure_cached_wheel,
23
- pip_install_from_path,
24
- )
25
-
26
- class WheelExecution(AInstallExecutionStrategy):
27
- """
28
- Wheel execution strategy - installs packages from wheel files.
29
-
30
- Downloads wheel first, then installs from local wheel file.
31
- Uses shared utilities from common/services/install_cache_utils.
32
- """
33
-
34
- def __init__(self, cache_dir: Optional[Path] = None):
35
- """
36
- Initialize wheel execution strategy.
37
-
38
- Args:
39
- cache_dir: Optional cache directory for wheels
40
- """
41
- self._cache_dir = cache_dir
42
-
43
- def execute_install(self, package_name: str, policy_args: List[str]) -> Any:
44
- """
45
- Execute installation from wheel file.
46
-
47
- Args:
48
- package_name: Package name to install
49
- policy_args: Policy arguments
50
-
51
- Returns:
52
- InstallResult with success status
53
- """
54
- # Check if wheel already exists
55
- wheel_path = get_wheel_path(package_name, self._cache_dir)
56
-
57
- if not wheel_path.exists():
58
- # Download wheel first
59
- wheel_path = ensure_cached_wheel(package_name, policy_args, self._cache_dir)
60
- if wheel_path is None:
61
- return InstallResult(
62
- package_name=package_name,
63
- success=False,
64
- status=InstallStatus.FAILED,
65
- error="Failed to download wheel"
66
- )
67
-
68
- # Install from wheel
69
- success = pip_install_from_path(wheel_path, policy_args)
70
-
71
- if success:
72
- return InstallResult(
73
- package_name=package_name,
74
- success=True,
75
- status=InstallStatus.SUCCESS,
76
- source="wheel"
77
- )
78
- else:
79
- return InstallResult(
80
- package_name=package_name,
81
- success=False,
82
- status=InstallStatus.FAILED,
83
- error="Failed to install from wheel"
84
- )
85
-
86
- def execute_uninstall(self, package_name: str) -> bool:
87
- """
88
- Execute uninstallation using pip.
89
-
90
- Args:
91
- package_name: Package name to uninstall
92
-
93
- Returns:
94
- True if successful, False otherwise
95
- """
96
- try:
97
- result = subprocess.run(
98
- [sys.executable, '-m', 'pip', 'uninstall', '-y', package_name],
99
- capture_output=True,
100
- text=True,
101
- check=True
102
- )
103
- return result.returncode == 0
104
- except Exception:
105
- return False
106
-
@@ -1,100 +0,0 @@
1
- """
2
- Discovery-First Mapping Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Discovery-first mapping strategy - discovery takes precedence over manifest.
11
- """
12
-
13
- from typing import Optional, List
14
- from ...package.base import AMappingStrategy
15
- from ...package.services.manifest import get_manifest_loader
16
-
17
- class DiscoveryFirstMapping(AMappingStrategy):
18
- """
19
- Discovery-first mapping strategy.
20
-
21
- Priority order:
22
- 1. Discovery mappings (automatic discovery - highest priority)
23
- 2. Manifest dependencies (explicit user configuration)
24
- 3. Common mappings (fallback)
25
- """
26
-
27
- def __init__(self, package_name: str = 'default'):
28
- """
29
- Initialize discovery-first mapping strategy.
30
-
31
- Args:
32
- package_name: Package name for isolation
33
- """
34
- self._package_name = package_name
35
- self._discovery = None # Lazy init
36
-
37
- def _get_discovery(self):
38
- """Get discovery instance (lazy init)."""
39
- if self._discovery is None:
40
- from ...package.services.discovery import LazyDiscovery
41
- self._discovery = LazyDiscovery(self._package_name)
42
- return self._discovery
43
-
44
- def map_import_to_package(self, import_name: str) -> Optional[str]:
45
- """
46
- Map import name to package name.
47
-
48
- Priority: Discovery > Manifest > Common mappings
49
-
50
- Args:
51
- import_name: Import name (e.g., 'cv2')
52
-
53
- Returns:
54
- Package name (e.g., 'opencv-python') or None
55
- """
56
- # Check discovery mappings FIRST
57
- discovery = self._get_discovery()
58
- discovery_mapping = discovery.get_import_package_mapping()
59
- package = discovery_mapping.get(import_name)
60
- if package:
61
- return package
62
-
63
- # Check manifest (fallback)
64
- loader = get_manifest_loader()
65
- manifest = loader.get_manifest(self._package_name)
66
- if manifest:
67
- package = manifest.get_dependency(import_name)
68
- if package:
69
- return package
70
-
71
- # Fallback to common mappings
72
- common_mappings = discovery.COMMON_MAPPINGS
73
- return common_mappings.get(import_name)
74
-
75
- def map_package_to_imports(self, package_name: str) -> List[str]:
76
- """
77
- Map package name to possible import names.
78
-
79
- Args:
80
- package_name: Package name (e.g., 'opencv-python')
81
-
82
- Returns:
83
- List of possible import names (e.g., ['cv2'])
84
- """
85
- # Check discovery mappings FIRST
86
- discovery = self._get_discovery()
87
- package_mapping = discovery.get_package_import_mapping()
88
- imports = package_mapping.get(package_name, [])
89
-
90
- # Also check manifest (reverse lookup)
91
- loader = get_manifest_loader()
92
- manifest = loader.get_manifest(self._package_name)
93
- if manifest:
94
- for import_name, pkg in manifest.dependencies.items():
95
- if pkg.lower() == package_name.lower():
96
- if import_name not in imports:
97
- imports.append(import_name)
98
-
99
- return imports if imports else [package_name]
100
-
@@ -1,105 +0,0 @@
1
- """
2
- Hybrid Mapping Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Hybrid mapping strategy - tries both manifest and discovery, uses best match.
11
- """
12
-
13
- from typing import Optional, List
14
- from ...package.base import AMappingStrategy
15
- from ...package.services.manifest import get_manifest_loader
16
-
17
- class HybridMapping(AMappingStrategy):
18
- """
19
- Hybrid mapping strategy.
20
-
21
- Tries both manifest and discovery, uses the best match.
22
- If both exist, prefers the one that's more specific.
23
- """
24
-
25
- def __init__(self, package_name: str = 'default'):
26
- """
27
- Initialize hybrid mapping strategy.
28
-
29
- Args:
30
- package_name: Package name for isolation
31
- """
32
- self._package_name = package_name
33
- self._discovery = None # Lazy init
34
-
35
- def _get_discovery(self):
36
- """Get discovery instance (lazy init)."""
37
- if self._discovery is None:
38
- from ...package.services.discovery import LazyDiscovery
39
- self._discovery = LazyDiscovery(self._package_name)
40
- return self._discovery
41
-
42
- def map_import_to_package(self, import_name: str) -> Optional[str]:
43
- """
44
- Map import name to package name.
45
-
46
- Tries both manifest and discovery, prefers more specific match.
47
-
48
- Args:
49
- import_name: Import name (e.g., 'cv2')
50
-
51
- Returns:
52
- Package name (e.g., 'opencv-python') or None
53
- """
54
- # Try manifest first
55
- loader = get_manifest_loader()
56
- manifest = loader.get_manifest(self._package_name)
57
- manifest_package = None
58
- if manifest:
59
- manifest_package = manifest.get_dependency(import_name)
60
-
61
- # Try discovery
62
- discovery = self._get_discovery()
63
- discovery_mapping = discovery.get_import_package_mapping()
64
- discovery_package = discovery_mapping.get(import_name)
65
-
66
- # Prefer manifest if both exist (more explicit)
67
- if manifest_package:
68
- return manifest_package
69
-
70
- if discovery_package:
71
- return discovery_package
72
-
73
- # Fallback to common mappings
74
- common_mappings = discovery.COMMON_MAPPINGS
75
- return common_mappings.get(import_name)
76
-
77
- def map_package_to_imports(self, package_name: str) -> List[str]:
78
- """
79
- Map package name to possible import names.
80
-
81
- Args:
82
- package_name: Package name (e.g., 'opencv-python')
83
-
84
- Returns:
85
- List of possible import names (e.g., ['cv2'])
86
- """
87
- imports = []
88
-
89
- # Check discovery mappings
90
- discovery = self._get_discovery()
91
- package_mapping = discovery.get_package_import_mapping()
92
- discovery_imports = package_mapping.get(package_name, [])
93
- imports.extend(discovery_imports)
94
-
95
- # Check manifest (reverse lookup)
96
- loader = get_manifest_loader()
97
- manifest = loader.get_manifest(self._package_name)
98
- if manifest:
99
- for import_name, pkg in manifest.dependencies.items():
100
- if pkg.lower() == package_name.lower():
101
- if import_name not in imports:
102
- imports.append(import_name)
103
-
104
- return imports if imports else [package_name]
105
-
@@ -1,100 +0,0 @@
1
- """
2
- Manifest-First Mapping Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Manifest-first mapping strategy - manifest takes precedence over discovery.
11
- """
12
-
13
- from typing import Optional, List
14
- from ...package.base import AMappingStrategy
15
- from ...package.services.manifest import get_manifest_loader
16
-
17
- class ManifestFirstMapping(AMappingStrategy):
18
- """
19
- Manifest-first mapping strategy.
20
-
21
- Priority order:
22
- 1. Manifest dependencies (explicit user configuration - highest priority)
23
- 2. Discovery mappings (automatic discovery)
24
- 3. Common mappings (fallback)
25
- """
26
-
27
- def __init__(self, package_name: str = 'default'):
28
- """
29
- Initialize manifest-first mapping strategy.
30
-
31
- Args:
32
- package_name: Package name for isolation
33
- """
34
- self._package_name = package_name
35
- self._discovery = None # Lazy init
36
-
37
- def _get_discovery(self):
38
- """Get discovery instance (lazy init)."""
39
- if self._discovery is None:
40
- from ...package.services.discovery import LazyDiscovery
41
- self._discovery = LazyDiscovery(self._package_name)
42
- return self._discovery
43
-
44
- def map_import_to_package(self, import_name: str) -> Optional[str]:
45
- """
46
- Map import name to package name.
47
-
48
- Priority: Manifest > Discovery > Common mappings
49
-
50
- Args:
51
- import_name: Import name (e.g., 'cv2')
52
-
53
- Returns:
54
- Package name (e.g., 'opencv-python') or None
55
- """
56
- # Check manifest FIRST - explicit user configuration takes precedence
57
- loader = get_manifest_loader()
58
- manifest = loader.get_manifest(self._package_name)
59
- if manifest:
60
- package = manifest.get_dependency(import_name)
61
- if package:
62
- return package
63
-
64
- # Check discovery mappings
65
- discovery = self._get_discovery()
66
- discovery_mapping = discovery.get_import_package_mapping()
67
- package = discovery_mapping.get(import_name)
68
- if package:
69
- return package
70
-
71
- # Fallback to common mappings
72
- common_mappings = discovery.COMMON_MAPPINGS
73
- return common_mappings.get(import_name)
74
-
75
- def map_package_to_imports(self, package_name: str) -> List[str]:
76
- """
77
- Map package name to possible import names.
78
-
79
- Args:
80
- package_name: Package name (e.g., 'opencv-python')
81
-
82
- Returns:
83
- List of possible import names (e.g., ['cv2'])
84
- """
85
- # Check discovery mappings
86
- discovery = self._get_discovery()
87
- package_mapping = discovery.get_package_import_mapping()
88
- imports = package_mapping.get(package_name, [])
89
-
90
- # Also check manifest (reverse lookup)
91
- loader = get_manifest_loader()
92
- manifest = loader.get_manifest(self._package_name)
93
- if manifest:
94
- for import_name, pkg in manifest.dependencies.items():
95
- if pkg.lower() == package_name.lower():
96
- if import_name not in imports:
97
- imports.append(import_name)
98
-
99
- return imports if imports else [package_name]
100
-
@@ -1,57 +0,0 @@
1
- """
2
- Allow List Policy Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Allow list policy - only allows packages in the allow list.
11
- """
12
-
13
- from typing import Tuple, List, Set
14
- from ...package.base import APolicyStrategy
15
-
16
- class AllowListPolicy(APolicyStrategy):
17
- """
18
- Allow list policy strategy - only allows packages in the allow list.
19
-
20
- Only packages explicitly in the allow list can be installed.
21
- """
22
-
23
- def __init__(self, allowed_packages: Set[str]):
24
- """
25
- Initialize allow list policy.
26
-
27
- Args:
28
- allowed_packages: Set of allowed package names
29
- """
30
- self._allowed = {pkg.lower() for pkg in allowed_packages}
31
-
32
- def is_allowed(self, package_name: str) -> Tuple[bool, str]:
33
- """
34
- Check if package is allowed to be installed.
35
-
36
- Args:
37
- package_name: Package name to check
38
-
39
- Returns:
40
- Tuple of (allowed: bool, reason: str)
41
- """
42
- if package_name.lower() in self._allowed:
43
- return (True, f"Package '{package_name}' is in allow list")
44
- return (False, f"Package '{package_name}' is not in allow list")
45
-
46
- def get_pip_args(self, package_name: str) -> List[str]:
47
- """
48
- Get pip arguments based on policy.
49
-
50
- Args:
51
- package_name: Package name
52
-
53
- Returns:
54
- List of pip arguments (empty for allow list policy)
55
- """
56
- return []
57
-
@@ -1,57 +0,0 @@
1
- """
2
- Deny List Policy Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Deny list policy - blocks packages in the deny list.
11
- """
12
-
13
- from typing import Tuple, List, Set
14
- from ...package.base import APolicyStrategy
15
-
16
- class DenyListPolicy(APolicyStrategy):
17
- """
18
- Deny list policy strategy - blocks packages in the deny list.
19
-
20
- Packages in the deny list cannot be installed.
21
- """
22
-
23
- def __init__(self, denied_packages: Set[str]):
24
- """
25
- Initialize deny list policy.
26
-
27
- Args:
28
- denied_packages: Set of denied package names
29
- """
30
- self._denied = {pkg.lower() for pkg in denied_packages}
31
-
32
- def is_allowed(self, package_name: str) -> Tuple[bool, str]:
33
- """
34
- Check if package is allowed to be installed.
35
-
36
- Args:
37
- package_name: Package name to check
38
-
39
- Returns:
40
- Tuple of (allowed: bool, reason: str)
41
- """
42
- if package_name.lower() in self._denied:
43
- return (False, f"Package '{package_name}' is in deny list")
44
- return (True, f"Package '{package_name}' is not in deny list")
45
-
46
- def get_pip_args(self, package_name: str) -> List[str]:
47
- """
48
- Get pip arguments based on policy.
49
-
50
- Args:
51
- package_name: Package name
52
-
53
- Returns:
54
- List of pip arguments (empty for deny list policy)
55
- """
56
- return []
57
-
@@ -1,46 +0,0 @@
1
- """
2
- Permissive Policy Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Permissive policy - allows all packages (default).
11
- """
12
-
13
- from typing import Tuple, List
14
- from ...package.base import APolicyStrategy
15
-
16
- class PermissivePolicy(APolicyStrategy):
17
- """
18
- Permissive policy strategy - allows all packages.
19
-
20
- This is the default policy that doesn't restrict any packages.
21
- """
22
-
23
- def is_allowed(self, package_name: str) -> Tuple[bool, str]:
24
- """
25
- Check if package is allowed to be installed.
26
-
27
- Args:
28
- package_name: Package name to check
29
-
30
- Returns:
31
- Tuple of (allowed: bool, reason: str)
32
- """
33
- return (True, "Permissive policy allows all packages")
34
-
35
- def get_pip_args(self, package_name: str) -> List[str]:
36
- """
37
- Get pip arguments based on policy.
38
-
39
- Args:
40
- package_name: Package name
41
-
42
- Returns:
43
- List of pip arguments (empty for permissive policy)
44
- """
45
- return []
46
-
@@ -1,67 +0,0 @@
1
- """
2
- Clean Timing Strategy
3
-
4
- Company: eXonware.com
5
- Author: Eng. Muhammad AlShehri
6
- Email: connect@exonware.com
7
-
8
- Generation Date: 15-Nov-2025
9
-
10
- Clean timing - install on usage + uninstall after completion.
11
- """
12
-
13
- from typing import List, Any
14
- from ...package.base import AInstallTimingStrategy
15
-
16
- class CleanTiming(AInstallTimingStrategy):
17
- """
18
- Clean timing strategy - installs on usage + uninstalls after completion (LazyInstallMode.CLEAN).
19
-
20
- Installs package when needed, then uninstalls after use to keep environment clean.
21
- """
22
-
23
- def should_install_now(self, package_name: str, context: Any) -> bool:
24
- """
25
- Determine if package should be installed now.
26
-
27
- Clean mode: Install when first needed.
28
-
29
- Args:
30
- package_name: Package name to check
31
- context: Context information (e.g., import error)
32
-
33
- Returns:
34
- True if should install now
35
- """
36
- # In clean mode, install when first needed
37
- return context is not None
38
-
39
- def should_uninstall_after(self, package_name: str, context: Any) -> bool:
40
- """
41
- Determine if package should be uninstalled after use.
42
-
43
- Clean mode: Uninstall after use.
44
-
45
- Args:
46
- package_name: Package name to check
47
- context: Context information
48
-
49
- Returns:
50
- True (uninstall after use)
51
- """
52
- return True
53
-
54
- def get_install_priority(self, packages: List[str]) -> List[str]:
55
- """
56
- Get priority order for installing packages.
57
-
58
- Clean mode: Install in order requested.
59
-
60
- Args:
61
- packages: List of package names
62
-
63
- Returns:
64
- Priority-ordered list
65
- """
66
- return packages
67
-