wup 0.1.10__tar.gz → 0.2.2__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.
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wup
3
- Version: 0.1.10
3
+ Version: 0.2.2
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
7
- Project-URL: Homepage, https://github.com/yourusername/wup
8
- Project-URL: Repository, https://github.com/yourusername/wup
7
+ Project-URL: Homepage, https://github.com/semcod/wup
8
+ Project-URL: Repository, https://github.com/semcod/wup
9
9
  Keywords: wup,watcher,testing,regression,file-monitoring
10
10
  Classifier: Development Status :: 3 - Alpha
11
11
  Classifier: Intended Audience :: Developers
@@ -28,17 +28,17 @@ Dynamic: license-file
28
28
 
29
29
  ## AI Cost Tracking
30
30
 
31
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.1.10-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
32
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$0.60-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-2.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
31
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.2-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
32
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$0.90-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-2.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
33
33
 
34
- - 🤖 **LLM usage:** $0.6000 (4 commits)
34
+ - 🤖 **LLM usage:** $0.9000 (6 commits)
35
35
  - 👤 **Human dev:** ~$200 (2.0h @ $100/h, 30min dedup)
36
36
 
37
37
  Generated on 2026-04-29 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
38
38
 
39
39
  ---
40
40
 
41
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.1.10-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
41
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.2-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
42
42
 
43
43
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
44
44
 
@@ -56,6 +56,9 @@ WUP monitors file changes and runs intelligent regression tests using a 3-layer
56
56
  - 🔍 **Dependency Mapping**: Automatic detection of files → endpoints → services
57
57
  - 🚀 **Framework Support**: FastAPI, Flask, Django, Express.js, and more
58
58
  - 📝 **Blame Reports**: Detailed regression reports with file/line/commit info
59
+ - ⚙️ **Configuration System**: Declarative configuration via `wup.yaml` file
60
+ - 🎛️ **Per-Service Settings**: Custom test strategies per service
61
+ - 🧪 **TestQL Integration**: Native support for TestQL scenarios
59
62
 
60
63
  ## Installation
61
64
 
@@ -70,13 +73,16 @@ pip install -e ".[dev]"
70
73
  ## Quick Start
71
74
 
72
75
  ```bash
73
- # 1. Build dependency map (one-time setup)
76
+ # 1. Initialize configuration (optional)
77
+ wup init
78
+
79
+ # 2. Build dependency map (one-time setup)
74
80
  wup map-deps ./my-project
75
81
 
76
- # 2. Start watching for changes
82
+ # 3. Start watching for changes
77
83
  wup watch ./my-project
78
84
 
79
- # 3. Start with live dashboard
85
+ # 4. Start with live dashboard
80
86
  wup watch ./my-project --dashboard
81
87
  ```
82
88
 
@@ -98,7 +104,7 @@ wup map-deps ./my-project --output my-deps.json
98
104
  ### Watch Project
99
105
 
100
106
  ```bash
101
- # Basic watching
107
+ # Basic watching (uses wup.yaml if present)
102
108
  wup watch ./my-project
103
109
 
104
110
  # With custom settings
@@ -109,6 +115,22 @@ wup watch ./my-project \
109
115
 
110
116
  # With live dashboard
111
117
  wup watch ./my-project --dashboard
118
+
119
+ # Use specific config file
120
+ wup watch ./my-project --config custom-config.yaml
121
+
122
+ # TestQL mode
123
+ wup watch ./my-project --mode testql
124
+ ```
125
+
126
+ ### Initialize Configuration
127
+
128
+ ```bash
129
+ # Generate default wup.yaml configuration
130
+ wup init
131
+
132
+ # Generate with custom output path
133
+ wup init --output .wup.yaml
112
134
  ```
113
135
 
114
136
  ### Check Status
@@ -160,15 +182,87 @@ Full regression: 15s test → 15% CPU spike
160
182
 
161
183
  ## Configuration
162
184
 
185
+ ### wup.yaml Configuration File
186
+
187
+ WUP supports declarative configuration via `wup.yaml` (or `.wup.yaml`) in your project root. This allows you to define watch paths, service-specific settings, and test strategies.
188
+
189
+ Generate a default configuration:
190
+
191
+ ```bash
192
+ wup init
193
+ ```
194
+
195
+ Example `wup.yaml`:
196
+
197
+ ```yaml
198
+ project:
199
+ name: "my-project"
200
+ description: "My awesome project"
201
+
202
+ watch:
203
+ # Folders to watch (supports glob patterns)
204
+ paths:
205
+ - "app/**"
206
+ - "src/**"
207
+ - "routes/**"
208
+ - "!tests/**" # exclusion
209
+ - "!node_modules/**"
210
+
211
+ # Global exclude patterns
212
+ exclude_patterns:
213
+ - "*.md"
214
+ - "*.txt"
215
+ - "migrations/**"
216
+
217
+ services:
218
+ # Service configurations
219
+ - name: "users"
220
+ root: "app/users"
221
+ paths:
222
+ - "app/users/**"
223
+ - "routes/users/**"
224
+ quick_tests:
225
+ scope: "read,write"
226
+ max_endpoints: 3
227
+ detail_tests:
228
+ scope: "all"
229
+ max_endpoints: 10
230
+ cpu_throttle: 0.7
231
+ notify:
232
+ type: "http+file"
233
+ url: "http://localhost:8001/notify"
234
+ file: "wup/notify-users.json"
235
+
236
+ test_strategy:
237
+ quick:
238
+ debounce_s: 2
239
+ max_queue: 5
240
+ timeout_s: 10
241
+ detail:
242
+ debounce_s: 10
243
+ max_queue: 1
244
+ timeout_s: 30
245
+
246
+ testql:
247
+ # TestQL-specific configuration
248
+ scenario_dir: "scenarios/tests"
249
+ smoke_scenario: "smoke.testql.toon.yaml"
250
+ output_format: "json"
251
+ extra_args:
252
+ - "--timeout 10s"
253
+ ```
254
+
163
255
  ### CLI Options
164
256
 
165
257
  | Option | Default | Description |
166
258
  |--------|---------|-------------|
259
+ | `--config` | auto | Path to wup.yaml config file |
167
260
  | `--cpu-throttle` | 0.8 | CPU usage threshold (0.0-1.0) |
168
261
  | `--debounce` | 2 | Debounce time in seconds |
169
262
  | `--cooldown` | 300 | Test cooldown in seconds |
170
263
  | `--dashboard` | false | Enable live dashboard |
171
264
  | `--deps` | deps.json | Dependency map file path |
265
+ | `--mode` | default | Watcher mode: default or testql |
172
266
 
173
267
  ### Environment Variables
174
268
 
@@ -213,11 +307,21 @@ async def run_detail_test(self, service: str, endpoints: List[str]) -> Dict:
213
307
  wup/
214
308
  ├── wup/
215
309
  │ ├── __init__.py # Package exports
310
+ │ ├── config.py # Configuration loader
311
+ │ ├── models/
312
+ │ │ ├── __init__.py # Models package
313
+ │ │ └── config.py # Configuration dataclasses
216
314
  │ ├── core.py # WupWatcher implementation
217
315
  │ ├── dependency_mapper.py # Dependency mapping logic
316
+ │ ├── testql_watcher.py # TestQL integration
218
317
  │ └── cli.py # CLI interface
219
318
  ├── tests/
220
319
  │ └── test_wup.py # Unit tests
320
+ ├── docs/
321
+ │ ├── 2.md # Refactoring documentation
322
+ │ ├── 3.md # Configuration plan
323
+ │ └── TESTQL_INTEGRATION.md # TestQL integration docs
324
+ ├── wup.yaml.example # Example configuration
221
325
  ├── pyproject.toml # Package configuration
222
326
  └── README.md # This file
223
327
  ```
@@ -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.1.10-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-$0.60-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-2.0h-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.2-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-$0.90-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-2.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
8
8
 
9
- - 🤖 **LLM usage:** $0.6000 (4 commits)
9
+ - 🤖 **LLM usage:** $0.9000 (6 commits)
10
10
  - 👤 **Human dev:** ~$200 (2.0h @ $100/h, 30min dedup)
11
11
 
12
12
  Generated on 2026-04-29 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.1.10-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.2-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
 
@@ -31,6 +31,9 @@ WUP monitors file changes and runs intelligent regression tests using a 3-layer
31
31
  - 🔍 **Dependency Mapping**: Automatic detection of files → endpoints → services
32
32
  - 🚀 **Framework Support**: FastAPI, Flask, Django, Express.js, and more
33
33
  - 📝 **Blame Reports**: Detailed regression reports with file/line/commit info
34
+ - ⚙️ **Configuration System**: Declarative configuration via `wup.yaml` file
35
+ - 🎛️ **Per-Service Settings**: Custom test strategies per service
36
+ - 🧪 **TestQL Integration**: Native support for TestQL scenarios
34
37
 
35
38
  ## Installation
36
39
 
@@ -45,13 +48,16 @@ pip install -e ".[dev]"
45
48
  ## Quick Start
46
49
 
47
50
  ```bash
48
- # 1. Build dependency map (one-time setup)
51
+ # 1. Initialize configuration (optional)
52
+ wup init
53
+
54
+ # 2. Build dependency map (one-time setup)
49
55
  wup map-deps ./my-project
50
56
 
51
- # 2. Start watching for changes
57
+ # 3. Start watching for changes
52
58
  wup watch ./my-project
53
59
 
54
- # 3. Start with live dashboard
60
+ # 4. Start with live dashboard
55
61
  wup watch ./my-project --dashboard
56
62
  ```
57
63
 
@@ -73,7 +79,7 @@ wup map-deps ./my-project --output my-deps.json
73
79
  ### Watch Project
74
80
 
75
81
  ```bash
76
- # Basic watching
82
+ # Basic watching (uses wup.yaml if present)
77
83
  wup watch ./my-project
78
84
 
79
85
  # With custom settings
@@ -84,6 +90,22 @@ wup watch ./my-project \
84
90
 
85
91
  # With live dashboard
86
92
  wup watch ./my-project --dashboard
93
+
94
+ # Use specific config file
95
+ wup watch ./my-project --config custom-config.yaml
96
+
97
+ # TestQL mode
98
+ wup watch ./my-project --mode testql
99
+ ```
100
+
101
+ ### Initialize Configuration
102
+
103
+ ```bash
104
+ # Generate default wup.yaml configuration
105
+ wup init
106
+
107
+ # Generate with custom output path
108
+ wup init --output .wup.yaml
87
109
  ```
88
110
 
89
111
  ### Check Status
@@ -135,15 +157,87 @@ Full regression: 15s test → 15% CPU spike
135
157
 
136
158
  ## Configuration
137
159
 
160
+ ### wup.yaml Configuration File
161
+
162
+ WUP supports declarative configuration via `wup.yaml` (or `.wup.yaml`) in your project root. This allows you to define watch paths, service-specific settings, and test strategies.
163
+
164
+ Generate a default configuration:
165
+
166
+ ```bash
167
+ wup init
168
+ ```
169
+
170
+ Example `wup.yaml`:
171
+
172
+ ```yaml
173
+ project:
174
+ name: "my-project"
175
+ description: "My awesome project"
176
+
177
+ watch:
178
+ # Folders to watch (supports glob patterns)
179
+ paths:
180
+ - "app/**"
181
+ - "src/**"
182
+ - "routes/**"
183
+ - "!tests/**" # exclusion
184
+ - "!node_modules/**"
185
+
186
+ # Global exclude patterns
187
+ exclude_patterns:
188
+ - "*.md"
189
+ - "*.txt"
190
+ - "migrations/**"
191
+
192
+ services:
193
+ # Service configurations
194
+ - name: "users"
195
+ root: "app/users"
196
+ paths:
197
+ - "app/users/**"
198
+ - "routes/users/**"
199
+ quick_tests:
200
+ scope: "read,write"
201
+ max_endpoints: 3
202
+ detail_tests:
203
+ scope: "all"
204
+ max_endpoints: 10
205
+ cpu_throttle: 0.7
206
+ notify:
207
+ type: "http+file"
208
+ url: "http://localhost:8001/notify"
209
+ file: "wup/notify-users.json"
210
+
211
+ test_strategy:
212
+ quick:
213
+ debounce_s: 2
214
+ max_queue: 5
215
+ timeout_s: 10
216
+ detail:
217
+ debounce_s: 10
218
+ max_queue: 1
219
+ timeout_s: 30
220
+
221
+ testql:
222
+ # TestQL-specific configuration
223
+ scenario_dir: "scenarios/tests"
224
+ smoke_scenario: "smoke.testql.toon.yaml"
225
+ output_format: "json"
226
+ extra_args:
227
+ - "--timeout 10s"
228
+ ```
229
+
138
230
  ### CLI Options
139
231
 
140
232
  | Option | Default | Description |
141
233
  |--------|---------|-------------|
234
+ | `--config` | auto | Path to wup.yaml config file |
142
235
  | `--cpu-throttle` | 0.8 | CPU usage threshold (0.0-1.0) |
143
236
  | `--debounce` | 2 | Debounce time in seconds |
144
237
  | `--cooldown` | 300 | Test cooldown in seconds |
145
238
  | `--dashboard` | false | Enable live dashboard |
146
239
  | `--deps` | deps.json | Dependency map file path |
240
+ | `--mode` | default | Watcher mode: default or testql |
147
241
 
148
242
  ### Environment Variables
149
243
 
@@ -188,11 +282,21 @@ async def run_detail_test(self, service: str, endpoints: List[str]) -> Dict:
188
282
  wup/
189
283
  ├── wup/
190
284
  │ ├── __init__.py # Package exports
285
+ │ ├── config.py # Configuration loader
286
+ │ ├── models/
287
+ │ │ ├── __init__.py # Models package
288
+ │ │ └── config.py # Configuration dataclasses
191
289
  │ ├── core.py # WupWatcher implementation
192
290
  │ ├── dependency_mapper.py # Dependency mapping logic
291
+ │ ├── testql_watcher.py # TestQL integration
193
292
  │ └── cli.py # CLI interface
194
293
  ├── tests/
195
294
  │ └── test_wup.py # Unit tests
295
+ ├── docs/
296
+ │ ├── 2.md # Refactoring documentation
297
+ │ ├── 3.md # Configuration plan
298
+ │ └── TESTQL_INTEGRATION.md # TestQL integration docs
299
+ ├── wup.yaml.example # Example configuration
196
300
  ├── pyproject.toml # Package configuration
197
301
  └── README.md # This file
198
302
  ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wup"
7
- version = "0.1.10"
7
+ version = "0.2.2"
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"
@@ -33,8 +33,8 @@ classifiers = [
33
33
  wup = "wup.cli:app"
34
34
 
35
35
  [project.urls]
36
- Homepage = "https://github.com/yourusername/wup"
37
- Repository = "https://github.com/yourusername/wup"
36
+ Homepage = "https://github.com/semcod/wup"
37
+ Repository = "https://github.com/semcod/wup"
38
38
 
39
39
  [tool.pfix]
40
40
  # Self-healing Python configuration
@@ -0,0 +1,89 @@
1
+ import asyncio
2
+ import json
3
+ import tempfile
4
+ from pathlib import Path
5
+ from subprocess import CompletedProcess
6
+
7
+ from wup.testql_watcher import TestQLWatcher
8
+ from wup.models.config import WupConfig, ProjectConfig
9
+
10
+
11
+ def test_process_changed_file_creates_track_on_failure():
12
+ with tempfile.TemporaryDirectory() as tmpdir:
13
+ root = Path(tmpdir)
14
+ app_file = root / "app" / "users" / "routes.py"
15
+ app_file.parent.mkdir(parents=True, exist_ok=True)
16
+ app_file.write_text("print('x')\n", encoding="utf-8")
17
+
18
+ scenario_dir = root / "testql-scenarios"
19
+ scenario_dir.mkdir(parents=True, exist_ok=True)
20
+ failing_scenario = scenario_dir / "api-users-failing.testql.toon.yaml"
21
+ failing_scenario.write_text("name: failing\n", encoding="utf-8")
22
+
23
+ # Pass empty config to prevent loading from temp dir
24
+ empty_config = WupConfig(
25
+ project=ProjectConfig(name="test"),
26
+ services=[],
27
+ test_strategy=None,
28
+ testql=None
29
+ )
30
+ watcher = TestQLWatcher(
31
+ project_root=str(root),
32
+ deps_file=str(root / "deps.json"),
33
+ scenarios_dir="testql-scenarios",
34
+ track_dir=".wup/tracks",
35
+ config=empty_config,
36
+ )
37
+
38
+ watcher.dependency_mapper.service_to_endpoints["app/users"] = ["/api/v1/users"]
39
+
40
+ def fake_run_testql(args, timeout):
41
+ if "--dry-run" in args:
42
+ return CompletedProcess(args=args, returncode=1, stdout="", stderr="intentional failure")
43
+ return CompletedProcess(args=args, returncode=0, stdout="{}", stderr="")
44
+
45
+ watcher._run_testql = fake_run_testql # type: ignore[method-assign]
46
+
47
+ result = asyncio.run(watcher.process_changed_file_once(str(app_file)))
48
+
49
+ assert result["processed_items"] >= 1
50
+ assert result["last_track_path"] is not None
51
+
52
+ track_path = Path(result["last_track_path"])
53
+ assert track_path.exists()
54
+
55
+ track_payload = json.loads(track_path.read_text(encoding="utf-8"))
56
+ assert track_payload["service"] == "app/users"
57
+ assert track_payload["stage"] == "quick"
58
+ assert "intentional failure" in track_payload["stderr_head"]
59
+
60
+
61
+ def test_browser_event_file_is_written_without_service_url():
62
+ with tempfile.TemporaryDirectory() as tmpdir:
63
+ root = Path(tmpdir)
64
+ scenario_dir = root / "testql-scenarios"
65
+ scenario_dir.mkdir(parents=True, exist_ok=True)
66
+ scenario_file = scenario_dir / "api-users-smoke.testql.toon.yaml"
67
+ scenario_file.write_text("name: smoke\n", encoding="utf-8")
68
+
69
+ watcher = TestQLWatcher(
70
+ project_root=str(root),
71
+ deps_file=str(root / "deps.json"),
72
+ scenarios_dir="testql-scenarios",
73
+ track_dir=".wup/tracks",
74
+ )
75
+
76
+ result = CompletedProcess(args=["testql", "run"], returncode=1, stdout="", stderr="boom")
77
+ track_path = watcher._write_track(
78
+ service="app/users",
79
+ stage="quick",
80
+ scenario=scenario_file,
81
+ result=result,
82
+ )
83
+
84
+ assert track_path.exists()
85
+ event_file = root / ".wup" / "browser-events" / "latest.json"
86
+ assert event_file.exists()
87
+ event_payload = json.loads(event_file.read_text(encoding="utf-8"))
88
+ assert event_payload["type"] == "wup_testql_error"
89
+ assert event_payload["service"] == "app/users"