wup 0.2.24__tar.gz → 0.2.25__tar.gz

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 (32) hide show
  1. {wup-0.2.24/wup.egg-info → wup-0.2.25}/PKG-INFO +7 -7
  2. {wup-0.2.24 → wup-0.2.25}/README.md +6 -6
  3. {wup-0.2.24 → wup-0.2.25}/pyproject.toml +1 -1
  4. {wup-0.2.24 → wup-0.2.25}/wup/__init__.py +1 -1
  5. {wup-0.2.24 → wup-0.2.25}/wup/core.py +61 -32
  6. {wup-0.2.24 → wup-0.2.25/wup.egg-info}/PKG-INFO +7 -7
  7. {wup-0.2.24 → wup-0.2.25}/LICENSE +0 -0
  8. {wup-0.2.24 → wup-0.2.25}/setup.cfg +0 -0
  9. {wup-0.2.24 → wup-0.2.25}/tests/test_e2e.py +0 -0
  10. {wup-0.2.24 → wup-0.2.25}/tests/test_testql_watcher.py +0 -0
  11. {wup-0.2.24 → wup-0.2.25}/tests/test_web_client.py +0 -0
  12. {wup-0.2.24 → wup-0.2.25}/tests/test_wup.py +0 -0
  13. {wup-0.2.24 → wup-0.2.25}/wup/_ast_detector.py +0 -0
  14. {wup-0.2.24 → wup-0.2.25}/wup/_hash_detector.py +0 -0
  15. {wup-0.2.24 → wup-0.2.25}/wup/_yaml_detector.py +0 -0
  16. {wup-0.2.24 → wup-0.2.25}/wup/anomaly_detector.py +0 -0
  17. {wup-0.2.24 → wup-0.2.25}/wup/anomaly_models.py +0 -0
  18. {wup-0.2.24 → wup-0.2.25}/wup/assistant.py +0 -0
  19. {wup-0.2.24 → wup-0.2.25}/wup/cli.py +0 -0
  20. {wup-0.2.24 → wup-0.2.25}/wup/config.py +0 -0
  21. {wup-0.2.24 → wup-0.2.25}/wup/dependency_mapper.py +0 -0
  22. {wup-0.2.24 → wup-0.2.25}/wup/models/__init__.py +0 -0
  23. {wup-0.2.24 → wup-0.2.25}/wup/models/config.py +0 -0
  24. {wup-0.2.24 → wup-0.2.25}/wup/testql_discovery.py +0 -0
  25. {wup-0.2.24 → wup-0.2.25}/wup/testql_watcher.py +0 -0
  26. {wup-0.2.24 → wup-0.2.25}/wup/visual_diff.py +0 -0
  27. {wup-0.2.24 → wup-0.2.25}/wup/web_client.py +0 -0
  28. {wup-0.2.24 → wup-0.2.25}/wup.egg-info/SOURCES.txt +0 -0
  29. {wup-0.2.24 → wup-0.2.25}/wup.egg-info/dependency_links.txt +0 -0
  30. {wup-0.2.24 → wup-0.2.25}/wup.egg-info/entry_points.txt +0 -0
  31. {wup-0.2.24 → wup-0.2.25}/wup.egg-info/requires.txt +0 -0
  32. {wup-0.2.24 → wup-0.2.25}/wup.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wup
3
- Version: 0.2.24
3
+ Version: 0.2.25
4
4
  Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -29,17 +29,17 @@ Dynamic: license-file
29
29
 
30
30
  ## AI Cost Tracking
31
31
 
32
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.22-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
33
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-11.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
32
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.25-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
33
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-14.3h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
34
34
 
35
- - 🤖 **LLM usage:** $1.8607 (34 commits)
36
- - 👤 **Human dev:** ~$1113 (11.1h @ $100/h, 30min dedup)
35
+ - 🤖 **LLM usage:** $1.8622 (35 commits)
36
+ - 👤 **Human dev:** ~$1432 (14.3h @ $100/h, 30min dedup)
37
37
 
38
- Generated on 2026-05-12 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
38
+ Generated on 2026-05-15 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
39
39
 
40
40
  ---
41
41
 
42
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.22-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
42
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.25-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
43
43
 
44
44
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
45
45
 
@@ -3,17 +3,17 @@
3
3
 
4
4
  ## AI Cost Tracking
5
5
 
6
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.22-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-11.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
6
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.25-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-14.3h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
8
8
 
9
- - 🤖 **LLM usage:** $1.8607 (34 commits)
10
- - 👤 **Human dev:** ~$1113 (11.1h @ $100/h, 30min dedup)
9
+ - 🤖 **LLM usage:** $1.8622 (35 commits)
10
+ - 👤 **Human dev:** ~$1432 (14.3h @ $100/h, 30min dedup)
11
11
 
12
- Generated on 2026-05-12 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
12
+ Generated on 2026-05-15 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
13
13
 
14
14
  ---
15
15
 
16
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.22-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
16
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.25-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
17
17
 
18
18
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
19
19
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wup"
7
- version = "0.2.24"
7
+ version = "0.2.25"
8
8
  description = "WUP (What's Up) - Intelligent file watcher for regression testing in large projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -7,7 +7,7 @@ WUP monitors file changes and runs intelligent regression tests using a 3-layer
7
7
  3. Detail Layer: Full tests with blame reports (only on failure)
8
8
  """
9
9
 
10
- __version__ = "0.2.22"
10
+ __version__ = "0.2.25"
11
11
  __author__ = "Tom Sapletta"
12
12
 
13
13
  from .config import load_config, save_config, get_default_config
@@ -6,6 +6,8 @@ import asyncio
6
6
  import json
7
7
  import subprocess
8
8
  import time
9
+ import urllib.error
10
+ import urllib.request
9
11
  from collections import defaultdict, deque
10
12
  from pathlib import Path
11
13
  from typing import Dict, List, Optional, Set, Tuple
@@ -298,69 +300,96 @@ class WupWatcher:
298
300
  async def run_quick_test(self, service: str, endpoints: List[str]) -> bool:
299
301
  """
300
302
  Run a quick test for a service (smoke test).
301
-
303
+
302
304
  Args:
303
305
  service: Service name
304
306
  endpoints: List of endpoints to test
305
-
307
+
306
308
  Returns:
307
309
  True if all tests passed, False otherwise
308
310
  """
309
311
  self.console.print(f"[cyan]🧪 Quick testing {service} ({len(endpoints)} endpoints)[/cyan]")
310
-
311
- # This is a placeholder - integrate with TestQL or your test framework
312
- # For now, simulate a test
313
- await asyncio.sleep(1)
314
-
315
- # Simulate random failure for demo (10% chance)
316
- import random
317
- passed = random.random() > 0.1
318
-
312
+
313
+ if not endpoints:
314
+ self.console.print(f"[yellow]⚠ No endpoints configured for {service}, skipping quick test[/yellow]")
315
+ return True
316
+
317
+ passed = True
318
+ for endpoint in endpoints:
319
+ try:
320
+ req = urllib.request.Request(endpoint, method="HEAD")
321
+ with urllib.request.urlopen(req, timeout=10) as resp:
322
+ if resp.status >= 400:
323
+ self.console.print(f"[red]✗ {endpoint} → HTTP {resp.status}[/red]")
324
+ passed = False
325
+ else:
326
+ self.console.print(f"[green]✓ {endpoint} → HTTP {resp.status}[/green]")
327
+ except Exception as e:
328
+ self.console.print(f"[red]✗ {endpoint} → {e}[/red]")
329
+ passed = False
330
+
319
331
  if passed:
320
332
  self.console.print(f"[green]✓ Quick test passed for {service}[/green]")
321
333
  else:
322
334
  self.console.print(f"[red]✗ Quick test failed for {service}[/red]")
323
-
335
+
324
336
  return passed
325
337
 
326
338
  async def run_detail_test(self, service: str, endpoints: List[str]) -> Dict:
327
339
  """
328
340
  Run a detailed test for a service with blame report.
329
-
341
+
330
342
  Args:
331
343
  service: Service name
332
344
  endpoints: List of endpoints to test
333
-
345
+
334
346
  Returns:
335
347
  Dictionary with test results and blame information
336
348
  """
337
349
  self.console.print(f"[cyan]🔍 Detail testing {service} ({len(endpoints)} endpoints)[/cyan]")
338
-
339
- # This is a placeholder - integrate with TestQL or your test framework
340
- # For now, simulate a test
341
- await asyncio.sleep(3)
342
-
343
- # Simulate results
350
+
344
351
  results = {
345
352
  "service": service,
346
353
  "total_endpoints": len(endpoints),
347
- "passed": len(endpoints) - 1,
348
- "failed": 1,
349
- "failed_endpoint": endpoints[0] if endpoints else None,
350
- "blame": {
351
- "file": f"app/{service}/routes.py",
352
- "line": 42,
353
- "commit": "abc123",
354
- "author": "developer"
355
- }
354
+ "passed": 0,
355
+ "failed": 0,
356
+ "failed_endpoint": None,
357
+ "blame": {},
356
358
  }
357
-
359
+
360
+ for endpoint in endpoints:
361
+ try:
362
+ req = urllib.request.Request(endpoint, method="GET")
363
+ with urllib.request.urlopen(req, timeout=30) as resp:
364
+ if resp.status >= 400:
365
+ results["failed"] += 1
366
+ self.console.print(f"[red]✗ {endpoint} → HTTP {resp.status}[/red]")
367
+ else:
368
+ results["passed"] += 1
369
+ self.console.print(f"[green]✓ {endpoint} → HTTP {resp.status}[/green]")
370
+ except Exception as e:
371
+ results["failed"] += 1
372
+ self.console.print(f"[red]✗ {endpoint} → {e}[/red]")
373
+
358
374
  if results["failed"] > 0:
375
+ results["failed_endpoint"] = endpoints[0] if endpoints else None
376
+ try:
377
+ blame_result = subprocess.run(
378
+ ["git", "log", "--oneline", "-5", "--", f"*/{service}/*"],
379
+ cwd=str(self.project_root),
380
+ capture_output=True,
381
+ text=True,
382
+ )
383
+ if blame_result.returncode == 0:
384
+ lines = blame_result.stdout.strip().split("\n")
385
+ if lines and lines[0]:
386
+ results["blame"] = {"recent_commits": lines}
387
+ except Exception:
388
+ pass
359
389
  self.console.print(f"[red]✗ Detail test found {results['failed']} regression(s)[/red]")
360
- self.console.print(f"[red] Blame: {results['blame']['file']}:{results['blame']['line']}[/red]")
361
390
  else:
362
391
  self.console.print(f"[green]✓ Detail test passed for {service}[/green]")
363
-
392
+
364
393
  return results
365
394
 
366
395
  async def test_loop(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wup
3
- Version: 0.2.24
3
+ Version: 0.2.25
4
4
  Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -29,17 +29,17 @@ Dynamic: license-file
29
29
 
30
30
  ## AI Cost Tracking
31
31
 
32
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.22-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
33
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-11.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
32
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.25-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
33
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-14.3h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
34
34
 
35
- - 🤖 **LLM usage:** $1.8607 (34 commits)
36
- - 👤 **Human dev:** ~$1113 (11.1h @ $100/h, 30min dedup)
35
+ - 🤖 **LLM usage:** $1.8622 (35 commits)
36
+ - 👤 **Human dev:** ~$1432 (14.3h @ $100/h, 30min dedup)
37
37
 
38
- Generated on 2026-05-12 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
38
+ Generated on 2026-05-15 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
39
39
 
40
40
  ---
41
41
 
42
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.22-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
42
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.25-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
43
43
 
44
44
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
45
45
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes