exonware-xwlazy 0.1.0.23__py3-none-any.whl → 1.0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. exonware/__init__.py +85 -34
  2. exonware/xwlazy/version.py +5 -5
  3. exonware/xwlazy.py +2546 -0
  4. exonware/xwlazy_external_libs.toml +716 -0
  5. {exonware_xwlazy-0.1.0.23.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/METADATA +5 -1
  6. exonware_xwlazy-1.0.1.2.dist-info/RECORD +8 -0
  7. exonware/xwlazy/__init__.py +0 -379
  8. exonware/xwlazy/common/__init__.py +0 -55
  9. exonware/xwlazy/common/base.py +0 -65
  10. exonware/xwlazy/common/cache.py +0 -504
  11. exonware/xwlazy/common/logger.py +0 -257
  12. exonware/xwlazy/common/services/__init__.py +0 -72
  13. exonware/xwlazy/common/services/dependency_mapper.py +0 -250
  14. exonware/xwlazy/common/services/install_async_utils.py +0 -170
  15. exonware/xwlazy/common/services/install_cache_utils.py +0 -245
  16. exonware/xwlazy/common/services/keyword_detection.py +0 -283
  17. exonware/xwlazy/common/services/spec_cache.py +0 -165
  18. exonware/xwlazy/common/services/state_manager.py +0 -84
  19. exonware/xwlazy/common/strategies/__init__.py +0 -28
  20. exonware/xwlazy/common/strategies/caching_dict.py +0 -44
  21. exonware/xwlazy/common/strategies/caching_installation.py +0 -88
  22. exonware/xwlazy/common/strategies/caching_lfu.py +0 -66
  23. exonware/xwlazy/common/strategies/caching_lru.py +0 -63
  24. exonware/xwlazy/common/strategies/caching_multitier.py +0 -59
  25. exonware/xwlazy/common/strategies/caching_ttl.py +0 -59
  26. exonware/xwlazy/common/utils.py +0 -142
  27. exonware/xwlazy/config.py +0 -193
  28. exonware/xwlazy/contracts.py +0 -1533
  29. exonware/xwlazy/defs.py +0 -378
  30. exonware/xwlazy/errors.py +0 -276
  31. exonware/xwlazy/facade.py +0 -1137
  32. exonware/xwlazy/host/__init__.py +0 -8
  33. exonware/xwlazy/host/conf.py +0 -16
  34. exonware/xwlazy/module/__init__.py +0 -18
  35. exonware/xwlazy/module/base.py +0 -622
  36. exonware/xwlazy/module/data.py +0 -17
  37. exonware/xwlazy/module/facade.py +0 -246
  38. exonware/xwlazy/module/importer_engine.py +0 -2964
  39. exonware/xwlazy/module/partial_module_detector.py +0 -275
  40. exonware/xwlazy/module/strategies/__init__.py +0 -22
  41. exonware/xwlazy/module/strategies/module_helper_lazy.py +0 -93
  42. exonware/xwlazy/module/strategies/module_helper_simple.py +0 -65
  43. exonware/xwlazy/module/strategies/module_manager_advanced.py +0 -111
  44. exonware/xwlazy/module/strategies/module_manager_simple.py +0 -95
  45. exonware/xwlazy/package/__init__.py +0 -18
  46. exonware/xwlazy/package/base.py +0 -863
  47. exonware/xwlazy/package/conf.py +0 -324
  48. exonware/xwlazy/package/data.py +0 -17
  49. exonware/xwlazy/package/facade.py +0 -480
  50. exonware/xwlazy/package/services/__init__.py +0 -84
  51. exonware/xwlazy/package/services/async_install_handle.py +0 -87
  52. exonware/xwlazy/package/services/config_manager.py +0 -249
  53. exonware/xwlazy/package/services/discovery.py +0 -435
  54. exonware/xwlazy/package/services/host_packages.py +0 -180
  55. exonware/xwlazy/package/services/install_async.py +0 -291
  56. exonware/xwlazy/package/services/install_cache.py +0 -145
  57. exonware/xwlazy/package/services/install_interactive.py +0 -59
  58. exonware/xwlazy/package/services/install_policy.py +0 -156
  59. exonware/xwlazy/package/services/install_registry.py +0 -54
  60. exonware/xwlazy/package/services/install_result.py +0 -17
  61. exonware/xwlazy/package/services/install_sbom.py +0 -153
  62. exonware/xwlazy/package/services/install_utils.py +0 -79
  63. exonware/xwlazy/package/services/installer_engine.py +0 -406
  64. exonware/xwlazy/package/services/lazy_installer.py +0 -803
  65. exonware/xwlazy/package/services/manifest.py +0 -503
  66. exonware/xwlazy/package/services/strategy_registry.py +0 -324
  67. exonware/xwlazy/package/strategies/__init__.py +0 -57
  68. exonware/xwlazy/package/strategies/package_discovery_file.py +0 -129
  69. exonware/xwlazy/package/strategies/package_discovery_hybrid.py +0 -84
  70. exonware/xwlazy/package/strategies/package_discovery_manifest.py +0 -101
  71. exonware/xwlazy/package/strategies/package_execution_async.py +0 -113
  72. exonware/xwlazy/package/strategies/package_execution_cached.py +0 -90
  73. exonware/xwlazy/package/strategies/package_execution_pip.py +0 -99
  74. exonware/xwlazy/package/strategies/package_execution_wheel.py +0 -106
  75. exonware/xwlazy/package/strategies/package_mapping_discovery_first.py +0 -100
  76. exonware/xwlazy/package/strategies/package_mapping_hybrid.py +0 -105
  77. exonware/xwlazy/package/strategies/package_mapping_manifest_first.py +0 -100
  78. exonware/xwlazy/package/strategies/package_policy_allow_list.py +0 -57
  79. exonware/xwlazy/package/strategies/package_policy_deny_list.py +0 -57
  80. exonware/xwlazy/package/strategies/package_policy_permissive.py +0 -46
  81. exonware/xwlazy/package/strategies/package_timing_clean.py +0 -67
  82. exonware/xwlazy/package/strategies/package_timing_full.py +0 -66
  83. exonware/xwlazy/package/strategies/package_timing_smart.py +0 -68
  84. exonware/xwlazy/package/strategies/package_timing_temporary.py +0 -66
  85. exonware/xwlazy/runtime/__init__.py +0 -18
  86. exonware/xwlazy/runtime/adaptive_learner.py +0 -129
  87. exonware/xwlazy/runtime/base.py +0 -274
  88. exonware/xwlazy/runtime/facade.py +0 -94
  89. exonware/xwlazy/runtime/intelligent_selector.py +0 -170
  90. exonware/xwlazy/runtime/metrics.py +0 -60
  91. exonware/xwlazy/runtime/performance.py +0 -37
  92. exonware_xwlazy-0.1.0.23.dist-info/RECORD +0 -93
  93. xwlazy/__init__.py +0 -14
  94. xwlazy/lazy.py +0 -30
  95. {exonware_xwlazy-0.1.0.23.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/WHEEL +0 -0
  96. {exonware_xwlazy-0.1.0.23.dist-info → exonware_xwlazy-1.0.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -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
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
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
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
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 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
-
@@ -1,66 +0,0 @@
1
- """
2
- Full 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
- Full timing - install all dependencies upfront.
11
- """
12
-
13
- from typing import Any
14
- from ...package.base import AInstallTimingStrategy
15
-
16
- class FullTiming(AInstallTimingStrategy):
17
- """
18
- Full timing strategy - installs all packages upfront (LazyInstallMode.FULL).
19
-
20
- Batch installs all dependencies in parallel on initialization.
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
- Full mode: Install all upfront.
28
-
29
- Args:
30
- package_name: Package name to check
31
- context: Context information (ignored in full mode)
32
-
33
- Returns:
34
- True (always install upfront)
35
- """
36
- return True
37
-
38
- def should_uninstall_after(self, package_name: str, context: Any) -> bool:
39
- """
40
- Determine if package should be uninstalled after use.
41
-
42
- Full mode: Keep installed after use.
43
-
44
- Args:
45
- package_name: Package name to check
46
- context: Context information
47
-
48
- Returns:
49
- False (keep installed)
50
- """
51
- return False
52
-
53
- def get_install_priority(self, packages: list[str]) -> list[str]:
54
- """
55
- Get priority order for installing packages.
56
-
57
- Full mode: Install all in parallel (no specific order).
58
-
59
- Args:
60
- packages: List of package names
61
-
62
- Returns:
63
- Priority-ordered list (original order)
64
- """
65
- return packages
66
-
@@ -1,68 +0,0 @@
1
- """
2
- Smart 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
- Smart timing - install on first usage (on-demand).
11
- """
12
-
13
- from typing import Any
14
- from ...package.base import AInstallTimingStrategy
15
- from ...defs import LazyInstallMode
16
-
17
- class SmartTiming(AInstallTimingStrategy):
18
- """
19
- Smart timing strategy - installs packages on-demand (LazyInstallMode.SMART).
20
-
21
- Installs package when first needed, then caches the result.
22
- """
23
-
24
- def should_install_now(self, package_name: str, context: Any) -> bool:
25
- """
26
- Determine if package should be installed now.
27
-
28
- Smart mode: Install when first needed.
29
-
30
- Args:
31
- package_name: Package name to check
32
- context: Context information (e.g., import error)
33
-
34
- Returns:
35
- True if should install now
36
- """
37
- # In smart mode, install when first needed (context indicates need)
38
- return context is not None
39
-
40
- def should_uninstall_after(self, package_name: str, context: Any) -> bool:
41
- """
42
- Determine if package should be uninstalled after use.
43
-
44
- Smart mode: Keep installed after use.
45
-
46
- Args:
47
- package_name: Package name to check
48
- context: Context information
49
-
50
- Returns:
51
- False (keep installed)
52
- """
53
- return False
54
-
55
- def get_install_priority(self, packages: list[str]) -> list[str]:
56
- """
57
- Get priority order for installing packages.
58
-
59
- Smart mode: Install in order requested.
60
-
61
- Args:
62
- packages: List of package names
63
-
64
- Returns:
65
- Priority-ordered list
66
- """
67
- return packages
68
-
@@ -1,66 +0,0 @@
1
- """
2
- Temporary 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
- Temporary timing - always uninstall after use (more aggressive than CLEAN).
11
- """
12
-
13
- from typing import Any
14
- from ...package.base import AInstallTimingStrategy
15
-
16
- class TemporaryTiming(AInstallTimingStrategy):
17
- """
18
- Temporary timing strategy - always uninstalls after use (LazyInstallMode.TEMPORARY).
19
-
20
- More aggressive than CLEAN - always uninstalls packages after use.
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
- Temporary 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
- return context is not None
37
-
38
- def should_uninstall_after(self, package_name: str, context: Any) -> bool:
39
- """
40
- Determine if package should be uninstalled after use.
41
-
42
- Temporary mode: Always uninstall after use.
43
-
44
- Args:
45
- package_name: Package name to check
46
- context: Context information (ignored)
47
-
48
- Returns:
49
- True (always uninstall)
50
- """
51
- return True
52
-
53
- def get_install_priority(self, packages: list[str]) -> list[str]:
54
- """
55
- Get priority order for installing packages.
56
-
57
- Temporary mode: Install in order requested.
58
-
59
- Args:
60
- packages: List of package names
61
-
62
- Returns:
63
- Priority-ordered list
64
- """
65
- return packages
66
-
@@ -1,18 +0,0 @@
1
- """
2
- Runtime Services Module
3
-
4
- This module provides concrete implementations for runtime services.
5
- Main facade: XWRuntimeHelper extends ARuntimeHelper
6
- """
7
-
8
- # Lazy imports to avoid circular dependencies
9
- def __getattr__(name: str):
10
- if name == 'XWRuntimeHelper':
11
- from .facade import XWRuntimeHelper
12
- return XWRuntimeHelper
13
- if name == 'XWRuntime': # Backward compatibility alias
14
- from .facade import XWRuntimeHelper
15
- return XWRuntimeHelper
16
- raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
17
-
18
- __all__ = ['XWRuntimeHelper', 'XWRuntime'] # XWRuntime is backward compatibility alias
@@ -1,129 +0,0 @@
1
- """
2
- #exonware/xwlazy/src/exonware/xwlazy/loading/adaptive_utils.py
3
-
4
- Adaptive learning utilities for pattern-based optimization.
5
-
6
- Company: eXonware.com
7
- Author: Eng. Muhammad AlShehri
8
- Email: connect@exonware.com
9
-
10
- Generation Date: 19-Nov-2025
11
-
12
- This module provides adaptive learning for ADAPTIVE mode.
13
- """
14
-
15
- import time
16
- import threading
17
- from typing import Optional
18
- from collections import defaultdict, deque
19
-
20
- # Logger not used in this module, removed to avoid circular dependency
21
-
22
- class AdaptiveLearner:
23
- """Learns import patterns and optimizes loading strategy."""
24
-
25
- def __init__(self, learning_window: int = 100, prediction_depth: int = 3):
26
- """
27
- Initialize adaptive learner.
28
-
29
- Args:
30
- learning_window: Number of imports to track for learning
31
- prediction_depth: Depth of sequence predictions
32
- """
33
- self._learning_window = learning_window
34
- self._prediction_depth = prediction_depth
35
- self._import_sequences: deque = deque(maxlen=learning_window)
36
- self._access_times: dict[str, list[float]] = defaultdict(list)
37
- self._import_chains: dict[str, dict[str, int]] = defaultdict(lambda: defaultdict(int))
38
- self._module_scores: dict[str, float] = {}
39
- self._lock = threading.RLock()
40
-
41
- def record_import(self, module_name: str, import_time: float) -> None:
42
- """Record an import event."""
43
- current_time = time.time()
44
-
45
- # Lock-free append to deque (thread-safe for appends)
46
- self._import_sequences.append((module_name, current_time, import_time))
47
-
48
- with self._lock:
49
- self._access_times[module_name].append(current_time)
50
-
51
- # Update import chains (what imports after what)
52
- if len(self._import_sequences) > 1:
53
- prev_name, _, _ = self._import_sequences[-2]
54
- self._import_chains[prev_name][module_name] += 1
55
-
56
- # Update module score (frequency * recency) - defer heavy computation
57
- if len(self._access_times[module_name]) % 5 == 0: # Update every 5th access
58
- self._update_module_score(module_name)
59
-
60
- def _update_module_score(self, module_name: str) -> None:
61
- """Update module priority score."""
62
- with self._lock:
63
- accesses = self._access_times[module_name]
64
- if not accesses:
65
- return
66
-
67
- # Frequency component
68
- recent_accesses = [t for t in accesses if time.time() - t < 3600] # Last hour
69
- frequency = len(recent_accesses)
70
-
71
- # Recency component (more recent = higher score)
72
- if accesses:
73
- last_access = accesses[-1]
74
- recency = 1.0 / (time.time() - last_access + 1.0)
75
- else:
76
- recency = 0.0
77
-
78
- # Chain component (if often imported after another module)
79
- chain_weight = sum(self._import_chains.get(prev, {}).get(module_name, 0)
80
- for prev in self._access_times.keys()) / max(len(self._import_sequences), 1)
81
-
82
- # Combined score
83
- self._module_scores[module_name] = frequency * 0.4 + recency * 1000 * 0.4 + chain_weight * 0.2
84
-
85
- def predict_next_imports(self, current_module: Optional[str] = None, limit: int = 5) -> list[str]:
86
- """Predict likely next imports based on patterns."""
87
- # Lock-free check first
88
- if not self._import_sequences:
89
- return []
90
-
91
- with self._lock:
92
- candidates: dict[str, float] = {}
93
-
94
- # Predict based on current module chain (lock-free read of dict)
95
- if current_module:
96
- chain_candidates = self._import_chains.get(current_module, {})
97
- for module, count in chain_candidates.items():
98
- candidates[module] = candidates.get(module, 0.0) + count * 2.0
99
-
100
- # Add high-scoring modules (lock-free read of dict)
101
- for module, score in self._module_scores.items():
102
- candidates[module] = candidates.get(module, 0.0) + score * 0.5
103
-
104
- # Sort by score
105
- sorted_candidates = sorted(candidates.items(), key=lambda x: x[1], reverse=True)
106
- return [module for module, _ in sorted_candidates[:limit]]
107
-
108
- def get_priority_modules(self, limit: int = 10) -> list[str]:
109
- """Get modules that should be preloaded based on scores."""
110
- with self._lock:
111
- sorted_modules = sorted(
112
- self._module_scores.items(),
113
- key=lambda x: x[1],
114
- reverse=True
115
- )
116
- return [module for module, _ in sorted_modules[:limit]]
117
-
118
- def get_stats(self) -> Dict:
119
- """Get learning statistics."""
120
- with self._lock:
121
- return {
122
- 'sequences_tracked': len(self._import_sequences),
123
- 'unique_modules': len(self._access_times),
124
- 'chains_tracked': sum(len(chains) for chains in self._import_chains.values()),
125
- 'top_modules': self.get_priority_modules(5),
126
- }
127
-
128
- __all__ = ['AdaptiveLearner']
129
-