pybinaryguard 1.0.0__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 (91) hide show
  1. pybinaryguard/__init__.py +78 -0
  2. pybinaryguard/__main__.py +7 -0
  3. pybinaryguard/_compat/__init__.py +0 -0
  4. pybinaryguard/agent/__init__.py +63 -0
  5. pybinaryguard/agent/guard.py +232 -0
  6. pybinaryguard/agent/recommender.py +283 -0
  7. pybinaryguard/agent/schema.py +200 -0
  8. pybinaryguard/agent/simulator.py +430 -0
  9. pybinaryguard/agent/tool_interface.py +474 -0
  10. pybinaryguard/analyzers/__init__.py +209 -0
  11. pybinaryguard/analyzers/base.py +40 -0
  12. pybinaryguard/analyzers/dependency_analyzer.py +336 -0
  13. pybinaryguard/analyzers/elf_analyzer.py +754 -0
  14. pybinaryguard/analyzers/symbol_analyzer.py +280 -0
  15. pybinaryguard/analyzers/wheel_analyzer.py +308 -0
  16. pybinaryguard/cli/__init__.py +5 -0
  17. pybinaryguard/cli/commands.py +414 -0
  18. pybinaryguard/cli/formatters.py +720 -0
  19. pybinaryguard/cli/main.py +250 -0
  20. pybinaryguard/diagnostics/__init__.py +13 -0
  21. pybinaryguard/diagnostics/explainer.py +356 -0
  22. pybinaryguard/diagnostics/findings.py +146 -0
  23. pybinaryguard/diagnostics/suggestions.py +508 -0
  24. pybinaryguard/frameworks/__init__.py +20 -0
  25. pybinaryguard/frameworks/onnxruntime.py +214 -0
  26. pybinaryguard/frameworks/pytorch.py +223 -0
  27. pybinaryguard/frameworks/tensorflow.py +266 -0
  28. pybinaryguard/frameworks/tensorrt.py +189 -0
  29. pybinaryguard/models/__init__.py +19 -0
  30. pybinaryguard/models/enums.py +102 -0
  31. pybinaryguard/models/finding.py +109 -0
  32. pybinaryguard/models/package.py +121 -0
  33. pybinaryguard/models/system.py +118 -0
  34. pybinaryguard/plugins/__init__.py +19 -0
  35. pybinaryguard/plugins/contrib/__init__.py +7 -0
  36. pybinaryguard/plugins/contrib/gstreamer.py +109 -0
  37. pybinaryguard/plugins/contrib/jetson.py +385 -0
  38. pybinaryguard/plugins/contrib/opencv.py +306 -0
  39. pybinaryguard/plugins/contrib/tensorrt.py +426 -0
  40. pybinaryguard/plugins/hooks.py +273 -0
  41. pybinaryguard/plugins/loader.py +190 -0
  42. pybinaryguard/predictor/__init__.py +23 -0
  43. pybinaryguard/predictor/dependency_graph.py +226 -0
  44. pybinaryguard/predictor/linker_simulator.py +161 -0
  45. pybinaryguard/predictor/predictor.py +144 -0
  46. pybinaryguard/predictor/resolver.py +282 -0
  47. pybinaryguard/probes/__init__.py +73 -0
  48. pybinaryguard/probes/base.py +45 -0
  49. pybinaryguard/probes/board_probe.py +248 -0
  50. pybinaryguard/probes/cpu_probe.py +176 -0
  51. pybinaryguard/probes/glibc_probe.py +215 -0
  52. pybinaryguard/probes/gpu_probe.py +430 -0
  53. pybinaryguard/probes/library_probe.py +132 -0
  54. pybinaryguard/probes/os_probe.py +227 -0
  55. pybinaryguard/probes/python_probe.py +135 -0
  56. pybinaryguard/probes/toolchain_probe.py +89 -0
  57. pybinaryguard/probes/venv_probe.py +111 -0
  58. pybinaryguard/profiles/__init__.py +12 -0
  59. pybinaryguard/profiles/engine.py +343 -0
  60. pybinaryguard/rules/__init__.py +24 -0
  61. pybinaryguard/rules/base.py +57 -0
  62. pybinaryguard/rules/builtin/__init__.py +136 -0
  63. pybinaryguard/rules/builtin/arch_rules.py +86 -0
  64. pybinaryguard/rules/builtin/board_profile_rules.py +282 -0
  65. pybinaryguard/rules/builtin/container_rules.py +170 -0
  66. pybinaryguard/rules/builtin/cpu_rules.py +204 -0
  67. pybinaryguard/rules/builtin/cuda_rules.py +760 -0
  68. pybinaryguard/rules/builtin/dependency_rules.py +278 -0
  69. pybinaryguard/rules/builtin/framework_rules.py +252 -0
  70. pybinaryguard/rules/builtin/glibc_rules.py +320 -0
  71. pybinaryguard/rules/builtin/numpy_rules.py +110 -0
  72. pybinaryguard/rules/builtin/predictive_rules.py +165 -0
  73. pybinaryguard/rules/builtin/python_abi_rules.py +259 -0
  74. pybinaryguard/rules/builtin/source_build_rules.py +150 -0
  75. pybinaryguard/rules/builtin/venv_rules.py +159 -0
  76. pybinaryguard/rules/engine.py +123 -0
  77. pybinaryguard/scanner.py +904 -0
  78. pybinaryguard/scoring/__init__.py +19 -0
  79. pybinaryguard/scoring/engine.py +416 -0
  80. pybinaryguard/snapshot/__init__.py +20 -0
  81. pybinaryguard/snapshot/generator.py +168 -0
  82. pybinaryguard/snapshot/lockfile.py +152 -0
  83. pybinaryguard/snapshot/verifier.py +315 -0
  84. pybinaryguard/validators/__init__.py +7 -0
  85. pybinaryguard/validators/import_validator.py +231 -0
  86. pybinaryguard-1.0.0.dist-info/METADATA +876 -0
  87. pybinaryguard-1.0.0.dist-info/RECORD +91 -0
  88. pybinaryguard-1.0.0.dist-info/WHEEL +5 -0
  89. pybinaryguard-1.0.0.dist-info/entry_points.txt +8 -0
  90. pybinaryguard-1.0.0.dist-info/licenses/LICENSE +21 -0
  91. pybinaryguard-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,214 @@
1
+ """ONNX Runtime framework deep inspection.
2
+
3
+ Validates ONNX Runtime execution providers, version compatibility,
4
+ and hardware acceleration support.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+ from typing import Dict, List, Optional, Set
11
+
12
+ from pybinaryguard.models.package import PackageBinaryInfo
13
+ from pybinaryguard.models.system import SystemProfile
14
+
15
+
16
+ def check_onnx_runtime_providers(
17
+ package: PackageBinaryInfo,
18
+ profile: SystemProfile
19
+ ) -> List[Dict[str, str]]:
20
+ """Check ONNX Runtime execution providers and compatibility.
21
+
22
+ Validates:
23
+ - Available execution providers (CUDA, TensorRT, OpenVINO, etc.)
24
+ - CUDA provider compatibility with system
25
+ - Missing hardware-specific providers
26
+
27
+ Args:
28
+ package: PackageBinaryInfo for onnxruntime package
29
+ profile: System profile
30
+
31
+ Returns:
32
+ List of compatibility issues and recommendations
33
+ """
34
+ issues: List[Dict[str, str]] = []
35
+
36
+ if not package.name.lower().startswith("onnxruntime"):
37
+ return issues
38
+
39
+ # Detect available execution providers
40
+ providers = detect_execution_providers(package)
41
+
42
+ # Check if GPU package on GPU system
43
+ has_gpu = profile.cuda_runtime_version is not None
44
+ has_cuda_provider = "CUDAExecutionProvider" in providers
45
+
46
+ if has_gpu and not has_cuda_provider:
47
+ issues.append({
48
+ "issue": "missing_cuda_provider",
49
+ "severity": "warning",
50
+ "message": "NVIDIA GPU detected but CUDA execution provider not available",
51
+ "recommendation": "Install onnxruntime-gpu instead of onnxruntime for GPU acceleration",
52
+ })
53
+
54
+ if has_cuda_provider and not has_gpu:
55
+ issues.append({
56
+ "issue": "cuda_provider_no_gpu",
57
+ "severity": "info",
58
+ "message": "CUDA execution provider available but no NVIDIA GPU detected",
59
+ "recommendation": "Install onnxruntime (CPU) to reduce package size",
60
+ })
61
+
62
+ # Check CUDA provider version compatibility
63
+ if has_cuda_provider and profile.cuda_runtime_version:
64
+ cuda_compat_issues = check_onnx_cuda_compatibility(
65
+ package.version,
66
+ profile.cuda_runtime_version
67
+ )
68
+ if cuda_compat_issues:
69
+ issues.append({
70
+ "issue": "onnx_cuda_version_mismatch",
71
+ "severity": "warning",
72
+ "message": cuda_compat_issues,
73
+ "recommendation": "Check ONNX Runtime CUDA compatibility matrix",
74
+ })
75
+
76
+ # Check for TensorRT provider on Jetson
77
+ if profile.board_name and "jetson" in profile.board_name.lower():
78
+ if "TensorrtExecutionProvider" not in providers:
79
+ issues.append({
80
+ "issue": "missing_tensorrt_provider_jetson",
81
+ "severity": "info",
82
+ "message": "TensorRT execution provider not detected on Jetson device",
83
+ "recommendation": "Build ONNX Runtime with TensorRT support for optimal performance",
84
+ })
85
+
86
+ return issues
87
+
88
+
89
+ def detect_execution_providers(package: PackageBinaryInfo) -> Set[str]:
90
+ """Detect available ONNX Runtime execution providers.
91
+
92
+ Args:
93
+ package: PackageBinaryInfo for onnxruntime package
94
+
95
+ Returns:
96
+ Set of detected execution provider names
97
+ """
98
+ providers: Set[str] = set()
99
+
100
+ # Always has CPU provider
101
+ providers.add("CPUExecutionProvider")
102
+
103
+ for so in package.shared_objects:
104
+ if not so.path:
105
+ continue
106
+
107
+ path_lower = so.path.lower()
108
+
109
+ # CUDA provider
110
+ if "cuda" in path_lower:
111
+ providers.add("CUDAExecutionProvider")
112
+
113
+ # TensorRT provider
114
+ if "tensorrt" in path_lower:
115
+ providers.add("TensorrtExecutionProvider")
116
+
117
+ # OpenVINO provider
118
+ if "openvino" in path_lower:
119
+ providers.add("OpenVINOExecutionProvider")
120
+
121
+ # DirectML provider (Windows)
122
+ if "directml" in path_lower:
123
+ providers.add("DmlExecutionProvider")
124
+
125
+ # CoreML provider (macOS)
126
+ if "coreml" in path_lower:
127
+ providers.add("CoreMLExecutionProvider")
128
+
129
+ return providers
130
+
131
+
132
+ def check_onnx_cuda_compatibility(
133
+ onnx_version: Optional[str],
134
+ cuda_version: Optional[str]
135
+ ) -> Optional[str]:
136
+ """Check ONNX Runtime GPU version compatibility with CUDA.
137
+
138
+ Args:
139
+ onnx_version: ONNX Runtime version (e.g., "1.16.0")
140
+ cuda_version: CUDA version (e.g., "12.1")
141
+
142
+ Returns:
143
+ Error message if incompatible, None if compatible
144
+ """
145
+ if not onnx_version or not cuda_version:
146
+ return None
147
+
148
+ # Compatibility matrix (ONNX Runtime -> CUDA versions)
149
+ compatibility_matrix = {
150
+ "1.16": ["11.8", "12.2"],
151
+ "1.15": ["11.8", "12.1"],
152
+ "1.14": ["11.6", "11.7", "11.8"],
153
+ "1.13": ["11.6", "11.7"],
154
+ "1.12": ["11.4", "11.6"],
155
+ "1.11": ["11.4"],
156
+ }
157
+
158
+ try:
159
+ onnx_major_minor = ".".join(onnx_version.split(".")[:2])
160
+ cuda_major_minor = ".".join(cuda_version.split(".")[:2])
161
+
162
+ supported_cuda = compatibility_matrix.get(onnx_major_minor, [])
163
+
164
+ if supported_cuda and cuda_major_minor not in supported_cuda:
165
+ return (
166
+ f"ONNX Runtime {onnx_major_minor} supports CUDA {', '.join(supported_cuda)}, "
167
+ f"but system has CUDA {cuda_version}"
168
+ )
169
+ except (ValueError, IndexError):
170
+ pass
171
+
172
+ return None
173
+
174
+
175
+ def check_onnx_opset_compatibility(
176
+ model_opset: int,
177
+ onnxruntime_version: Optional[str]
178
+ ) -> Optional[str]:
179
+ """Check if ONNX model opset is supported by ONNX Runtime version.
180
+
181
+ Args:
182
+ model_opset: ONNX model opset version
183
+ onnxruntime_version: ONNX Runtime version
184
+
185
+ Returns:
186
+ Error message if incompatible, None if compatible
187
+ """
188
+ if not onnxruntime_version:
189
+ return None
190
+
191
+ # Maximum supported opset by ONNX Runtime version
192
+ max_opset_by_version = {
193
+ "1.16": 19,
194
+ "1.15": 18,
195
+ "1.14": 18,
196
+ "1.13": 17,
197
+ "1.12": 16,
198
+ "1.11": 15,
199
+ "1.10": 15,
200
+ }
201
+
202
+ try:
203
+ ort_major_minor = ".".join(onnxruntime_version.split(".")[:2])
204
+ max_opset = max_opset_by_version.get(ort_major_minor, 19)
205
+
206
+ if model_opset > max_opset:
207
+ return (
208
+ f"Model requires ONNX opset {model_opset}, "
209
+ f"but ONNX Runtime {ort_major_minor} only supports up to opset {max_opset}"
210
+ )
211
+ except (ValueError, IndexError):
212
+ pass
213
+
214
+ return None
@@ -0,0 +1,223 @@
1
+ """PyTorch framework deep inspection.
2
+
3
+ Validates PyTorch CUDA ABI compatibility, build configuration, and
4
+ version-specific requirements beyond generic binary checks.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+ from typing import Dict, List, Optional, Tuple
11
+
12
+ from pybinaryguard.models.package import PackageBinaryInfo
13
+ from pybinaryguard.models.system import SystemProfile
14
+
15
+
16
+ def detect_pytorch_build(package: PackageBinaryInfo) -> Dict[str, Optional[str]]:
17
+ """Detect PyTorch build configuration from binary metadata.
18
+
19
+ Args:
20
+ package: PackageBinaryInfo for torch package
21
+
22
+ Returns:
23
+ Dictionary with detected build info:
24
+ - cuda_version: CUDA version (e.g., "11.8", "12.1")
25
+ - cxx11_abi: C++11 ABI status ("enabled", "disabled", "unknown")
26
+ - cpu_only: Whether this is CPU-only build
27
+ - rocm_version: ROCm version if AMD build
28
+ """
29
+ result: Dict[str, Optional[str]] = {
30
+ "cuda_version": None,
31
+ "cxx11_abi": None,
32
+ "cpu_only": False,
33
+ "rocm_version": None,
34
+ }
35
+
36
+ # Check package CUDA version from metadata
37
+ if package.cuda_version:
38
+ result["cuda_version"] = package.cuda_version
39
+
40
+ # Check for CPU-only build from package name patterns
41
+ if any(so.path and "cpu" in so.path.lower() for so in package.shared_objects):
42
+ result["cpu_only"] = True
43
+
44
+ # Check for ROCm (AMD GPU) build
45
+ for so in package.shared_objects:
46
+ if so.path and "rocm" in so.path.lower():
47
+ # Try to extract ROCm version
48
+ match = re.search(r"rocm[_-]?(\d+\.\d+)", so.path.lower())
49
+ if match:
50
+ result["rocm_version"] = match.group(1)
51
+
52
+ # Detect C++11 ABI from GLIBCXX symbols
53
+ # PyTorch with new ABI uses GLIBCXX_3.4.21+, old ABI uses GLIBCXX_3.4.19
54
+ max_glibcxx = None
55
+ for so in package.shared_objects:
56
+ for symbol in so.symbols:
57
+ if symbol.startswith("GLIBCXX_3.4."):
58
+ version_str = symbol.replace("GLIBCXX_3.4.", "")
59
+ try:
60
+ version_num = int(version_str)
61
+ if max_glibcxx is None or version_num > max_glibcxx:
62
+ max_glibcxx = version_num
63
+ except ValueError:
64
+ continue
65
+
66
+ if max_glibcxx is not None:
67
+ # GLIBCXX >= 3.4.21 indicates C++11 ABI
68
+ result["cxx11_abi"] = "enabled" if max_glibcxx >= 21 else "disabled"
69
+ else:
70
+ result["cxx11_abi"] = "unknown"
71
+
72
+ return result
73
+
74
+
75
+ def check_pytorch_cuda_abi(
76
+ package: PackageBinaryInfo,
77
+ profile: SystemProfile
78
+ ) -> List[Dict[str, str]]:
79
+ """Check PyTorch CUDA ABI compatibility.
80
+
81
+ Validates:
82
+ - CUDA version matches system runtime
83
+ - C++11 ABI compatibility with system
84
+ - Compute capability support
85
+ - cuDNN version requirements
86
+
87
+ Args:
88
+ package: PackageBinaryInfo for torch package
89
+ profile: System profile
90
+
91
+ Returns:
92
+ List of compatibility issues found
93
+ """
94
+ issues: List[Dict[str, str]] = []
95
+
96
+ if package.name.lower() != "torch":
97
+ return issues
98
+
99
+ build_info = detect_pytorch_build(package)
100
+
101
+ # Check CUDA version compatibility
102
+ if build_info["cuda_version"] and profile.cuda_runtime_version:
103
+ pkg_cuda_major = int(build_info["cuda_version"].split(".")[0])
104
+ sys_cuda_major = int(profile.cuda_runtime_version.split(".")[0])
105
+
106
+ if pkg_cuda_major != sys_cuda_major:
107
+ issues.append({
108
+ "issue": "cuda_major_mismatch",
109
+ "severity": "critical",
110
+ "message": (
111
+ f"PyTorch built for CUDA {build_info['cuda_version']} but "
112
+ f"system has CUDA {profile.cuda_runtime_version}"
113
+ ),
114
+ "recommendation": f"Install PyTorch built for CUDA {sys_cuda_major}.x",
115
+ })
116
+
117
+ # Check for CPU-only PyTorch on GPU system
118
+ if build_info["cpu_only"] and profile.cuda_runtime_version:
119
+ issues.append({
120
+ "issue": "cpu_build_on_gpu_system",
121
+ "severity": "warning",
122
+ "message": "CPU-only PyTorch detected on system with NVIDIA GPU",
123
+ "recommendation": "Install GPU-enabled PyTorch to utilize available hardware",
124
+ })
125
+
126
+ # Check compute capability for PyTorch 2.x
127
+ if package.version and package.version.startswith("2."):
128
+ if profile.cuda_compute_capability:
129
+ compute_major = int(profile.cuda_compute_capability.split(".")[0])
130
+ # PyTorch 2.x requires compute capability >= 3.5
131
+ if compute_major < 3 or (compute_major == 3 and int(profile.cuda_compute_capability.split(".")[1]) < 5):
132
+ issues.append({
133
+ "issue": "compute_capability_too_low",
134
+ "severity": "critical",
135
+ "message": (
136
+ f"PyTorch 2.x requires compute capability >= 3.5, "
137
+ f"but GPU has {profile.cuda_compute_capability}"
138
+ ),
139
+ "recommendation": "Downgrade to PyTorch 1.x or upgrade GPU hardware",
140
+ })
141
+
142
+ # Check C++11 ABI compatibility
143
+ if build_info["cxx11_abi"] == "disabled":
144
+ issues.append({
145
+ "issue": "old_cxx11_abi",
146
+ "severity": "info",
147
+ "message": "PyTorch built with old C++11 ABI (pre-GCC 5.1)",
148
+ "recommendation": (
149
+ "Consider rebuilding extensions with _GLIBCXX_USE_CXX11_ABI=0 "
150
+ "if encountering symbol errors"
151
+ ),
152
+ })
153
+
154
+ return issues
155
+
156
+
157
+ def check_pytorch_torchvision_compatibility(
158
+ torch_version: Optional[str],
159
+ torchvision_version: Optional[str]
160
+ ) -> Optional[str]:
161
+ """Check if torchvision version is compatible with torch version.
162
+
163
+ Args:
164
+ torch_version: PyTorch version (e.g., "2.1.0")
165
+ torchvision_version: torchvision version (e.g., "0.16.0")
166
+
167
+ Returns:
168
+ Error message if incompatible, None if compatible
169
+ """
170
+ if not torch_version or not torchvision_version:
171
+ return None
172
+
173
+ # Compatibility matrix (PyTorch -> torchvision major.minor)
174
+ compatibility_matrix = {
175
+ "2.2": "0.17",
176
+ "2.1": "0.16",
177
+ "2.0": "0.15",
178
+ "1.13": "0.14",
179
+ "1.12": "0.13",
180
+ "1.11": "0.12",
181
+ "1.10": "0.11",
182
+ }
183
+
184
+ try:
185
+ torch_major_minor = ".".join(torch_version.split(".")[:2])
186
+ torchvision_major_minor = ".".join(torchvision_version.split(".")[:2])
187
+
188
+ expected_torchvision = compatibility_matrix.get(torch_major_minor)
189
+ if expected_torchvision and torchvision_major_minor != expected_torchvision:
190
+ return (
191
+ f"PyTorch {torch_major_minor} expects torchvision {expected_torchvision}.x, "
192
+ f"but found {torchvision_version}"
193
+ )
194
+ except (ValueError, IndexError):
195
+ pass
196
+
197
+ return None
198
+
199
+
200
+ def detect_pytorch_distributed_backend(package: PackageBinaryInfo) -> List[str]:
201
+ """Detect available distributed training backends in PyTorch.
202
+
203
+ Args:
204
+ package: PackageBinaryInfo for torch package
205
+
206
+ Returns:
207
+ List of available backends: ["nccl", "gloo", "mpi"]
208
+ """
209
+ backends = []
210
+
211
+ for so in package.shared_objects:
212
+ if not so.path:
213
+ continue
214
+
215
+ path_lower = so.path.lower()
216
+ if "nccl" in path_lower:
217
+ backends.append("nccl")
218
+ elif "gloo" in path_lower:
219
+ backends.append("gloo")
220
+ elif "mpi" in path_lower:
221
+ backends.append("mpi")
222
+
223
+ return list(set(backends)) # Remove duplicates
@@ -0,0 +1,266 @@
1
+ """TensorFlow framework deep inspection.
2
+
3
+ Validates TensorFlow CUDA compatibility, compute capability requirements,
4
+ and build configuration.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+ from typing import Dict, List, Optional
11
+
12
+ from pybinaryguard.models.package import PackageBinaryInfo
13
+ from pybinaryguard.models.system import SystemProfile
14
+
15
+
16
+ def check_tensorflow_compute_capability(
17
+ package: PackageBinaryInfo,
18
+ profile: SystemProfile
19
+ ) -> List[Dict[str, str]]:
20
+ """Check TensorFlow compute capability requirements.
21
+
22
+ Validates:
23
+ - Minimum compute capability for TensorFlow version
24
+ - CUDA version compatibility
25
+ - cuDNN version requirements
26
+ - AVX instruction set availability
27
+
28
+ Args:
29
+ package: PackageBinaryInfo for tensorflow package
30
+ profile: System profile
31
+
32
+ Returns:
33
+ List of compatibility issues found
34
+ """
35
+ issues: List[Dict[str, str]] = []
36
+
37
+ if not package.name.lower().startswith("tensorflow"):
38
+ return issues
39
+
40
+ tf_version = package.version
41
+ if not tf_version:
42
+ return issues
43
+
44
+ # Check compute capability requirements
45
+ if profile.cuda_compute_capability:
46
+ min_compute = get_tensorflow_min_compute_capability(tf_version)
47
+
48
+ if min_compute:
49
+ try:
50
+ gpu_compute = float(profile.cuda_compute_capability)
51
+ if gpu_compute < min_compute:
52
+ issues.append({
53
+ "issue": "tensorflow_compute_capability_too_low",
54
+ "severity": "critical",
55
+ "message": (
56
+ f"TensorFlow {tf_version} requires compute capability >= {min_compute}, "
57
+ f"but GPU has {profile.cuda_compute_capability}"
58
+ ),
59
+ "recommendation": f"Upgrade GPU or use TensorFlow version supporting compute {gpu_compute}",
60
+ })
61
+ except ValueError:
62
+ pass
63
+
64
+ # Check CUDA version for GPU builds
65
+ if profile.cuda_runtime_version and not is_tensorflow_cpu_only(package):
66
+ cuda_compat = check_tensorflow_cuda_compatibility(tf_version, profile.cuda_runtime_version)
67
+ if cuda_compat:
68
+ issues.append({
69
+ "issue": "tensorflow_cuda_mismatch",
70
+ "severity": "critical",
71
+ "message": cuda_compat,
72
+ "recommendation": "Install TensorFlow version compatible with your CUDA version",
73
+ })
74
+
75
+ # Check AVX instruction set (TensorFlow 1.6+ requires AVX)
76
+ if not profile.cpu_flags or "avx" not in profile.cpu_flags.lower():
77
+ major_version = int(tf_version.split(".")[0])
78
+ if major_version >= 1:
79
+ issues.append({
80
+ "issue": "tensorflow_missing_avx",
81
+ "severity": "critical",
82
+ "message": "TensorFlow requires AVX instruction set, but CPU doesn't support it",
83
+ "recommendation": "Build TensorFlow from source without AVX or upgrade CPU",
84
+ })
85
+
86
+ return issues
87
+
88
+
89
+ def get_tensorflow_min_compute_capability(tf_version: str) -> Optional[float]:
90
+ """Get minimum compute capability required for TensorFlow version.
91
+
92
+ Args:
93
+ tf_version: TensorFlow version (e.g., "2.15.0")
94
+
95
+ Returns:
96
+ Minimum compute capability as float, or None if unknown
97
+ """
98
+ try:
99
+ major = int(tf_version.split(".")[0])
100
+ minor = int(tf_version.split(".")[1])
101
+
102
+ # TensorFlow 2.11+ requires compute capability >= 3.5
103
+ if major >= 2 and minor >= 11:
104
+ return 3.5
105
+
106
+ # TensorFlow 2.x requires compute capability >= 3.0
107
+ if major >= 2:
108
+ return 3.0
109
+
110
+ # TensorFlow 1.x requires compute capability >= 3.0
111
+ return 3.0
112
+ except (ValueError, IndexError):
113
+ return None
114
+
115
+
116
+ def check_tensorflow_cuda_compatibility(
117
+ tf_version: str,
118
+ cuda_version: str
119
+ ) -> Optional[str]:
120
+ """Check TensorFlow and CUDA version compatibility.
121
+
122
+ Args:
123
+ tf_version: TensorFlow version (e.g., "2.15.0")
124
+ cuda_version: CUDA version (e.g., "12.2")
125
+
126
+ Returns:
127
+ Error message if incompatible, None if compatible
128
+ """
129
+ # Compatibility matrix (TensorFlow -> CUDA versions)
130
+ compatibility_matrix = {
131
+ "2.15": ["12.2"],
132
+ "2.14": ["11.8"],
133
+ "2.13": ["11.8"],
134
+ "2.12": ["11.8"],
135
+ "2.11": ["11.2"],
136
+ "2.10": ["11.2"],
137
+ "2.9": ["11.2"],
138
+ "2.8": ["11.2"],
139
+ "2.7": ["11.2"],
140
+ "2.6": ["11.2"],
141
+ "2.5": ["11.2"],
142
+ "2.4": ["11.0"],
143
+ "2.3": ["10.1"],
144
+ "2.2": ["10.1"],
145
+ "2.1": ["10.0"],
146
+ "2.0": ["10.0"],
147
+ }
148
+
149
+ try:
150
+ tf_major_minor = ".".join(tf_version.split(".")[:2])
151
+ cuda_major_minor = ".".join(cuda_version.split(".")[:2])
152
+
153
+ supported_cuda = compatibility_matrix.get(tf_major_minor, [])
154
+
155
+ if supported_cuda and cuda_major_minor not in supported_cuda:
156
+ return (
157
+ f"TensorFlow {tf_major_minor} requires CUDA {', '.join(supported_cuda)}, "
158
+ f"but system has CUDA {cuda_version}"
159
+ )
160
+ except (ValueError, IndexError):
161
+ pass
162
+
163
+ return None
164
+
165
+
166
+ def is_tensorflow_cpu_only(package: PackageBinaryInfo) -> bool:
167
+ """Detect if TensorFlow is CPU-only build.
168
+
169
+ Args:
170
+ package: PackageBinaryInfo for tensorflow package
171
+
172
+ Returns:
173
+ True if CPU-only build
174
+ """
175
+ # Check package name
176
+ if "cpu" in package.name.lower():
177
+ return True
178
+
179
+ # Check for CUDA-related shared objects
180
+ for so in package.shared_objects:
181
+ if so.path and "cuda" in so.path.lower():
182
+ return False
183
+
184
+ return True
185
+
186
+
187
+ def detect_tensorflow_gpu_support(package: PackageBinaryInfo) -> Dict[str, bool]:
188
+ """Detect TensorFlow GPU support features.
189
+
190
+ Args:
191
+ package: PackageBinaryInfo for tensorflow package
192
+
193
+ Returns:
194
+ Dictionary with GPU support flags
195
+ """
196
+ support = {
197
+ "cuda": False,
198
+ "tensorrt": False,
199
+ "rocm": False,
200
+ "xla": False,
201
+ }
202
+
203
+ for so in package.shared_objects:
204
+ if not so.path:
205
+ continue
206
+
207
+ path_lower = so.path.lower()
208
+
209
+ if "cuda" in path_lower:
210
+ support["cuda"] = True
211
+ if "tensorrt" in path_lower:
212
+ support["tensorrt"] = True
213
+ if "rocm" in path_lower:
214
+ support["rocm"] = True
215
+ if "xla" in path_lower:
216
+ support["xla"] = True
217
+
218
+ return support
219
+
220
+
221
+ def check_tensorflow_lite_compatibility(
222
+ tflite_model_schema: int,
223
+ tflite_runtime_version: Optional[str]
224
+ ) -> Optional[str]:
225
+ """Check TFLite model schema compatibility with runtime.
226
+
227
+ Args:
228
+ tflite_model_schema: TFLite model schema version
229
+ tflite_runtime_version: TFLite runtime version
230
+
231
+ Returns:
232
+ Error message if incompatible, None if compatible
233
+ """
234
+ if not tflite_runtime_version:
235
+ return None
236
+
237
+ # TFLite schema version by TensorFlow version
238
+ schema_by_version = {
239
+ "2.15": 3,
240
+ "2.14": 3,
241
+ "2.13": 3,
242
+ "2.12": 3,
243
+ "2.11": 3,
244
+ "2.10": 3,
245
+ "2.9": 3,
246
+ "2.8": 3,
247
+ "2.7": 3,
248
+ "2.6": 3,
249
+ "2.5": 3,
250
+ "2.4": 3,
251
+ "2.3": 3,
252
+ }
253
+
254
+ try:
255
+ tflite_major_minor = ".".join(tflite_runtime_version.split(".")[:2])
256
+ max_schema = schema_by_version.get(tflite_major_minor, 3)
257
+
258
+ if tflite_model_schema > max_schema:
259
+ return (
260
+ f"TFLite model schema version {tflite_model_schema} is newer than "
261
+ f"runtime version {tflite_runtime_version} (max schema: {max_schema})"
262
+ )
263
+ except (ValueError, IndexError):
264
+ pass
265
+
266
+ return None