pintest-cli 0.2.0__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.
@@ -0,0 +1,527 @@
1
+ Metadata-Version: 2.4
2
+ Name: pintest-cli
3
+ Version: 0.2.0
4
+ Summary: Run only the tests affected by your code changes.
5
+ Author: Pintest Contributors
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: pytest>=7.0.0
16
+ Requires-Dist: pytest-cov>=4.0.0
17
+ Requires-Dist: coverage[toml]>=7.0.0
18
+ Requires-Dist: requests>=2.25.0
19
+ Dynamic: author
20
+ Dynamic: classifier
21
+ Dynamic: description
22
+ Dynamic: description-content-type
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
26
+
27
+ # Pintest
28
+
29
+ **Run only the tests affected by your code changes** - automatically!
30
+
31
+ Pintest integrates with your git workflow as a pre-commit hook, running only tests that cover the code you've changed. This dramatically speeds up your development cycle while ensuring quality.
32
+
33
+ ## 🎯 Key Features
34
+
35
+ - **🚀 Fast**: Run only affected tests, not the entire suite
36
+ - **🔒 Safe**: Blocks commits if affected tests fail
37
+ - **📊 Intelligent**: Uses SQLite-based test-to-code mapping for instant lookups
38
+ - **🔄 Incremental Coverage**: Combines coverage from test runs
39
+ - **✨ New Test Detection**: Always runs newly added tests
40
+ - **🧠 Auto-Discovery**: Detects unmapped tests and builds mapping automatically
41
+ - **🎣 Pre-commit Hook**: Automatic integration with git workflow
42
+ - **🐳 Docker Integration**: Ensures containers are running before tests
43
+ - **🔧 Preflight Checks**: Validates database connections (postgres, neo4j)
44
+ - **📦 Git LFS Support**: Shares pre-built mapping database across team (30-60min savings)
45
+ - **🚀 Auto-Push**: Automatically pushes commits with updated mapping database
46
+
47
+ ## ⚡ Quick Start (Pre-Commit Hook)
48
+
49
+ ```bash
50
+ cd ~/workspace/myproject
51
+
52
+ # Install the pre-commit hook
53
+ ~/workspace/all/pintest/scripts/install_pre_commit.sh
54
+
55
+ # That's it! Now every commit will:
56
+ # 1. Find tests affected by your changes
57
+ # 2. Run only those tests
58
+ # 3. Block commit if tests fail
59
+ # 4. Combine coverage with existing data
60
+ ```
61
+
62
+ ## 📋 How It Works
63
+
64
+ ### Pre-Commit Flow
65
+
66
+ ```
67
+ Developer commits changes
68
+
69
+ Pre-commit hook triggered
70
+
71
+ Compare staged changes vs development branch
72
+
73
+ Query SQLite mapping: "Which tests cover these lines?"
74
+
75
+ Detect unmapped tests (dry-run pytest --collect-only)
76
+
77
+ Run unmapped tests all-at-once (build mapping)
78
+
79
+ Run mapped affected tests with coverage
80
+
81
+ Tests pass? → Combine coverage → Allow commit ✅
82
+ Tests fail? → Block commit ❌
83
+ ```
84
+
85
+ ### Auto-Discovery of Unmapped Tests
86
+
87
+ The pre-commit hook automatically detects tests that exist in your codebase but aren't in the mapping database yet:
88
+
89
+ 1. **Collect all tests**: Runs `pytest --collect-only` to find all available tests
90
+ 2. **Compare with mapping**: Queries `.test_mapping.db` to see which tests are already mapped
91
+ 3. **Find delta**: Identifies tests that exist but have never been run with coverage
92
+ 4. **Run all-at-once**: Executes all unmapped tests together with `--cov-context=test` (fastest)
93
+ 5. **Update mapping**: After completion, updates the mapping database with new coverage
94
+
95
+ **Why this matters:**
96
+ - New tests you write are automatically added to the mapping
97
+ - Tests added by teammates get mapped when you first commit
98
+ - No need to manually regenerate the entire mapping
99
+ - Mapping database grows organically over time
100
+ - All tests run in a single pytest invocation (fastest possible)
101
+
102
+ **Example:**
103
+
104
+ ```bash
105
+ $ git commit -m "Fix bug in auth.py"
106
+
107
+ 📝 Found 1 changed Python file
108
+ 📊 Mapping DB: 1234 tests, 567 files, 45678 mappings
109
+ 🔍 Collected 1250 total tests from pytest
110
+ ⚠️ Found 16 unmapped test(s)
111
+
112
+ ================================================================================
113
+ Building coverage mapping for 16 unmapped test(s)
114
+ ================================================================================
115
+
116
+ Running unmapped test: unit_tests/test_new_feature.py::test_case_1
117
+ ✓ Mapping updated for: unit_tests/test_new_feature.py::test_case_1
118
+ Running unmapped test: unit_tests/test_new_feature.py::test_case_2
119
+ ✓ Mapping updated for: unit_tests/test_new_feature.py::test_case_2
120
+ ...
121
+ ✓ Successfully mapped 16 test(s)
122
+
123
+ ================================================================================
124
+ Running 3 affected test(s)...
125
+ ================================================================================
126
+ ...
127
+ ```
128
+
129
+ ### Mapping Database
130
+
131
+ The mapping is stored in `.test_mapping.db` (SQLite) at your repo root:
132
+
133
+ ```sql
134
+ CREATE TABLE test_coverage (
135
+ test_name TEXT,
136
+ file_path TEXT,
137
+ line_number INTEGER,
138
+ PRIMARY KEY (test_name, file_path, line_number)
139
+ );
140
+ ```
141
+
142
+ Fast lookups: "Which tests cover file X, line Y?"
143
+
144
+ ## 🔧 Installation
145
+
146
+ ### Prerequisites
147
+
148
+ - Python 3.8+
149
+ - pytest >= 7.0
150
+ - pytest-cov >= 4.0
151
+ - Git repository
152
+
153
+ ### Step 1: Install Package
154
+
155
+ ```bash
156
+ cd ~/workspace/all/pintest
157
+ pip install -e .
158
+ ```
159
+
160
+ ### Step 2: Generate Initial Coverage
161
+
162
+ ```bash
163
+ cd ~/workspace/myproject
164
+
165
+ # Run all tests with coverage context enabled
166
+ pytest --cov=. --cov-context=test --cov-report=
167
+ ```
168
+
169
+ This creates `.coverage` file with test-to-code mappings.
170
+
171
+ ### Step 3: Create Mapping Database
172
+
173
+ Choose one of two methods:
174
+
175
+ **Option A: Iterative (Recommended for large test suites )**
176
+
177
+ ```bash
178
+ # Build mapping by running tests one-by-one (resumable)
179
+ pintest build-mapping --repo-root ~/workspace/myproject --verbose
180
+
181
+ # If interrupted, resume with:
182
+ pintest build-mapping --repo-root ~/workspace/myproject --resume --verbose
183
+ ```
184
+
185
+ **Benefits:**
186
+ - ✅ Resumable after interruption or failure
187
+ - ✅ Progress saved every 10 tests
188
+ - ✅ Safe for 20,000+ test suites
189
+ - ✅ Continues even if some tests fail
190
+
191
+ **Time:** ~2-4 hours , but can be interrupted and resumed anytime.
192
+
193
+ **Option B: Batch (Faster, but not resumable)**
194
+
195
+ ```bash
196
+ # Run all tests with coverage at once
197
+ pytest --cov=. --cov-context=test --cov-report=
198
+
199
+ # Build mapping from coverage
200
+ pintest update-mapping --repo-root ~/workspace/myproject --verbose
201
+ ```
202
+
203
+ **Benefits:**
204
+ - ✅ Faster (45-90 minutes )
205
+ - ✅ Single command
206
+
207
+ **Drawbacks:**
208
+ - ❌ Not resumable if interrupted
209
+ - ❌ Stops on first failure
210
+ - ❌ Must regenerate from scratch
211
+
212
+ 📖 **See [ITERATIVE_SETUP_GUIDE.md](ITERATIVE_SETUP_GUIDE.md) for detailed guide**
213
+
214
+ **Option C: Use Pre-built Database (Git LFS)**
215
+
216
+ If your repo uses Git LFS to store `.test_mapping.db`, you can skip building:
217
+
218
+ ```bash
219
+ # Install Git LFS (one-time)
220
+ brew install git-lfs # macOS
221
+ # or: sudo apt-get install git-lfs # Linux
222
+
223
+ # Initialize in repo
224
+ cd ~/workspace/myproject
225
+ git lfs install
226
+
227
+ # Pull the pre-built database
228
+ git lfs pull
229
+ ```
230
+
231
+ **Benefits:**
232
+ - ✅ Instant - no rebuild needed
233
+ - ✅ Shared across team
234
+ - ✅ Always available after clone/pull
235
+
236
+ See GIT_LFS_SETUP.md in your repo.
237
+
238
+ ### Step 4: Install Pre-Commit Hook
239
+
240
+ ```bash
241
+ cd ~/workspace/myproject
242
+ ~/workspace/all/pintest/scripts/install_pre_commit.sh
243
+ ```
244
+
245
+ Done! Now every commit will run only affected tests.
246
+
247
+ ## 📖 Usage
248
+
249
+ ### Pre-Commit Hook (Automatic)
250
+
251
+ Just commit normally:
252
+
253
+ ```bash
254
+ git add src/my_module.py
255
+ git commit -m "Fix bug in authentication"
256
+
257
+ # Hook runs automatically:
258
+ # - Finds tests covering src/my_module.py
259
+ # - Runs only those tests
260
+ # - Blocks commit if tests fail
261
+ # - Combines coverage on success
262
+ ```
263
+
264
+ ### Manual Test Running
265
+
266
+ ```bash
267
+ # Show what tests would run
268
+ pintest run --repo-root ~/workspace/myproject --dry-run --verbose
269
+
270
+ # Run affected tests manually
271
+ pintest run --repo-root ~/workspace/myproject
272
+
273
+ # Compare against different branch
274
+ pintest run --repo-root ~/workspace/myproject --base-branch develop
275
+
276
+ # Pass pytest arguments
277
+ pintest run --repo-root ~/workspace/myproject -- -x --pdb
278
+ ```
279
+
280
+ ### Update Mapping
281
+
282
+ Update the mapping database when you add new tests or change coverage significantly:
283
+
284
+ **Regular updates (batch):**
285
+
286
+ ```bash
287
+ # Run tests with coverage
288
+ pytest --cov=. --cov-context=test --cov-report=
289
+
290
+ # Update mapping database
291
+ pintest update-mapping --repo-root ~/workspace/myproject --verbose
292
+ ```
293
+
294
+ **After adding many tests (iterative):**
295
+
296
+ ```bash
297
+ # Resume where you left off (only runs unmapped tests)
298
+ pintest build-mapping --repo-root ~/workspace/myproject --resume --verbose
299
+ ```
300
+
301
+ **When to update:**
302
+ - After adding new test files
303
+ - After significant refactoring
304
+ - Weekly (recommended for active projects)
305
+ - When mapping feels "stale" (tests not being selected correctly)
306
+
307
+ ## 🎛️ Commands
308
+
309
+ ### `pintest run`
310
+
311
+ Run affected tests based on changes.
312
+
313
+ ```bash
314
+ pintest run [OPTIONS] [-- PYTEST_ARGS]
315
+
316
+ Options:
317
+ --repo-root PATH Repository root (default: current directory)
318
+ --base-branch BRANCH Branch to compare against (default: master)
319
+ --coverage-file PATH Path to .coverage file
320
+ --dry-run Show tests without running
321
+ --min-tests N Minimum tests required
322
+ -v, --verbose Detailed output
323
+ ```
324
+
325
+ ### `pintest update-mapping`
326
+
327
+ Update test mapping database from coverage data.
328
+
329
+ ```bash
330
+ pintest update-mapping [OPTIONS]
331
+
332
+ Options:
333
+ --repo-root PATH Repository root (default: current directory)
334
+ --coverage-file PATH Source .coverage file
335
+ --mapping-db PATH Target mapping database path
336
+ -v, --verbose Detailed output
337
+ ```
338
+
339
+ ## 🔍 How Test Selection Works
340
+
341
+ ### 1. Changed Files Detection
342
+
343
+ ```bash
344
+ git diff --cached development...HEAD
345
+ ```
346
+
347
+ Identifies:
348
+ - Which Python files changed
349
+ - Which lines were added/modified
350
+ - Which files are test files
351
+
352
+ ### 2. Test Mapping Lookup
353
+
354
+ ```sql
355
+ SELECT DISTINCT test_name
356
+ FROM test_coverage
357
+ WHERE file_path = 'src/auth.py'
358
+ AND line_number IN (42, 43, 44)
359
+ ```
360
+
361
+ Fast O(1) lookup using SQLite indexes.
362
+
363
+ ### 3. Test Categories
364
+
365
+ | Category | Always Run? | Example |
366
+ |----------|-------------|---------|
367
+ | **New tests** | ✅ Yes | `test_new_feature.py` (added in commit) |
368
+ | **Modified tests** | ✅ Yes | `test_auth.py` (changed in commit) |
369
+ | **Coverage-based** | ✅ Yes | Tests that cover changed lines |
370
+ | **Unaffected** | ❌ No | Tests not covering any changes |
371
+
372
+ ### 4. Coverage Combining
373
+
374
+ ```python
375
+ # Existing coverage from previous runs
376
+ .coverage (before)
377
+
378
+ # New coverage from affected tests
379
+ .coverage.new
380
+
381
+ # Combined result
382
+ .coverage (after) = .coverage (before) + .coverage.new
383
+ ```
384
+
385
+ Uses `coverage combine` to merge data safely.
386
+
387
+ ## 💡 Examples
388
+
389
+ ### Example 1: Bug Fix
390
+
391
+ ```bash
392
+ # You fix a bug in src/auth.py line 42
393
+ vim src/auth.py
394
+
395
+ git add src/auth.py
396
+ git commit -m "Fix login timeout bug"
397
+
398
+ # Hook runs:
399
+ # 📝 Found 1 changed Python file
400
+ # 📊 Mapping DB: 1234 tests, 567 files
401
+ # 📍 src/auth.py: 3 test(s) cover changed lines
402
+ # - unit_tests/test_auth.py::test_login_timeout
403
+ # - unit_tests/test_auth.py::test_login_retry
404
+ # - integration_tests/test_full_auth_flow.py::test_complete_flow
405
+ #
406
+ # Running 3 affected test(s)...
407
+ # ✅ All tests passed. Commit allowed.
408
+ ```
409
+
410
+ ### Example 2: New Test Added
411
+
412
+ ```bash
413
+ # You add a new test file
414
+ vim unit_tests/test_new_feature.py
415
+
416
+ git add unit_tests/test_new_feature.py
417
+ git commit -m "Add tests for new feature"
418
+
419
+ # Hook runs:
420
+ # ✨ New test files (always run): 1
421
+ # + unit_tests/test_new_feature.py
422
+ #
423
+ # Running 1 test file...
424
+ # ✅ All tests passed. Commit allowed.
425
+ ```
426
+
427
+ ### Example 3: Refactoring
428
+
429
+ ```bash
430
+ # You refactor a utility function used everywhere
431
+ vim src/utils/helpers.py
432
+
433
+ git add src/utils/helpers.py
434
+ git commit -m "Refactor helper function"
435
+
436
+ # Hook runs:
437
+ # 📍 src/utils/helpers.py: 47 test(s) cover changed lines
438
+ #
439
+ # Running 47 affected test(s)...
440
+ # (Only runs 47, not all 1234 tests!)
441
+ ```
442
+
443
+ ## 🚫 Bypassing the Hook
444
+
445
+ For urgent commits or when hook is broken:
446
+
447
+ ```bash
448
+ git commit --no-verify -m "Urgent hotfix"
449
+ ```
450
+
451
+ ## 🔧 Configuration
452
+
453
+ ### Change Base Branch
454
+
455
+ Edit `.git/hooks/pre-commit`:
456
+
457
+ ```bash
458
+ python3 -m pintest.pre_commit_hook \
459
+ --repo-root "$REPO_ROOT" \
460
+ --base-branch main \ # Changed from development
461
+ --verbose
462
+ ```
463
+
464
+ ### Customize Coverage Options
465
+
466
+ The hook runs pytest with:
467
+
468
+ ```bash
469
+ pytest --cov=. --cov-context=test --cov-append --cov-report=
470
+ ```
471
+
472
+ To customize, edit `pintest/pre_commit_hook.py`.
473
+
474
+ ## 📊 Statistics
475
+
476
+ Typical time savings:
477
+
478
+ | Project Size | Total Tests | Avg Affected | Time Before | Time After | Savings |
479
+ |--------------|-------------|--------------|-------------|------------|---------|
480
+ | Small (500 tests) | 500 | ~15 | 2 min | 10 sec | 92% |
481
+ | Medium (2000 tests) | 2000 | ~30 | 8 min | 30 sec | 94% |
482
+ | Large (5000 tests) | 5000 | ~50 | 20 min | 1 min | 95% |
483
+
484
+ *Actual savings depend on test distribution and change scope.*
485
+
486
+ ## 🐛 Troubleshooting
487
+
488
+ **"Mapping database not found"**
489
+
490
+ ```bash
491
+ pintest update-mapping --repo-root ~/workspace/myproject
492
+ ```
493
+
494
+ **"No tests selected"**
495
+
496
+ - Check if `.coverage` file exists and is recent
497
+ - Update mapping: `pintest update-mapping`
498
+ - Run with `--verbose` to see what's happening
499
+
500
+ **"Tests that should run aren't selected"**
501
+
502
+ Regenerate coverage and mapping:
503
+
504
+ ```bash
505
+ pytest --cov=. --cov-context=test --cov-report=
506
+ pintest update-mapping --verbose
507
+ ```
508
+
509
+ **"Hook runs all tests"**
510
+
511
+ Check that mapping database exists:
512
+
513
+ ```bash
514
+ ls -lh .test_mapping.db
515
+ ```
516
+
517
+ If missing, generate it with `update-mapping`.
518
+
519
+ ## 📁 Files Created
520
+
521
+ - `.test_mapping.db` - SQLite database with test-to-code mappings (gitignored)
522
+ - `.coverage` - pytest coverage data (gitignored)
523
+ - `.git/hooks/pre-commit` - Pre-commit hook script
524
+
525
+ ## 🤝 Contributing
526
+
527
+ Pintest is an open-source developer productivity tool.