flakestat 0.1.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.

Potentially problematic release.


This version of flakestat might be problematic. Click here for more details.

@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: flakestat
3
+ Version: 0.1.0
4
+ Summary: Find flaky tests in any language - pytest, Jest, go test, JUnit. Local CLI, no SaaS, no account.
5
+ Author: flakestat contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rowhitswami/flakestat
8
+ Project-URL: Issues, https://github.com/rowhitswami/flakestat/issues
9
+ Project-URL: Source, https://github.com/rowhitswami/flakestat
10
+ Keywords: flaky,flaky-tests,flaky-test-detection,test-flakiness,flake-detection,test-stability,pytest,testing,junit,ci,quarantine
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Testing
16
+ Classifier: Topic :: Software Development :: Quality Assurance
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+
20
+ # flakestat
21
+
22
+ Find flaky tests in any language. No SaaS, no account, no data leaving your machine.
23
+
24
+ A flaky test passes and fails randomly **on the same code**. flakestat tells you
25
+ exactly which ones, ranked worst first.
26
+
27
+ ```bash
28
+ flakestat hunt --runs 20 \
29
+ --junit 'reports/junit-{run}.xml' \
30
+ -- pytest -q --junitxml='reports/junit-{run}.xml'
31
+ ```
32
+
33
+ ```
34
+ VERDICT SCORE RUNS PASS/FAIL TEST
35
+ flaky 0.62 20 14/6 tests.test_auth::test_refresh_token
36
+ consistently-failing 0.00 20 0/20 tests.test_billing::test_discount
37
+
38
+ 1 flaky, 0 suspect, 1 consistently failing, 1 stable, 1 unscored (of 4 tests)
39
+ ```
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install flakestat
45
+ ```
46
+
47
+ This package downloads the prebuilt `flakestat` binary for your platform
48
+ (macOS, Linux, Windows on x86_64/arm64) from GitHub Releases on first use. It has
49
+ no Python dependencies, so it cannot interfere with your project's resolution.
50
+
51
+ ## Why the verdicts matter
52
+
53
+ **Flakiness is inconsistency, not failure.** A test that fails 100% of the time
54
+ scores 1.0 on failure rate but isn't flaky — it's broken. flakestat scores
55
+ *state transitions* (pass→fail→pass), so an always-failing test correctly scores
56
+ zero and is reported separately as `consistently-failing` instead of being mixed
57
+ in with real flakes.
58
+
59
+ Skipped tests are excluded rather than treated as passes, so `@pytest.mark.skip`
60
+ never manufactures a phantom transition.
61
+
62
+ ## How it compares
63
+
64
+ `pytest-rerunfailures` and `pytest-flakefinder` retry tests so a run goes green.
65
+ That hides the symptom. flakestat *measures* which tests are unreliable and by
66
+ how much, so they can be fixed — and it works across every suite in a polyglot
67
+ repo, not just the Python one.
68
+
69
+ ## Tracking over time
70
+
71
+ A burst proves flakiness exists. History *measures* it, and catches
72
+ environment-dependent flakes a local burst never will.
73
+
74
+ ```bash
75
+ flakestat ingest 'reports/**/*.xml' # in CI, after tests
76
+ flakestat report --top 20
77
+ flakestat report --fail-on-flaky # exit 1 to gate a pipeline
78
+ ```
79
+
80
+ History lives in `.flakestat/runs.ndjson` — one JSON object per line. Commit it
81
+ for shared team history, or keep it as a CI artifact.
82
+
83
+ ## Environment variables
84
+
85
+ | Variable | Effect |
86
+ |---|---|
87
+ | `FLAKESTAT_BINARY` | Use this binary instead of downloading |
88
+ | `FLAKESTAT_SKIP_DOWNLOAD` | Fail instead of downloading |
89
+ | `FLAKESTAT_CACHE_DIR` | Where the binary is cached |
90
+
91
+ ## Full documentation
92
+
93
+ <https://github.com/rowhitswami/flakestat>
94
+
95
+ MIT
@@ -0,0 +1,76 @@
1
+ # flakestat
2
+
3
+ Find flaky tests in any language. No SaaS, no account, no data leaving your machine.
4
+
5
+ A flaky test passes and fails randomly **on the same code**. flakestat tells you
6
+ exactly which ones, ranked worst first.
7
+
8
+ ```bash
9
+ flakestat hunt --runs 20 \
10
+ --junit 'reports/junit-{run}.xml' \
11
+ -- pytest -q --junitxml='reports/junit-{run}.xml'
12
+ ```
13
+
14
+ ```
15
+ VERDICT SCORE RUNS PASS/FAIL TEST
16
+ flaky 0.62 20 14/6 tests.test_auth::test_refresh_token
17
+ consistently-failing 0.00 20 0/20 tests.test_billing::test_discount
18
+
19
+ 1 flaky, 0 suspect, 1 consistently failing, 1 stable, 1 unscored (of 4 tests)
20
+ ```
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ pip install flakestat
26
+ ```
27
+
28
+ This package downloads the prebuilt `flakestat` binary for your platform
29
+ (macOS, Linux, Windows on x86_64/arm64) from GitHub Releases on first use. It has
30
+ no Python dependencies, so it cannot interfere with your project's resolution.
31
+
32
+ ## Why the verdicts matter
33
+
34
+ **Flakiness is inconsistency, not failure.** A test that fails 100% of the time
35
+ scores 1.0 on failure rate but isn't flaky — it's broken. flakestat scores
36
+ *state transitions* (pass→fail→pass), so an always-failing test correctly scores
37
+ zero and is reported separately as `consistently-failing` instead of being mixed
38
+ in with real flakes.
39
+
40
+ Skipped tests are excluded rather than treated as passes, so `@pytest.mark.skip`
41
+ never manufactures a phantom transition.
42
+
43
+ ## How it compares
44
+
45
+ `pytest-rerunfailures` and `pytest-flakefinder` retry tests so a run goes green.
46
+ That hides the symptom. flakestat *measures* which tests are unreliable and by
47
+ how much, so they can be fixed — and it works across every suite in a polyglot
48
+ repo, not just the Python one.
49
+
50
+ ## Tracking over time
51
+
52
+ A burst proves flakiness exists. History *measures* it, and catches
53
+ environment-dependent flakes a local burst never will.
54
+
55
+ ```bash
56
+ flakestat ingest 'reports/**/*.xml' # in CI, after tests
57
+ flakestat report --top 20
58
+ flakestat report --fail-on-flaky # exit 1 to gate a pipeline
59
+ ```
60
+
61
+ History lives in `.flakestat/runs.ndjson` — one JSON object per line. Commit it
62
+ for shared team history, or keep it as a CI artifact.
63
+
64
+ ## Environment variables
65
+
66
+ | Variable | Effect |
67
+ |---|---|
68
+ | `FLAKESTAT_BINARY` | Use this binary instead of downloading |
69
+ | `FLAKESTAT_SKIP_DOWNLOAD` | Fail instead of downloading |
70
+ | `FLAKESTAT_CACHE_DIR` | Where the binary is cached |
71
+
72
+ ## Full documentation
73
+
74
+ <https://github.com/rowhitswami/flakestat>
75
+
76
+ MIT
@@ -0,0 +1,37 @@
1
+ """flakestat - find flaky tests in any language.
2
+
3
+ This package is a thin wrapper that fetches and runs the flakestat binary.
4
+ The tool itself is written in Go; see https://github.com/rowhitswami/flakestat.
5
+ """
6
+
7
+ import subprocess
8
+ import sys
9
+
10
+ from ._binary import InstallError, ensure_binary
11
+
12
+ # Kept in step with the released binary by CI at publish time.
13
+ __version__ = "0.0.0"
14
+
15
+ __all__ = ["main", "ensure_binary", "InstallError", "__version__"]
16
+
17
+
18
+ def main() -> int:
19
+ """Console-script entry point: exec the binary, preserving the exit code."""
20
+ try:
21
+ binary = ensure_binary()
22
+ except InstallError as exc:
23
+ print(str(exc), file=sys.stderr)
24
+ return 1
25
+
26
+ try:
27
+ # CI gates depend on the exit code, so pass it straight through.
28
+ return subprocess.call([str(binary)] + sys.argv[1:])
29
+ except KeyboardInterrupt:
30
+ return 130
31
+ except OSError as exc:
32
+ print("flakestat: {}".format(exc), file=sys.stderr)
33
+ return 1
34
+
35
+
36
+ if __name__ == "__main__":
37
+ sys.exit(main())
@@ -0,0 +1,8 @@
1
+ """Support `python -m flakestat` alongside the console script."""
2
+
3
+ import sys
4
+
5
+ from . import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())
@@ -0,0 +1,184 @@
1
+ """Resolve the flakestat binary, downloading it on first use.
2
+
3
+ pip has no post-install hook, and building a Go binary at install time would
4
+ require a Go toolchain on the user's machine. So the binary is fetched from
5
+ GitHub Releases the first time it is needed and cached per version.
6
+
7
+ Everything here is stdlib: the wrapper must never interfere with a user's
8
+ dependency resolution.
9
+ """
10
+
11
+ import hashlib
12
+ import os
13
+ import platform
14
+ import shutil
15
+ import stat
16
+ import sys
17
+ import tarfile
18
+ import tempfile
19
+ import urllib.error
20
+ import urllib.request
21
+ import zipfile
22
+ from pathlib import Path
23
+
24
+ OWNER = "rowhitswami"
25
+ REPO = "flakestat"
26
+
27
+
28
+ class InstallError(RuntimeError):
29
+ """Raised when the binary cannot be obtained."""
30
+
31
+
32
+ def _version() -> str:
33
+ from . import __version__
34
+
35
+ return __version__
36
+
37
+
38
+ def _target():
39
+ """Map this interpreter's platform onto the release archive naming."""
40
+ system = platform.system().lower()
41
+ goos = {"darwin": "darwin", "linux": "linux", "windows": "windows"}.get(system)
42
+
43
+ machine = platform.machine().lower()
44
+ goarch = {
45
+ "x86_64": "amd64",
46
+ "amd64": "amd64",
47
+ "aarch64": "arm64",
48
+ "arm64": "arm64",
49
+ }.get(machine)
50
+
51
+ if not goos or not goarch:
52
+ raise InstallError(
53
+ "flakestat: unsupported platform {}/{}.\n"
54
+ "Prebuilt binaries cover macOS, Linux and Windows on x86_64 and arm64.\n"
55
+ "Build from source instead:\n"
56
+ " go install github.com/{}/{}/cmd/{}@latest".format(
57
+ system, machine, OWNER, REPO, REPO
58
+ )
59
+ )
60
+
61
+ return goos, goarch
62
+
63
+
64
+ def _cache_dir() -> Path:
65
+ """Per-version cache, so upgrading the wrapper fetches a matching binary."""
66
+ if os.environ.get("FLAKESTAT_CACHE_DIR"):
67
+ base = Path(os.environ["FLAKESTAT_CACHE_DIR"])
68
+ elif sys.platform == "win32":
69
+ base = Path(os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local"))
70
+ elif sys.platform == "darwin":
71
+ base = Path.home() / "Library" / "Caches"
72
+ else:
73
+ base = Path(os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache"))
74
+
75
+ return base / "flakestat" / _version()
76
+
77
+
78
+ def _binary_name() -> str:
79
+ return "flakestat.exe" if sys.platform == "win32" else "flakestat"
80
+
81
+
82
+ def _fetch(url: str) -> bytes:
83
+ try:
84
+ with urllib.request.urlopen(url) as resp: # noqa: S310 - fixed https host
85
+ return resp.read()
86
+ except urllib.error.HTTPError as exc:
87
+ raise InstallError("flakestat: GET {} -> {}".format(url, exc.code)) from exc
88
+ except urllib.error.URLError as exc:
89
+ raise InstallError(
90
+ "flakestat: could not reach {} ({})".format(url, exc.reason)
91
+ ) from exc
92
+
93
+
94
+ def _verify(archive_name: str, blob: bytes, base_url: str) -> None:
95
+ try:
96
+ sums = _fetch("{}/checksums.txt".format(base_url)).decode("utf-8")
97
+ except InstallError:
98
+ print("flakestat: checksums.txt unavailable, skipping verification", file=sys.stderr)
99
+ return
100
+
101
+ expected = None
102
+ for line in sums.splitlines():
103
+ if line.strip().endswith(archive_name):
104
+ expected = line.split()[0]
105
+ break
106
+
107
+ if expected is None:
108
+ return
109
+
110
+ actual = hashlib.sha256(blob).hexdigest()
111
+ if expected != actual:
112
+ raise InstallError(
113
+ "flakestat: checksum mismatch for {}\n expected: {}\n actual: {}".format(
114
+ archive_name, expected, actual
115
+ )
116
+ )
117
+
118
+
119
+ def _download(dest: Path) -> None:
120
+ goos, goarch = _target()
121
+ version = _version()
122
+ ext = "zip" if goos == "windows" else "tar.gz"
123
+
124
+ archive = "{}_{}_{}_{}.{}".format(REPO, version, goos, goarch, ext)
125
+ base_url = "https://github.com/{}/{}/releases/download/v{}".format(OWNER, REPO, version)
126
+
127
+ print(
128
+ "flakestat: downloading {} v{} ({}/{})".format(REPO, version, goos, goarch),
129
+ file=sys.stderr,
130
+ )
131
+
132
+ blob = _fetch("{}/{}".format(base_url, archive))
133
+ _verify(archive, blob, base_url)
134
+
135
+ name = _binary_name()
136
+
137
+ with tempfile.TemporaryDirectory() as tmp:
138
+ tmp_path = Path(tmp)
139
+ archive_path = tmp_path / archive
140
+ archive_path.write_bytes(blob)
141
+
142
+ if ext == "zip":
143
+ with zipfile.ZipFile(archive_path) as zf:
144
+ zf.extract(name, tmp_path)
145
+ else:
146
+ with tarfile.open(archive_path) as tf:
147
+ member = tf.getmember(name)
148
+ # Refuse absolute paths and traversal in archive members.
149
+ if member.name != name or Path(member.name).is_absolute():
150
+ raise InstallError("flakestat: unexpected archive member {}".format(member.name))
151
+ tf.extract(member, tmp_path)
152
+
153
+ dest.parent.mkdir(parents=True, exist_ok=True)
154
+
155
+ # Move into place via a temporary name so concurrent installs cannot
156
+ # observe a half-written binary.
157
+ staged = dest.parent / (dest.name + ".tmp")
158
+ shutil.move(str(tmp_path / name), str(staged))
159
+ staged.chmod(staged.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
160
+ os.replace(str(staged), str(dest))
161
+
162
+ print("flakestat: installed to {}".format(dest), file=sys.stderr)
163
+
164
+
165
+ def ensure_binary() -> Path:
166
+ """Return the path to the binary, downloading it if needed."""
167
+ override = os.environ.get("FLAKESTAT_BINARY")
168
+ if override:
169
+ path = Path(override)
170
+ if not path.exists():
171
+ raise InstallError("flakestat: FLAKESTAT_BINARY={} does not exist".format(override))
172
+ return path
173
+
174
+ dest = _cache_dir() / _binary_name()
175
+ if dest.exists():
176
+ return dest
177
+
178
+ if os.environ.get("FLAKESTAT_SKIP_DOWNLOAD"):
179
+ raise InstallError(
180
+ "flakestat: binary missing and FLAKESTAT_SKIP_DOWNLOAD is set"
181
+ )
182
+
183
+ _download(dest)
184
+ return dest
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: flakestat
3
+ Version: 0.1.0
4
+ Summary: Find flaky tests in any language - pytest, Jest, go test, JUnit. Local CLI, no SaaS, no account.
5
+ Author: flakestat contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rowhitswami/flakestat
8
+ Project-URL: Issues, https://github.com/rowhitswami/flakestat/issues
9
+ Project-URL: Source, https://github.com/rowhitswami/flakestat
10
+ Keywords: flaky,flaky-tests,flaky-test-detection,test-flakiness,flake-detection,test-stability,pytest,testing,junit,ci,quarantine
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Testing
16
+ Classifier: Topic :: Software Development :: Quality Assurance
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+
20
+ # flakestat
21
+
22
+ Find flaky tests in any language. No SaaS, no account, no data leaving your machine.
23
+
24
+ A flaky test passes and fails randomly **on the same code**. flakestat tells you
25
+ exactly which ones, ranked worst first.
26
+
27
+ ```bash
28
+ flakestat hunt --runs 20 \
29
+ --junit 'reports/junit-{run}.xml' \
30
+ -- pytest -q --junitxml='reports/junit-{run}.xml'
31
+ ```
32
+
33
+ ```
34
+ VERDICT SCORE RUNS PASS/FAIL TEST
35
+ flaky 0.62 20 14/6 tests.test_auth::test_refresh_token
36
+ consistently-failing 0.00 20 0/20 tests.test_billing::test_discount
37
+
38
+ 1 flaky, 0 suspect, 1 consistently failing, 1 stable, 1 unscored (of 4 tests)
39
+ ```
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install flakestat
45
+ ```
46
+
47
+ This package downloads the prebuilt `flakestat` binary for your platform
48
+ (macOS, Linux, Windows on x86_64/arm64) from GitHub Releases on first use. It has
49
+ no Python dependencies, so it cannot interfere with your project's resolution.
50
+
51
+ ## Why the verdicts matter
52
+
53
+ **Flakiness is inconsistency, not failure.** A test that fails 100% of the time
54
+ scores 1.0 on failure rate but isn't flaky — it's broken. flakestat scores
55
+ *state transitions* (pass→fail→pass), so an always-failing test correctly scores
56
+ zero and is reported separately as `consistently-failing` instead of being mixed
57
+ in with real flakes.
58
+
59
+ Skipped tests are excluded rather than treated as passes, so `@pytest.mark.skip`
60
+ never manufactures a phantom transition.
61
+
62
+ ## How it compares
63
+
64
+ `pytest-rerunfailures` and `pytest-flakefinder` retry tests so a run goes green.
65
+ That hides the symptom. flakestat *measures* which tests are unreliable and by
66
+ how much, so they can be fixed — and it works across every suite in a polyglot
67
+ repo, not just the Python one.
68
+
69
+ ## Tracking over time
70
+
71
+ A burst proves flakiness exists. History *measures* it, and catches
72
+ environment-dependent flakes a local burst never will.
73
+
74
+ ```bash
75
+ flakestat ingest 'reports/**/*.xml' # in CI, after tests
76
+ flakestat report --top 20
77
+ flakestat report --fail-on-flaky # exit 1 to gate a pipeline
78
+ ```
79
+
80
+ History lives in `.flakestat/runs.ndjson` — one JSON object per line. Commit it
81
+ for shared team history, or keep it as a CI artifact.
82
+
83
+ ## Environment variables
84
+
85
+ | Variable | Effect |
86
+ |---|---|
87
+ | `FLAKESTAT_BINARY` | Use this binary instead of downloading |
88
+ | `FLAKESTAT_SKIP_DOWNLOAD` | Fail instead of downloading |
89
+ | `FLAKESTAT_CACHE_DIR` | Where the binary is cached |
90
+
91
+ ## Full documentation
92
+
93
+ <https://github.com/rowhitswami/flakestat>
94
+
95
+ MIT
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ flakestat/__init__.py
4
+ flakestat/__main__.py
5
+ flakestat/_binary.py
6
+ flakestat.egg-info/PKG-INFO
7
+ flakestat.egg-info/SOURCES.txt
8
+ flakestat.egg-info/dependency_links.txt
9
+ flakestat.egg-info/entry_points.txt
10
+ flakestat.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ flakestat = flakestat:main
@@ -0,0 +1 @@
1
+ flakestat
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "flakestat"
7
+ version = "0.1.0"
8
+ description = "Find flaky tests in any language - pytest, Jest, go test, JUnit. Local CLI, no SaaS, no account."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "flakestat contributors" }]
13
+ keywords = [
14
+ "flaky",
15
+ "flaky-tests",
16
+ "flaky-test-detection",
17
+ "test-flakiness",
18
+ "flake-detection",
19
+ "test-stability",
20
+ "pytest",
21
+ "testing",
22
+ "junit",
23
+ "ci",
24
+ "quarantine",
25
+ ]
26
+ classifiers = [
27
+ "Development Status :: 3 - Alpha",
28
+ "Intended Audience :: Developers",
29
+ "License :: OSI Approved :: MIT License",
30
+ "Programming Language :: Python :: 3",
31
+ "Topic :: Software Development :: Testing",
32
+ "Topic :: Software Development :: Quality Assurance",
33
+ ]
34
+ # No runtime dependencies on purpose: everything used here is stdlib, so the
35
+ # wrapper cannot break a user's dependency resolution.
36
+ dependencies = []
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/rowhitswami/flakestat"
40
+ Issues = "https://github.com/rowhitswami/flakestat/issues"
41
+ Source = "https://github.com/rowhitswami/flakestat"
42
+
43
+ [project.scripts]
44
+ flakestat = "flakestat:main"
45
+
46
+ [tool.setuptools]
47
+ packages = ["flakestat"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+