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,57 +0,0 @@
1
- """
2
- Package Strategies
3
-
4
- All package strategy implementations.
5
- """
6
-
7
- # Mapping strategies
8
- from .package_mapping_manifest_first import ManifestFirstMapping
9
- from .package_mapping_discovery_first import DiscoveryFirstMapping
10
- from .package_mapping_hybrid import HybridMapping
11
-
12
- # Policy strategies
13
- from .package_policy_permissive import PermissivePolicy
14
- from .package_policy_allow_list import AllowListPolicy
15
- from .package_policy_deny_list import DenyListPolicy
16
-
17
- # Timing strategies
18
- from .package_timing_smart import SmartTiming
19
- from .package_timing_full import FullTiming
20
- from .package_timing_clean import CleanTiming
21
- from .package_timing_temporary import TemporaryTiming
22
-
23
- # Execution strategies
24
- from .package_execution_pip import PipExecution
25
- from .package_execution_wheel import WheelExecution
26
- from .package_execution_cached import CachedExecution
27
- from .package_execution_async import AsyncExecution
28
-
29
- # Discovery strategies
30
- from .package_discovery_file import FileBasedDiscovery
31
- from .package_discovery_manifest import ManifestBasedDiscovery
32
- from .package_discovery_hybrid import HybridDiscovery
33
-
34
- __all__ = [
35
- # Mapping strategies
36
- 'ManifestFirstMapping',
37
- 'DiscoveryFirstMapping',
38
- 'HybridMapping',
39
- # Policy strategies
40
- 'PermissivePolicy',
41
- 'AllowListPolicy',
42
- 'DenyListPolicy',
43
- # Timing strategies
44
- 'SmartTiming',
45
- 'FullTiming',
46
- 'CleanTiming',
47
- 'TemporaryTiming',
48
- # Execution strategies
49
- 'PipExecution',
50
- 'WheelExecution',
51
- 'CachedExecution',
52
- 'AsyncExecution',
53
- # Discovery strategies
54
- 'FileBasedDiscovery',
55
- 'ManifestBasedDiscovery',
56
- 'HybridDiscovery',
57
- ]
@@ -1,129 +0,0 @@
1
- """
2
- File-Based Discovery 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
- File-based discovery - discovers dependencies from project files.
11
- """
12
-
13
- from pathlib import Path
14
- from typing import Dict, Optional, Any
15
- from ...package.base import ADiscoveryStrategy
16
-
17
- class FileBasedDiscovery(ADiscoveryStrategy):
18
- """
19
- File-based discovery strategy - discovers dependencies from project files.
20
-
21
- Reads from pyproject.toml, requirements.txt, setup.py, etc.
22
- """
23
-
24
- def __init__(self, project_root: Optional[Path] = None):
25
- """
26
- Initialize file-based discovery strategy.
27
-
28
- Args:
29
- project_root: Project root directory (auto-detected if None)
30
- """
31
- self._project_root = project_root or self._detect_project_root()
32
-
33
- def _detect_project_root(self) -> Path:
34
- """Detect project root directory."""
35
- import os
36
- cwd = Path.cwd()
37
-
38
- # Look for common project markers
39
- markers = ['pyproject.toml', 'requirements.txt', 'setup.py', '.git']
40
- for marker in markers:
41
- current = cwd
42
- for _ in range(5): # Search up to 5 levels
43
- if (current / marker).exists():
44
- return current
45
- parent = current.parent
46
- if parent == current: # Reached filesystem root
47
- break
48
- current = parent
49
-
50
- return cwd
51
-
52
- def discover(self, project_root: Any = None) -> Dict[str, str]:
53
- """
54
- Discover dependencies from project files.
55
-
56
- Args:
57
- project_root: Optional project root (uses instance root if None)
58
-
59
- Returns:
60
- Dict mapping import_name -> package_name
61
- """
62
- root = Path(project_root) if project_root else self._project_root
63
- dependencies = {}
64
-
65
- # Check pyproject.toml
66
- pyproject = root / "pyproject.toml"
67
- if pyproject.exists():
68
- try:
69
- import tomllib
70
- except ImportError:
71
- try:
72
- import tomli as tomllib
73
- except ImportError:
74
- tomllib = None
75
-
76
- if tomllib:
77
- with open(pyproject, 'rb') as f:
78
- data = tomllib.load(f)
79
- project = data.get('project', {})
80
- deps = project.get('dependencies', [])
81
- for dep in deps:
82
- # Parse dependency spec (e.g., "pandas>=1.0" -> "pandas")
83
- package_name = dep.split('>=')[0].split('==')[0].split('!=')[0].strip()
84
- # Use package name as import name (heuristic)
85
- import_name = package_name.replace('-', '_')
86
- dependencies[import_name] = package_name
87
-
88
- # Check requirements.txt
89
- requirements = root / "requirements.txt"
90
- if requirements.exists():
91
- with open(requirements, 'r', encoding='utf-8') as f:
92
- for line in f:
93
- line = line.strip()
94
- if line and not line.startswith('#'):
95
- # Parse requirement (e.g., "pandas>=1.0" -> "pandas")
96
- package_name = line.split('>=')[0].split('==')[0].split('!=')[0].strip()
97
- import_name = package_name.replace('-', '_')
98
- dependencies[import_name] = package_name
99
-
100
- return dependencies
101
-
102
- def get_source(self, import_name: str) -> Optional[str]:
103
- """
104
- Get the source of a discovered dependency.
105
-
106
- Args:
107
- import_name: Import name to check
108
-
109
- Returns:
110
- Source file name or None
111
- """
112
- root = self._project_root
113
-
114
- # Check pyproject.toml
115
- pyproject = root / "pyproject.toml"
116
- if pyproject.exists():
117
- deps = self.discover()
118
- if import_name in deps:
119
- return "pyproject.toml"
120
-
121
- # Check requirements.txt
122
- requirements = root / "requirements.txt"
123
- if requirements.exists():
124
- deps = self.discover()
125
- if import_name in deps:
126
- return "requirements.txt"
127
-
128
- return None
129
-
@@ -1,84 +0,0 @@
1
- """
2
- Hybrid Discovery 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 discovery - combines file-based and manifest-based discovery.
11
- """
12
-
13
- from pathlib import Path
14
- from typing import Dict, Optional, Any
15
- from ...package.base import ADiscoveryStrategy
16
- from .package_discovery_file import FileBasedDiscovery
17
- from .package_discovery_manifest import ManifestBasedDiscovery
18
-
19
- class HybridDiscovery(ADiscoveryStrategy):
20
- """
21
- Hybrid discovery strategy - combines file-based and manifest-based discovery.
22
-
23
- Priority: Manifest > File-based
24
- """
25
-
26
- def __init__(self, package_name: str = 'default', project_root: Optional[Path] = None):
27
- """
28
- Initialize hybrid discovery strategy.
29
-
30
- Args:
31
- package_name: Package name for isolation
32
- project_root: Project root directory (auto-detected if None)
33
- """
34
- self._package_name = package_name
35
- self._project_root = project_root
36
- self._file_discovery = FileBasedDiscovery(project_root)
37
- self._manifest_discovery = ManifestBasedDiscovery(package_name, project_root)
38
-
39
- def discover(self, project_root: Any = None) -> Dict[str, str]:
40
- """
41
- Discover dependencies from all sources.
42
-
43
- Priority: Manifest > File-based
44
-
45
- Args:
46
- project_root: Optional project root (uses instance root if None)
47
-
48
- Returns:
49
- Dict mapping import_name -> package_name
50
- """
51
- dependencies = {}
52
-
53
- # First, get file-based dependencies
54
- file_deps = self._file_discovery.discover(project_root)
55
- dependencies.update(file_deps)
56
-
57
- # Then, overlay manifest dependencies (takes precedence)
58
- manifest_deps = self._manifest_discovery.discover(project_root)
59
- dependencies.update(manifest_deps) # Manifest overrides file-based
60
-
61
- return dependencies
62
-
63
- def get_source(self, import_name: str) -> Optional[str]:
64
- """
65
- Get the source of a discovered dependency.
66
-
67
- Args:
68
- import_name: Import name to check
69
-
70
- Returns:
71
- Source file name or "hybrid"
72
- """
73
- # Check manifest first (higher priority)
74
- manifest_source = self._manifest_discovery.get_source(import_name)
75
- if manifest_source:
76
- return manifest_source
77
-
78
- # Check file-based
79
- file_source = self._file_discovery.get_source(import_name)
80
- if file_source:
81
- return file_source
82
-
83
- return None
84
-
@@ -1,101 +0,0 @@
1
- """
2
- Manifest-Based Discovery 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-based discovery - discovers dependencies from manifest files.
11
- """
12
-
13
- from pathlib import Path
14
- from typing import Dict, Optional, Any
15
- from ...package.base import ADiscoveryStrategy
16
-
17
- class ManifestBasedDiscovery(ADiscoveryStrategy):
18
- """
19
- Manifest-based discovery strategy - discovers dependencies from manifest files.
20
-
21
- Reads from xwlazy.manifest.json or pyproject.toml [tool.xwlazy] section.
22
- """
23
-
24
- def __init__(self, package_name: str = 'default', project_root: Optional[Path] = None):
25
- """
26
- Initialize manifest-based discovery strategy.
27
-
28
- Args:
29
- package_name: Package name for isolation
30
- project_root: Project root directory (auto-detected if None)
31
- """
32
- self._package_name = package_name
33
- self._project_root = project_root or self._detect_project_root()
34
-
35
- def _detect_project_root(self) -> Path:
36
- """Detect project root directory."""
37
- import os
38
- cwd = Path.cwd()
39
-
40
- # Look for manifest files
41
- markers = ['xwlazy.manifest.json', 'lazy.manifest.json', '.xwlazy.manifest.json', 'pyproject.toml']
42
- for marker in markers:
43
- current = cwd
44
- for _ in range(5): # Search up to 5 levels
45
- if (current / marker).exists():
46
- return current
47
- parent = current.parent
48
- if parent == current: # Reached filesystem root
49
- break
50
- current = parent
51
-
52
- return cwd
53
-
54
- def discover(self, project_root: Any = None) -> Dict[str, str]:
55
- """
56
- Discover dependencies from manifest files.
57
-
58
- Args:
59
- project_root: Optional project root (uses instance root if None)
60
-
61
- Returns:
62
- Dict mapping import_name -> package_name
63
- """
64
- # Lazy import to avoid circular dependency
65
- from ...package.manifest import get_manifest_loader
66
-
67
- loader = get_manifest_loader()
68
- manifest = loader.get_manifest(self._package_name)
69
-
70
- if manifest and manifest.dependencies:
71
- return manifest.dependencies.copy()
72
-
73
- return {}
74
-
75
- def get_source(self, import_name: str) -> Optional[str]:
76
- """
77
- Get the source of a discovered dependency.
78
-
79
- Args:
80
- import_name: Import name to check
81
-
82
- Returns:
83
- Source file name (e.g., "xwlazy.manifest.json")
84
- """
85
- from ...package.manifest import get_manifest_loader
86
-
87
- loader = get_manifest_loader()
88
- manifest = loader.get_manifest(self._package_name)
89
-
90
- if manifest and manifest.dependencies and import_name in manifest.dependencies:
91
- # Try to find which file was used
92
- root = self._project_root
93
- for filename in ['xwlazy.manifest.json', 'lazy.manifest.json', '.xwlazy.manifest.json']:
94
- if (root / filename).exists():
95
- return filename
96
- # Check pyproject.toml
97
- if (root / "pyproject.toml").exists():
98
- return "pyproject.toml [tool.xwlazy]"
99
-
100
- return None
101
-
@@ -1,113 +0,0 @@
1
- """
2
- Async 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
- Async execution strategy - async pip install using asyncio.
11
- Uses shared utilities from common/services/install_async_utils.
12
- """
13
-
14
- import sys
15
- import asyncio
16
- import subprocess
17
- from typing import List, Any
18
- from ...package.base import AInstallExecutionStrategy
19
- from ...package.services.install_result import InstallResult, InstallStatus
20
- from ...common.services.install_async_utils import async_install_package
21
-
22
- class AsyncExecution(AInstallExecutionStrategy):
23
- """
24
- Async execution strategy - installs packages asynchronously using asyncio.
25
-
26
- Uses asyncio subprocess for non-blocking installation.
27
- Uses shared utilities from common/services/install_async_utils.
28
- """
29
-
30
- def execute_install(self, package_name: str, policy_args: List[str]) -> Any:
31
- """
32
- Execute installation asynchronously.
33
-
34
- Note: This is a synchronous wrapper that runs async code.
35
- For true async, use the async methods directly.
36
-
37
- Args:
38
- package_name: Package name to install
39
- policy_args: Policy arguments
40
-
41
- Returns:
42
- InstallResult with success status
43
- """
44
- try:
45
- # Run async install in event loop
46
- loop = asyncio.get_event_loop()
47
- if loop.is_running():
48
- # If loop is running, use run_coroutine_threadsafe
49
- future = asyncio.run_coroutine_threadsafe(
50
- self._async_install(package_name, policy_args),
51
- loop
52
- )
53
- return future.result(timeout=600) # 10 min timeout
54
- else:
55
- # If no loop running, use asyncio.run
56
- return asyncio.run(self._async_install(package_name, policy_args))
57
- except Exception as e:
58
- return InstallResult(
59
- package_name=package_name,
60
- success=False,
61
- status=InstallStatus.FAILED,
62
- error=str(e)
63
- )
64
-
65
- async def _async_install(self, package_name: str, policy_args: List[str]) -> InstallResult:
66
- """
67
- Async installation implementation.
68
-
69
- Args:
70
- package_name: Package name to install
71
- policy_args: Policy arguments
72
-
73
- Returns:
74
- InstallResult with success status
75
- """
76
- success, error_msg = await async_install_package(package_name, policy_args)
77
-
78
- if success:
79
- return InstallResult(
80
- package_name=package_name,
81
- success=True,
82
- status=InstallStatus.SUCCESS,
83
- source="pip-async"
84
- )
85
- else:
86
- return InstallResult(
87
- package_name=package_name,
88
- success=False,
89
- status=InstallStatus.FAILED,
90
- error=error_msg or "Unknown error"
91
- )
92
-
93
- def execute_uninstall(self, package_name: str) -> bool:
94
- """
95
- Execute uninstallation using pip.
96
-
97
- Args:
98
- package_name: Package name to uninstall
99
-
100
- Returns:
101
- True if successful, False otherwise
102
- """
103
- try:
104
- result = subprocess.run(
105
- [sys.executable, '-m', 'pip', 'uninstall', '-y', package_name],
106
- capture_output=True,
107
- text=True,
108
- check=True
109
- )
110
- return result.returncode == 0
111
- except Exception:
112
- return False
113
-
@@ -1,90 +0,0 @@
1
- """
2
- Cached 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
- Cached execution strategy - install from cached tree.
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_cache_dir,
22
- install_from_cached_tree,
23
- )
24
-
25
- class CachedExecution(AInstallExecutionStrategy):
26
- """
27
- Cached execution strategy - installs packages from cached installation tree.
28
-
29
- Fastest installation method - copies from pre-extracted cache.
30
- Uses shared utilities from common/services/install_cache_utils.
31
- """
32
-
33
- def __init__(self, cache_dir: Optional[Path] = None):
34
- """
35
- Initialize cached execution strategy.
36
-
37
- Args:
38
- cache_dir: Optional cache directory for installation trees
39
- """
40
- self._cache_dir = cache_dir
41
-
42
- def execute_install(self, package_name: str, policy_args: List[str]) -> Any:
43
- """
44
- Execute installation from cached tree.
45
-
46
- Args:
47
- package_name: Package name to install
48
- policy_args: Policy arguments (ignored for cached install)
49
-
50
- Returns:
51
- InstallResult with success status
52
- """
53
- success = install_from_cached_tree(package_name, self._cache_dir)
54
-
55
- if success:
56
- return InstallResult(
57
- package_name=package_name,
58
- success=True,
59
- status=InstallStatus.SUCCESS,
60
- source="cache-tree"
61
- )
62
- else:
63
- return InstallResult(
64
- package_name=package_name,
65
- success=False,
66
- status=InstallStatus.FAILED,
67
- error="Cached installation tree not found"
68
- )
69
-
70
- def execute_uninstall(self, package_name: str) -> bool:
71
- """
72
- Execute uninstallation using pip.
73
-
74
- Args:
75
- package_name: Package name to uninstall
76
-
77
- Returns:
78
- True if successful, False otherwise
79
- """
80
- try:
81
- result = subprocess.run(
82
- [sys.executable, '-m', 'pip', 'uninstall', '-y', package_name],
83
- capture_output=True,
84
- text=True,
85
- check=True
86
- )
87
- return result.returncode == 0
88
- except Exception:
89
- return False
90
-
@@ -1,99 +0,0 @@
1
- """
2
- Pip 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
- Pip execution strategy - direct pip install.
11
- """
12
-
13
- import sys
14
- import subprocess
15
- from typing import List, Any
16
- from ...package.base import AInstallExecutionStrategy
17
- from ...package.services.install_result import InstallResult, InstallStatus
18
-
19
- class PipExecution(AInstallExecutionStrategy):
20
- """
21
- Pip execution strategy - installs packages directly using pip.
22
-
23
- This is the default execution strategy that uses pip install.
24
- """
25
-
26
- def execute_install(self, package_name: str, policy_args: List[str]) -> Any:
27
- """
28
- Execute installation using pip.
29
-
30
- Args:
31
- package_name: Package name to install
32
- policy_args: Policy arguments (index URLs, trusted hosts, etc.)
33
-
34
- Returns:
35
- InstallResult with success status
36
- """
37
- try:
38
- pip_args = [sys.executable, '-m', 'pip', 'install']
39
- if policy_args:
40
- pip_args.extend(policy_args)
41
- pip_args.append(package_name)
42
-
43
- result = subprocess.run(
44
- pip_args,
45
- capture_output=True,
46
- text=True,
47
- check=True
48
- )
49
-
50
- if result.returncode == 0:
51
- return InstallResult(
52
- package_name=package_name,
53
- success=True,
54
- status=InstallStatus.SUCCESS,
55
- source="pip"
56
- )
57
- else:
58
- return InstallResult(
59
- package_name=package_name,
60
- success=False,
61
- status=InstallStatus.FAILED,
62
- error=result.stderr or "Unknown error"
63
- )
64
- except subprocess.CalledProcessError as e:
65
- return InstallResult(
66
- package_name=package_name,
67
- success=False,
68
- status=InstallStatus.FAILED,
69
- error=e.stderr or str(e)
70
- )
71
- except Exception as e:
72
- return InstallResult(
73
- package_name=package_name,
74
- success=False,
75
- status=InstallStatus.FAILED,
76
- error=str(e)
77
- )
78
-
79
- def execute_uninstall(self, package_name: str) -> bool:
80
- """
81
- Execute uninstallation using pip.
82
-
83
- Args:
84
- package_name: Package name to uninstall
85
-
86
- Returns:
87
- True if successful, False otherwise
88
- """
89
- try:
90
- result = subprocess.run(
91
- [sys.executable, '-m', 'pip', 'uninstall', '-y', package_name],
92
- capture_output=True,
93
- text=True,
94
- check=True
95
- )
96
- return result.returncode == 0
97
- except Exception:
98
- return False
99
-