radarflake 1.1.1__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 (43) hide show
  1. radarflake-1.1.1/LICENSE +21 -0
  2. radarflake-1.1.1/PKG-INFO +370 -0
  3. radarflake-1.1.1/README.md +333 -0
  4. radarflake-1.1.1/pyproject.toml +70 -0
  5. radarflake-1.1.1/setup.cfg +4 -0
  6. radarflake-1.1.1/src/flakeradar/__init__.py +7 -0
  7. radarflake-1.1.1/src/flakeradar/badge.py +59 -0
  8. radarflake-1.1.1/src/flakeradar/cli.py +436 -0
  9. radarflake-1.1.1/src/flakeradar/clustering.py +99 -0
  10. radarflake-1.1.1/src/flakeradar/config.py +164 -0
  11. radarflake-1.1.1/src/flakeradar/gitinfo.py +33 -0
  12. radarflake-1.1.1/src/flakeradar/llm/__init__.py +43 -0
  13. radarflake-1.1.1/src/flakeradar/llm/analyzer.py +149 -0
  14. radarflake-1.1.1/src/flakeradar/llm/anthropic_provider.py +41 -0
  15. radarflake-1.1.1/src/flakeradar/llm/base.py +28 -0
  16. radarflake-1.1.1/src/flakeradar/llm/gemini_provider.py +36 -0
  17. radarflake-1.1.1/src/flakeradar/llm/groq_provider.py +42 -0
  18. radarflake-1.1.1/src/flakeradar/llm/ollama_provider.py +39 -0
  19. radarflake-1.1.1/src/flakeradar/llm/openai_provider.py +42 -0
  20. radarflake-1.1.1/src/flakeradar/plugin.py +152 -0
  21. radarflake-1.1.1/src/flakeradar/py.typed +0 -0
  22. radarflake-1.1.1/src/flakeradar/quarantine.py +119 -0
  23. radarflake-1.1.1/src/flakeradar/report.py +206 -0
  24. radarflake-1.1.1/src/flakeradar/scoring.py +133 -0
  25. radarflake-1.1.1/src/flakeradar/storage.py +216 -0
  26. radarflake-1.1.1/src/flakeradar/summary.py +79 -0
  27. radarflake-1.1.1/src/radarflake.egg-info/PKG-INFO +370 -0
  28. radarflake-1.1.1/src/radarflake.egg-info/SOURCES.txt +41 -0
  29. radarflake-1.1.1/src/radarflake.egg-info/dependency_links.txt +1 -0
  30. radarflake-1.1.1/src/radarflake.egg-info/entry_points.txt +5 -0
  31. radarflake-1.1.1/src/radarflake.egg-info/requires.txt +11 -0
  32. radarflake-1.1.1/src/radarflake.egg-info/top_level.txt +1 -0
  33. radarflake-1.1.1/tests/test_analyzer.py +83 -0
  34. radarflake-1.1.1/tests/test_badge.py +35 -0
  35. radarflake-1.1.1/tests/test_cli.py +99 -0
  36. radarflake-1.1.1/tests/test_clustering.py +47 -0
  37. radarflake-1.1.1/tests/test_config.py +65 -0
  38. radarflake-1.1.1/tests/test_plugin_integration.py +78 -0
  39. radarflake-1.1.1/tests/test_quarantine.py +71 -0
  40. radarflake-1.1.1/tests/test_report.py +49 -0
  41. radarflake-1.1.1/tests/test_scoring.py +69 -0
  42. radarflake-1.1.1/tests/test_storage.py +76 -0
  43. radarflake-1.1.1/tests/test_summary.py +59 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lethe044
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,370 @@
1
+ Metadata-Version: 2.4
2
+ Name: radarflake
3
+ Version: 1.1.1
4
+ Summary: Flaky test detection, historical tracking, and AI-assisted root cause analysis for pytest
5
+ Author: Lethe044
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Lethe044/flakeradar
8
+ Project-URL: Repository, https://github.com/Lethe044/flakeradar
9
+ Project-URL: Issues, https://github.com/Lethe044/flakeradar/issues
10
+ Project-URL: Changelog, https://github.com/Lethe044/flakeradar/blob/main/CHANGELOG.md
11
+ Keywords: pytest,testing,flaky-tests,ci,test-reliability,quality-assurance
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Framework :: Pytest
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Testing
24
+ Classifier: Topic :: Software Development :: Quality Assurance
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: pytest>=7.0
29
+ Requires-Dist: requests>=2.28
30
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0; extra == "dev"
33
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
34
+ Requires-Dist: build>=1.0; extra == "dev"
35
+ Requires-Dist: twine>=4.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # flakeradar
39
+
40
+ Flaky test detection, historical tracking, and AI-assisted root cause analysis for pytest.
41
+
42
+ [![CI](https://github.com/Lethe044/flakeradar/actions/workflows/ci.yml/badge.svg)](https://github.com/Lethe044/flakeradar/actions/workflows/ci.yml)
43
+ [![PyPI](https://img.shields.io/pypi/v/radarflake.svg)](https://pypi.org/project/radarflake/)
44
+ [![Python versions](https://img.shields.io/pypi/pyversions/radarflake.svg)](https://pypi.org/project/radarflake/)
45
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
46
+
47
+ A test that fails one run in twenty and passes the other nineteen is worse
48
+ than a test that always fails. The always-failing test gets fixed the same
49
+ day. The occasional failure gets re-run, ignored, and eventually nobody
50
+ trusts a red CI run again.
51
+
52
+ flakeradar tracks every test run over time, tells you which tests are
53
+ actually flaky versus just plain broken, clusters the failures by root
54
+ cause, and can optionally ask a free-tier LLM to explain what's probably
55
+ going wrong, all without requiring a paid API key or a hosted service.
56
+
57
+ ## Why not just re-run failed tests?
58
+
59
+ Retrying failures hides the problem instead of measuring it. flakeradar
60
+ takes a different approach:
61
+
62
+ - **It measures flakiness properly.** A test that fails 100% of the time
63
+ isn't flaky, it's broken. flakeradar's scoring is based on how often a
64
+ test's outcome *flips* between runs, not just its raw failure rate, so
65
+ real bugs and genuine flakiness get classified differently.
66
+ - **It keeps history, not just the current run.** Flakiness usually only
67
+ becomes obvious over dozens of runs. flakeradar persists results to a
68
+ local SQLite database so trends build up across CI runs, not just within
69
+ one `pytest` invocation.
70
+ - **It doesn't require an API key to be useful.** The scoring, clustering,
71
+ quarantine list, and HTML report all work with zero configuration. AI
72
+ root cause analysis is an optional layer on top, and it works with free
73
+ tiers (Groq, Gemini) or a fully local model (Ollama), not just paid APIs.
74
+ - **It stays out of your way in CI.** Quarantined tests are skipped, not
75
+ deleted or silently ignored. The quarantine list is a plain text file
76
+ meant to be reviewed in code review, with auto-added and manually pinned
77
+ entries kept clearly separate.
78
+
79
+ ## Installation
80
+
81
+ ```bash
82
+ pip install radarflake
83
+ ```
84
+
85
+ The PyPI distribution is named `radarflake` (the original `flakeradar` name
86
+ was already taken by an unrelated project). Everything else - the CLI
87
+ command, the `import flakeradar` module name, and the `pytest --flakeradar`
88
+ flag - is unaffected.
89
+
90
+ Requires Python 3.9 or newer and pytest 7 or newer. No other required
91
+ dependencies beyond `requests` for optional AI calls.
92
+
93
+ ## Quickstart
94
+
95
+ ```bash
96
+ # 1. Scaffold a config file (optional but recommended)
97
+ flakeradar init
98
+
99
+ # 2. Run your test suite with tracking enabled
100
+ pytest --flakeradar
101
+
102
+ # Run it a few more times (or let it run over a few days of CI) so there's
103
+ # enough history to classify tests confidently.
104
+ pytest --flakeradar
105
+ pytest --flakeradar
106
+
107
+ # 3. See what's flaky
108
+ flakeradar report --open
109
+ ```
110
+
111
+ The report is a single self-contained HTML file. No CDN calls, no external
112
+ JavaScript, safe to attach to a ticket or open with no internet connection.
113
+
114
+ ### Don't want to wait for CI history to build up?
115
+
116
+ Stress-test a specific test right now by running it repeatedly:
117
+
118
+ ```bash
119
+ flakeradar stress tests/test_checkout.py -k test_apply_discount -n 30 --analyze
120
+ ```
121
+
122
+ This runs the test 30 times in a row, records the outcomes, prints a
123
+ flakiness score immediately, and (with `--analyze` and a provider
124
+ configured) asks an LLM for a root cause hypothesis.
125
+
126
+ Try it on the bundled example file to see the whole flow without touching
127
+ your own test suite:
128
+
129
+ ```bash
130
+ flakeradar stress examples/demo_flaky_tests.py -k test_race_condition -n 30
131
+ flakeradar report --open
132
+ ```
133
+
134
+ ## How flakiness is scored
135
+
136
+ Each test gets a score from 0.0 to 1.0, combining two signals:
137
+
138
+ - **Transition rate**: how often the outcome flips from one run to the
139
+ next. A test that alternates pass, fail, pass, fail has a transition
140
+ rate of 1.0. A test that's always green (or always red) has a
141
+ transition rate of 0.0.
142
+ - **Balance**: how close the pass/fail split is to 50/50, which is the
143
+ pattern most associated with genuine non-determinism.
144
+
145
+ ```
146
+ score = 0.6 x transition_rate + 0.4 x balance
147
+ ```
148
+
149
+ Tests are then classified as:
150
+
151
+ | Classification | Meaning |
152
+ |---------------------|------------------------------------------------------------------|
153
+ | `stable` | Consistently passing (or consistently skipped) |
154
+ | `flaky` | Score at or above the threshold (default `0.15`) |
155
+ | `broken` | Fails almost every run with little to no flipping - likely a real bug, not flakiness |
156
+ | `insufficient_data` | Fewer recorded runs than `min_runs` (default `5`) |
157
+
158
+ Both thresholds are configurable in `flakeradar.toml`.
159
+
160
+ ## AI-assisted root cause analysis
161
+
162
+ Statistics tell you *that* a test is flaky. The AI layer is an optional
163
+ extra step that tries to explain *why*, by looking at the clustered
164
+ failure tracebacks and (if you point it at the source file) the test code
165
+ itself.
166
+
167
+ ```bash
168
+ flakeradar analyze tests/test_checkout.py::test_apply_discount --source tests/test_checkout.py
169
+ ```
170
+
171
+ Example output:
172
+
173
+ ```
174
+ tests/test_checkout.py::test_apply_discount
175
+ runs=24 fail_rate=29% score=0.41 -> flaky
176
+ 2 distinct failure cluster(s)
177
+
178
+ AI root cause analysis (confidence: high)
179
+ Category: Race condition
180
+ Explanation: The two failure clusters both involve the discount total
181
+ being read before the async cart update finishes, which
182
+ matches an unawaited coroutine in apply_discount().
183
+ Suggested fix: Await cart.update() before reading cart.total in the
184
+ discount calculation, or add an explicit synchronization
185
+ point in the test fixture.
186
+ ```
187
+
188
+ ### Supported providers
189
+
190
+ | Provider | Cost | Setup |
191
+ |-------------|--------------------------------|-----------------------------------------------------|
192
+ | `groq` | Free tier | `FLAKERADAR_LLM_PROVIDER=groq`, `GROQ_API_KEY=...` |
193
+ | `gemini` | Free tier | `FLAKERADAR_LLM_PROVIDER=gemini`, `GEMINI_API_KEY=...` |
194
+ | `ollama` | Free, fully local, no API key | `FLAKERADAR_LLM_PROVIDER=ollama` (Ollama running locally) |
195
+ | `openai` | Paid, bring your own key | `FLAKERADAR_LLM_PROVIDER=openai`, `OPENAI_API_KEY=...` |
196
+ | `anthropic` | Paid, bring your own key | `FLAKERADAR_LLM_PROVIDER=anthropic`, `ANTHROPIC_API_KEY=...` |
197
+
198
+ If `llm_provider` is left as `none` (the default), everything except
199
+ `flakeradar analyze`'s AI section still works normally, the statistical
200
+ output is always shown regardless of whether AI analysis succeeds.
201
+
202
+ ## Quarantining flaky tests
203
+
204
+ Once a test is confirmed flaky, you usually don't want it blocking merges
205
+ while someone investigates. flakeradar can auto-manage a quarantine list:
206
+
207
+ ```bash
208
+ flakeradar quarantine sync # add/remove tests based on current scores
209
+ flakeradar quarantine list # see what's currently quarantined and why
210
+ ```
211
+
212
+ Then, in CI, skip quarantined tests instead of letting them fail the build:
213
+
214
+ ```bash
215
+ pytest --flakeradar --flakeradar-quarantine
216
+ ```
217
+
218
+ The quarantine file (`.flakeradar/quarantine.txt`) is plain text and meant
219
+ to be committed to version control:
220
+
221
+ ```
222
+ tests/test_payments.py::test_webhook_retry # score=0.42, auto-added 2026-08-20
223
+ tests/test_upload.py::test_large_file # manually pinned, see #482
224
+ ```
225
+
226
+ Entries with an `auto-added` comment are managed automatically by
227
+ `flakeradar quarantine sync` and get removed once a test stabilizes.
228
+ Entries without that marker are treated as manually pinned and are never
229
+ touched by `sync`, so a human decision to hold a test back doesn't get
230
+ silently reverted.
231
+
232
+ Preview changes before committing to them:
233
+
234
+ ```bash
235
+ flakeradar quarantine sync --dry-run
236
+ ```
237
+
238
+ ## Visibility in CI
239
+
240
+ Two lightweight extras help flakiness stay visible without anyone having
241
+ to remember to open the HTML report.
242
+
243
+ **Job summaries.** When `pytest --flakeradar` runs inside GitHub Actions,
244
+ it automatically writes a short Markdown summary of that run's failing
245
+ tests - flagged as known-flaky, consistently-failing, or unexpectedly
246
+ failing - to the job summary tab. No configuration needed; it activates
247
+ whenever `GITHUB_STEP_SUMMARY` is set.
248
+
249
+ **A status badge.** Generate a small, self-contained SVG badge showing the
250
+ current flaky test count:
251
+
252
+ ```bash
253
+ flakeradar badge --out flakeradar-badge.svg
254
+ ```
255
+
256
+ The badge has no external service dependency, it's rendered entirely
257
+ locally. Commit it or upload it as a CI artifact and reference it from
258
+ your README:
259
+
260
+ ```markdown
261
+ ![flaky tests](flakeradar-badge.svg)
262
+ ```
263
+
264
+ **A CI health gate.** Separate from per-test quarantine, you can fail a
265
+ build outright if overall flakiness crosses a budget:
266
+
267
+ ```bash
268
+ flakeradar report --max-flaky 5 --max-broken 0
269
+ ```
270
+
271
+ **Machine-readable output.** For custom dashboards or other tooling:
272
+
273
+ ```bash
274
+ flakeradar report --format json --out flakeradar-report.json
275
+ ```
276
+
277
+ ## CI integration
278
+
279
+ flakeradar's own database is per-machine by default, so in CI you need to
280
+ persist it between runs (otherwise every run starts from zero history).
281
+ Here's a minimal GitHub Actions example; a fuller version with quarantine
282
+ sync and report upload lives in
283
+ [`examples/github-workflow-example.yml`](examples/github-workflow-example.yml)
284
+ (copy it into your own project's `.github/workflows/`, it is not an active
285
+ workflow in this repo).
286
+
287
+ ```yaml
288
+ - name: Restore flaky-test history
289
+ uses: actions/cache@v4
290
+ with:
291
+ path: .flakeradar/history.db
292
+ key: flakeradar-history-${{ github.ref_name }}
293
+ restore-keys: flakeradar-history-main
294
+
295
+ - name: Run tests with tracking
296
+ run: pytest --flakeradar --flakeradar-quarantine
297
+
298
+ - name: Save updated history
299
+ uses: actions/cache/save@v4
300
+ if: always()
301
+ with:
302
+ path: .flakeradar/history.db
303
+ key: flakeradar-history-${{ github.ref_name }}-${{ github.run_id }}
304
+ ```
305
+
306
+ ## Configuration reference
307
+
308
+ flakeradar reads configuration from, in order of priority (highest first):
309
+
310
+ 1. CLI flags
311
+ 2. Environment variables (`FLAKERADAR_*`)
312
+ 3. `flakeradar.toml` in the project root
313
+ 4. `[tool.flakeradar]` in `pyproject.toml`
314
+ 5. Built-in defaults
315
+
316
+ See [`flakeradar.toml.example`](flakeradar.toml.example) for every
317
+ available option with comments.
318
+
319
+ ## CLI reference
320
+
321
+ ```
322
+ flakeradar init Scaffold a flakeradar.toml config file
323
+ flakeradar report [--open] [--out PATH] [--format html|json] [--max-flaky N] [--max-broken N]
324
+ Generate the flakiness report
325
+ flakeradar history <nodeid> Print raw pass/fail history for one test
326
+ flakeradar stress <path> [-k EXPR] [-n N] [--analyze]
327
+ Run a test repeatedly right now
328
+ flakeradar analyze <nodeid> [--source PATH]
329
+ AI root cause analysis for one test
330
+ flakeradar quarantine list|sync [--dry-run]|add|remove
331
+ Manage the quarantine list
332
+ flakeradar badge [--out PATH] [--label TEXT]
333
+ Generate an SVG flaky-test-count badge
334
+ ```
335
+
336
+ Run `flakeradar <command> --help` for the full set of flags on any
337
+ subcommand.
338
+
339
+ ## FAQ
340
+
341
+ **Does this slow down my test suite?**
342
+ `pytest --flakeradar` only adds an in-memory hook that records outcomes and
343
+ writes them once at the end of the session. The overhead is negligible for
344
+ any suite where the tests themselves take more than a few milliseconds
345
+ each.
346
+
347
+ **Does it work with `pytest-xdist`?**
348
+ Yes, results from parallel workers are recorded the same way as a
349
+ sequential run. Note that `--flakeradar-quarantine` marks are applied at
350
+ collection time on each worker, so quarantine changes made mid-run by
351
+ another process won't retroactively apply within that same session.
352
+
353
+ **Where is the data stored?**
354
+ Locally, in a SQLite file at `.flakeradar/history.db` by default. Nothing
355
+ is sent anywhere unless you explicitly enable an AI provider, in which
356
+ case only the specific failure tracebacks and test name for the test
357
+ you're analyzing are sent to that provider, never your whole suite.
358
+
359
+ **What happens if I don't configure an LLM provider?**
360
+ Everything works except the AI explanation text. Scoring, history,
361
+ reports, and quarantine management have no dependency on AI at all.
362
+
363
+ ## Contributing
364
+
365
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for how
366
+ to get set up and what to keep in mind before opening a pull request.
367
+
368
+ ## License
369
+
370
+ MIT. See [LICENSE](LICENSE).