diffai-python 0.3.5__py3-none-win_amd64.whl → 0.3.7__py3-none-win_amd64.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffai-python
3
- Version: 0.3.5
3
+ Version: 0.3.7
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -0,0 +1,4 @@
1
+ diffai_python-0.3.7.data/scripts/diffai.exe,sha256=IfN13u0-0p1KGYbLrO6-N-Bp-Sj1px9d4hIoC1j-liQ,243200
2
+ diffai_python-0.3.7.dist-info/METADATA,sha256=nd4DnAwMa5Uo3l-kkj2wQ03X9G4BPuEAKLPAPuCcdx8,11943
3
+ diffai_python-0.3.7.dist-info/WHEEL,sha256=T1-x9ZAB-aE3ewIGbYuockW5ywV7fI-Nla9FsiR1vW4,93
4
+ diffai_python-0.3.7.dist-info/RECORD,,
diffai/__init__.py DELETED
@@ -1,303 +0,0 @@
1
- """
2
- diffai - AI/ML specialized diff tool for deep tensor comparison and analysis
3
-
4
- This package provides a Python wrapper around the diffai Rust binary,
5
- following the same pattern as ruff for optimal performance and reliability.
6
- """
7
-
8
- # No backward compatibility imports
9
-
10
- import json
11
- import subprocess
12
- import sys
13
- import shutil
14
- from pathlib import Path
15
- from typing import Any, Dict, List, Optional, Union
16
- from dataclasses import dataclass
17
- from enum import Enum
18
-
19
- # Version is now managed dynamically from pyproject.toml
20
- # This prevents hardcoded version mismatches during releases
21
- try:
22
- from importlib.metadata import version
23
- __version__ = version("diffai-python")
24
- except ImportError:
25
- # Fallback for Python < 3.8
26
- try:
27
- import pkg_resources
28
- __version__ = pkg_resources.get_distribution("diffai-python").version
29
- except Exception:
30
- __version__ = "unknown"
31
-
32
- class OutputFormat(Enum):
33
- """Supported output formats for diffai results."""
34
- CLI = "cli"
35
- JSON = "json"
36
- YAML = "yaml"
37
-
38
- @dataclass
39
- class DiffOptions:
40
- """Configuration options for diffai analysis."""
41
-
42
- # Basic options
43
- input_format: Optional[str] = None
44
- output_format: Optional[OutputFormat] = None
45
- recursive: bool = False
46
- verbose: bool = False
47
- path: Optional[str] = None
48
- ignore_keys_regex: Optional[str] = None
49
- epsilon: Optional[float] = None
50
- array_id_key: Optional[str] = None
51
-
52
- # ML analysis options
53
- show_layer_impact: bool = False
54
- quantization_analysis: bool = False
55
- sort_by_change_magnitude: bool = False
56
- stats: bool = False
57
- learning_progress: bool = False
58
- convergence_analysis: bool = False
59
- anomaly_detection: bool = False
60
- gradient_analysis: bool = False
61
- memory_analysis: bool = False
62
- inference_speed_estimate: bool = False
63
- regression_test: bool = False
64
- alert_on_degradation: bool = False
65
- review_friendly: bool = False
66
- change_summary: bool = False
67
- deployment_readiness: bool = False
68
- architecture_comparison: bool = False
69
- param_efficiency_analysis: bool = False
70
- hyperparameter_impact: bool = False
71
- learning_rate_analysis: bool = False
72
- performance_impact_estimate: bool = False
73
- generate_report: bool = False
74
- markdown_output: bool = False
75
- include_charts: bool = False
76
- embedding_analysis: bool = False
77
- similarity_matrix: bool = False
78
- clustering_change: bool = False
79
- attention_analysis: bool = False
80
- head_importance: bool = False
81
- attention_pattern_diff: bool = False
82
- hyperparameter_comparison: bool = False
83
- learning_curve_analysis: bool = False
84
- statistical_significance: bool = False
85
-
86
- def to_args(self) -> List[str]:
87
- """Convert options to command line arguments."""
88
- args = []
89
-
90
- # Basic options
91
- if self.input_format:
92
- args.extend(["--format", self.input_format])
93
- if self.output_format:
94
- args.extend(["--output", self.output_format.value])
95
- if self.recursive:
96
- args.append("--recursive")
97
- if self.verbose:
98
- args.append("--verbose")
99
- if self.path:
100
- args.extend(["--path", self.path])
101
- if self.ignore_keys_regex:
102
- args.extend(["--ignore-keys-regex", self.ignore_keys_regex])
103
- if self.epsilon is not None:
104
- args.extend(["--epsilon", str(self.epsilon)])
105
- if self.array_id_key:
106
- args.extend(["--array-id-key", self.array_id_key])
107
-
108
- # ML analysis options
109
- if self.show_layer_impact:
110
- args.append("--show-layer-impact")
111
- if self.quantization_analysis:
112
- args.append("--quantization-analysis")
113
- if self.sort_by_change_magnitude:
114
- args.append("--sort-by-change-magnitude")
115
- if self.stats:
116
- args.append("--stats")
117
- if self.learning_progress:
118
- args.append("--learning-progress")
119
- if self.convergence_analysis:
120
- args.append("--convergence-analysis")
121
- if self.anomaly_detection:
122
- args.append("--anomaly-detection")
123
- if self.gradient_analysis:
124
- args.append("--gradient-analysis")
125
- if self.memory_analysis:
126
- args.append("--memory-analysis")
127
- if self.inference_speed_estimate:
128
- args.append("--inference-speed-estimate")
129
- if self.regression_test:
130
- args.append("--regression-test")
131
- if self.alert_on_degradation:
132
- args.append("--alert-on-degradation")
133
- if self.review_friendly:
134
- args.append("--review-friendly")
135
- if self.change_summary:
136
- args.append("--change-summary")
137
- if self.deployment_readiness:
138
- args.append("--deployment-readiness")
139
- if self.architecture_comparison:
140
- args.append("--architecture-comparison")
141
- if self.param_efficiency_analysis:
142
- args.append("--param-efficiency-analysis")
143
- if self.hyperparameter_impact:
144
- args.append("--hyperparameter-impact")
145
- if self.learning_rate_analysis:
146
- args.append("--learning-rate-analysis")
147
- if self.performance_impact_estimate:
148
- args.append("--performance-impact-estimate")
149
- if self.generate_report:
150
- args.append("--generate-report")
151
- if self.markdown_output:
152
- args.append("--markdown-output")
153
- if self.include_charts:
154
- args.append("--include-charts")
155
- if self.embedding_analysis:
156
- args.append("--embedding-analysis")
157
- if self.similarity_matrix:
158
- args.append("--similarity-matrix")
159
- if self.clustering_change:
160
- args.append("--clustering-change")
161
- if self.attention_analysis:
162
- args.append("--attention-analysis")
163
- if self.head_importance:
164
- args.append("--head-importance")
165
- if self.attention_pattern_diff:
166
- args.append("--attention-pattern-diff")
167
- if self.hyperparameter_comparison:
168
- args.append("--hyperparameter-comparison")
169
- if self.learning_curve_analysis:
170
- args.append("--learning-curve-analysis")
171
- if self.statistical_significance:
172
- args.append("--statistical-significance")
173
-
174
- return args
175
-
176
- class DiffaiError(Exception):
177
- """Base exception for diffai-related errors."""
178
- pass
179
-
180
- class DiffResult:
181
- """Result from diffai analysis."""
182
-
183
- def __init__(self, raw_output: str, format_type: str = "cli", return_code: int = 0):
184
- self.raw_output = raw_output
185
- self.format_type = format_type
186
- self.return_code = return_code
187
- self._parsed_data = None
188
-
189
- @property
190
- def data(self) -> Any:
191
- """Get parsed data (JSON objects for JSON output, raw string otherwise)."""
192
- if self._parsed_data is None:
193
- if self.format_type == "json" and self.raw_output.strip():
194
- try:
195
- self._parsed_data = json.loads(self.raw_output)
196
- except json.JSONDecodeError:
197
- self._parsed_data = self.raw_output
198
- else:
199
- self._parsed_data = self.raw_output
200
- return self._parsed_data
201
-
202
- @property
203
- def is_json(self) -> bool:
204
- """True if result is in JSON format."""
205
- return self.format_type == "json" and isinstance(self.data, (dict, list))
206
-
207
- def __str__(self) -> str:
208
- return self.raw_output
209
-
210
- def _find_diffai_binary() -> str:
211
- """Find the diffai binary, checking bundled location first."""
212
- # Check if bundled with package
213
- package_dir = Path(__file__).parent.parent.parent
214
- bundled_binary = package_dir / "diffai"
215
-
216
- if bundled_binary.exists() and bundled_binary.is_file():
217
- return str(bundled_binary)
218
-
219
- # Fallback to system PATH
220
- system_binary = shutil.which("diffai")
221
- if system_binary:
222
- return system_binary
223
-
224
- raise DiffaiError(
225
- "diffai binary not found. Please ensure diffai is installed or available in PATH."
226
- )
227
-
228
- def diff(
229
- input1: str,
230
- input2: str,
231
- options: Optional[Union[DiffOptions, Dict[str, Any]]] = None,
232
- **kwargs
233
- ) -> DiffResult:
234
- """
235
- Compare two files using diffai.
236
-
237
- Args:
238
- input1: Path to first input file
239
- input2: Path to second input file
240
- options: DiffOptions object or dict of options
241
- **kwargs: Additional options as keyword arguments
242
-
243
- Returns:
244
- DiffResult object containing comparison results
245
- """
246
- # Handle different option formats
247
- if options is None:
248
- options = DiffOptions(**kwargs)
249
- elif isinstance(options, dict):
250
- combined_options = {**options, **kwargs}
251
- options = DiffOptions(**combined_options)
252
- elif kwargs:
253
- # Merge kwargs into existing DiffOptions
254
- option_dict = {
255
- field.name: getattr(options, field.name)
256
- for field in options.__dataclass_fields__.values()
257
- }
258
- combined_options = {**option_dict, **kwargs}
259
- options = DiffOptions(**combined_options)
260
-
261
- try:
262
- binary_path = _find_diffai_binary()
263
- cmd = [binary_path] + options.to_args() + [input1, input2]
264
-
265
- result = subprocess.run(
266
- cmd,
267
- capture_output=True,
268
- text=True,
269
- check=False
270
- )
271
-
272
- if result.returncode != 0 and result.stderr:
273
- raise DiffaiError(f"diffai failed: {result.stderr}")
274
-
275
- format_type = options.output_format.value if options.output_format else "cli"
276
- return DiffResult(result.stdout, format_type, result.returncode)
277
-
278
- except FileNotFoundError:
279
- raise DiffaiError("diffai binary not found")
280
- except Exception as e:
281
- raise DiffaiError(f"Diff failed: {e}")
282
-
283
- def main():
284
- """CLI entry point for the diffai command."""
285
- try:
286
- binary_path = _find_diffai_binary()
287
- # Forward all arguments to the binary
288
- result = subprocess.run([binary_path] + sys.argv[1:])
289
- sys.exit(result.returncode)
290
- except DiffaiError as e:
291
- print(f"Error: {e}", file=sys.stderr)
292
- sys.exit(1)
293
-
294
- # Export main API
295
- __all__ = [
296
- "diff",
297
- "DiffOptions",
298
- "DiffResult",
299
- "OutputFormat",
300
- "DiffaiError",
301
- "__version__",
302
- "main",
303
- ]
diffai/__main__.py DELETED
@@ -1,8 +0,0 @@
1
- """
2
- Entry point for python -m diffai
3
- """
4
-
5
- from . import main
6
-
7
- if __name__ == "__main__":
8
- main()
diffai/installer.py DELETED
@@ -1,206 +0,0 @@
1
- """
2
- Binary installer for diffai Python package.
3
-
4
- This module handles downloading and installing the diffai binary
5
- when the package is installed via pip.
6
-
7
- Supports platforms: Windows, Linux, Darwin (macOS) with x86_64 and aarch64 architectures.
8
- """
9
-
10
- import os
11
- import platform
12
- import shutil
13
- import subprocess
14
- import sys
15
- import tarfile
16
- import tempfile
17
- import urllib.request
18
- import zipfile
19
- from pathlib import Path
20
-
21
- # Package version constant for GitHub releases
22
- PACKAGE_VERSION = "0.3.4"
23
-
24
-
25
- def get_platform_info():
26
- """Get platform-specific information for binary download.
27
-
28
- Supported platforms: Windows, Linux, Darwin
29
- Supported architectures: x86_64, aarch64
30
- """
31
- system = platform.system().lower()
32
- machine = platform.machine().lower()
33
-
34
- if system == "linux": # Linux systems
35
- if machine in ("x86_64", "amd64"):
36
- return "linux-x86_64", "diffai"
37
- else:
38
- raise RuntimeError(f"Unsupported Linux architecture: {machine}")
39
- elif system == "darwin": # Darwin (macOS) systems
40
- if machine == "arm64":
41
- return "macos-aarch64", "diffai"
42
- elif machine in ("x86_64", "amd64"):
43
- return "macos-x86_64", "diffai"
44
- else:
45
- raise RuntimeError(f"Unsupported Darwin architecture: {machine}")
46
- elif system == "windows": # Windows systems
47
- if machine in ("x86_64", "amd64"):
48
- return "windows-x86_64", "diffai.exe"
49
- else:
50
- raise RuntimeError(f"Unsupported Windows architecture: {machine}")
51
- else:
52
- raise RuntimeError(f"Unsupported operating system: {system}")
53
-
54
-
55
- def download_file(url, dest_path):
56
- """Download a file from URL to destination path."""
57
- try:
58
- with urllib.request.urlopen(url) as response:
59
- with open(dest_path, 'wb') as f:
60
- f.write(response.read())
61
- except Exception as e:
62
- raise RuntimeError(f"Failed to download file: {e}")
63
-
64
-
65
- def extract_archive(archive_path, extract_to):
66
- """Extract archive file to destination directory."""
67
- try:
68
- if archive_path.endswith('.zip'):
69
- with zipfile.ZipFile(archive_path, 'r') as zip_ref:
70
- zip_ref.extractall(extract_to)
71
- elif archive_path.endswith(('.tar.gz', '.tgz')):
72
- with tarfile.open(archive_path, 'r:gz') as tar_ref:
73
- tar_ref.extractall(extract_to)
74
- else:
75
- raise RuntimeError(f"Unsupported archive format: {archive_path}")
76
- except Exception as e:
77
- raise RuntimeError(f"Failed to extract archive: {e}")
78
-
79
-
80
- def verify_binary(binary_path):
81
- """Verify that the downloaded binary works correctly."""
82
- try:
83
- # Test binary with --version flag
84
- result = subprocess.run(
85
- [binary_path, "--version"],
86
- capture_output=True,
87
- text=True,
88
- timeout=10
89
- )
90
-
91
- if result.returncode == 0:
92
- return True
93
- else:
94
- raise RuntimeError(f"Binary verification failed: {result.stderr}")
95
-
96
- except subprocess.TimeoutExpired:
97
- raise RuntimeError("Binary verification timed out")
98
- except Exception as e:
99
- raise RuntimeError(f"Failed to verify binary: {e}")
100
-
101
-
102
- def get_latest_release_info():
103
- """Get information about the latest GitHub release from github.com."""
104
- try:
105
- import json
106
-
107
- # GitHub API URL for latest release
108
- url = "https://api.github.com/repos/kako-jun/diffai/releases/latest"
109
- with urllib.request.urlopen(url) as response:
110
- data = json.loads(response.read().decode())
111
-
112
- return data["tag_name"], data["assets"]
113
- except Exception as e:
114
- raise RuntimeError(f"Failed to get release information from github.com: {e}")
115
-
116
-
117
- def download_binary(version=None):
118
- """Download the diffai binary for the current platform."""
119
- platform_name, binary_name = get_platform_info()
120
-
121
- if version is None:
122
- version, assets = get_latest_release_info()
123
- else:
124
- # For specific version, construct asset URL manually
125
- assets = None
126
-
127
- # Construct download URL
128
- if assets:
129
- # Find the correct asset
130
- asset_name = f"diffai-{platform_name}.tar.gz"
131
- if platform_name.startswith("windows"):
132
- asset_name = f"diffai-{platform_name}.zip"
133
-
134
- asset_url = None
135
- for asset in assets:
136
- if asset["name"] == asset_name:
137
- asset_url = asset["browser_download_url"]
138
- break
139
-
140
- if not asset_url:
141
- raise RuntimeError(f"Binary not found for platform: {platform_name}")
142
- else:
143
- # Fallback URL construction
144
- base_url = "https://github.com/kako-jun/diffai/releases/download"
145
- if platform_name.startswith("windows"):
146
- asset_name = f"diffai-{platform_name}.zip"
147
- else:
148
- asset_name = f"diffai-{platform_name}.tar.gz"
149
- asset_url = f"{base_url}/{version}/{asset_name}"
150
-
151
- # Download to temporary location
152
- with tempfile.TemporaryDirectory() as temp_dir:
153
- temp_path = Path(temp_dir)
154
- archive_path = temp_path / asset_name
155
-
156
- print(f"Downloading {asset_url}...")
157
- urllib.request.urlretrieve(asset_url, archive_path)
158
-
159
- # Extract archive
160
- if asset_name.endswith(".tar.gz"):
161
- subprocess.run(["tar", "-xzf", archive_path, "-C", temp_path], check=True)
162
- elif asset_name.endswith(".zip"):
163
- import zipfile
164
- with zipfile.ZipFile(archive_path, 'r') as zip_ref:
165
- zip_ref.extractall(temp_path)
166
-
167
- # Find the binary
168
- binary_path = temp_path / binary_name
169
- if not binary_path.exists():
170
- raise RuntimeError(f"Binary not found in archive: {binary_name}")
171
-
172
- return binary_path
173
-
174
-
175
- def install_binary():
176
- """Install the diffai binary to the package directory."""
177
- try:
178
- # Get package directory
179
- package_dir = Path(__file__).parent.parent.parent
180
- binary_dir = package_dir / "bin"
181
- binary_dir.mkdir(exist_ok=True)
182
-
183
- # Download binary
184
- temp_binary = download_binary()
185
-
186
- # Copy to package directory
187
- platform_name, binary_name = get_platform_info()
188
- target_path = binary_dir / binary_name
189
-
190
- shutil.copy2(temp_binary, target_path)
191
-
192
- # Make executable on Unix-like systems
193
- if not platform_name.startswith("windows"):
194
- os.chmod(target_path, 0o755)
195
-
196
- print(f"Successfully installed diffai binary to {target_path}")
197
- return target_path
198
-
199
- except Exception as e:
200
- print(f"Warning: Failed to install diffai binary: {e}")
201
- print("The Python API will still work if diffai is available in PATH")
202
- return None
203
-
204
-
205
- if __name__ == "__main__":
206
- install_binary()
@@ -1,7 +0,0 @@
1
- diffai/__init__.py,sha256=eL_ZqXdoct718oT9v7smtFVbvRSrV1WjP0w4oRNMnjs,10653
2
- diffai/__main__.py,sha256=0ABdXiMt3e1FQ3Bept_jgjEoU6unvf-pW9iG50YuS70,106
3
- diffai/installer.py,sha256=8aLhL6sZ8uDgCoZQM6Ea_dR2jiF4k7mN81I7TghO12U,7132
4
- diffai_python-0.3.5.data/scripts/diffai.exe,sha256=l_nv72_RPvTHQ1MYsOYIxmLEep4Vcm0BPVAd_mF64ys,243200
5
- diffai_python-0.3.5.dist-info/METADATA,sha256=5MP_ruae0bR2XXDYJSikQH6udsbO88onsZQ9N7jJ9r4,11943
6
- diffai_python-0.3.5.dist-info/WHEEL,sha256=T1-x9ZAB-aE3ewIGbYuockW5ywV7fI-Nla9FsiR1vW4,93
7
- diffai_python-0.3.5.dist-info/RECORD,,