pytest-flakefighters 0.0.0__py3-none-any.whl → 0.1.5__py3-none-any.whl
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.
- _version.py +34 -0
- pytest_flakefighters/flakefighters/coverage_independence.py +6 -5
- pytest_flakefighters/flakefighters/deflaker.py +4 -3
- pytest_flakefighters/flakefighters/traceback_matching.py +8 -3
- pytest_flakefighters/function_coverage.py +1 -1
- pytest_flakefighters/main.py +6 -1
- pytest_flakefighters/plugin.py +1 -1
- pytest_flakefighters/rerun_strategies.py +1 -1
- {pytest_flakefighters-0.0.0.dist-info → pytest_flakefighters-0.1.5.dist-info}/METADATA +4 -25
- pytest_flakefighters-0.1.5.dist-info/RECORD +18 -0
- {pytest_flakefighters-0.0.0.dist-info → pytest_flakefighters-0.1.5.dist-info}/top_level.txt +1 -0
- pytest_flakefighters-0.0.0.dist-info/RECORD +0 -17
- {pytest_flakefighters-0.0.0.dist-info → pytest_flakefighters-0.1.5.dist-info}/WHEEL +0 -0
- {pytest_flakefighters-0.0.0.dist-info → pytest_flakefighters-0.1.5.dist-info}/entry_points.txt +0 -0
- {pytest_flakefighters-0.0.0.dist-info → pytest_flakefighters-0.1.5.dist-info}/licenses/LICENSE +0 -0
_version.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.1.5'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 5)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -18,13 +18,14 @@ class CoverageIndependence(FlakeFighter):
|
|
|
18
18
|
"""
|
|
19
19
|
Classify tests as flaky if they fail independently of passing test cases that exercise overlapping code.
|
|
20
20
|
|
|
21
|
+
:ivar run_live: Run detection "live" after each test. Otherwise run as a postprocessing step after the test suite.
|
|
22
|
+
This is always False as live classification is not supported.
|
|
21
23
|
:ivar threshold: The minimum distance to consider as "similar", expressed as a proportion 0 <= threshold < 1 where 0
|
|
22
|
-
|
|
23
|
-
:ivar metric:
|
|
24
|
-
|
|
25
|
-
'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule'].
|
|
24
|
+
represents no difference and 1 represents complete difference.
|
|
25
|
+
:ivar metric: The distance metric to use. For a full list of valid values,see the `SciPy documentation for spatial
|
|
26
|
+
distances <https://docs.scipy.org/doc/scipy/reference/spatial.distance.html>`_.
|
|
26
27
|
:ivar linkage_method: From `scipy.cluster.hierarchy.linkage`: ['single', 'complete', 'average', 'weighted',
|
|
27
|
-
|
|
28
|
+
'centroid', 'median', 'ward']
|
|
28
29
|
"""
|
|
29
30
|
|
|
30
31
|
def __init__(self, threshold: float = 0, metric: str = "jaccard", linkage_method="single"):
|
|
@@ -17,10 +17,11 @@ from pytest_flakefighters.flakefighters.abstract_flakefighter import FlakeFighte
|
|
|
17
17
|
|
|
18
18
|
class DeFlaker(FlakeFighter):
|
|
19
19
|
"""
|
|
20
|
-
A python equivalent of the DeFlaker algorithm from Bell et al. 2019
|
|
20
|
+
A python equivalent of the DeFlaker algorithm from `Bell et al. (2019) <https://doi.org/10.1145/3180155.3180164>`_.
|
|
21
21
|
Given the subtle differences between JUnit and pytest, this is not intended to be an exact port, but it follows
|
|
22
22
|
the same general methodology of checking whether covered code has been changed between commits.
|
|
23
23
|
|
|
24
|
+
:ivar run_live: Run detection "live" after each test. Otherwise run as a postprocessing step after the test suite.
|
|
24
25
|
:ivar root: The root directory of the Git repository.
|
|
25
26
|
:ivar source_commit: The source (older) commit hash. Defaults to HEAD^ (the previous commit to target).
|
|
26
27
|
:ivar target_commit: The target (newer) commit hash. Defaults to HEAD (the most recent commit).
|
|
@@ -95,8 +96,8 @@ class DeFlaker(FlakeFighter):
|
|
|
95
96
|
Classify an execution as flaky or not.
|
|
96
97
|
:return: Boolean True of the test is classed as flaky and False otherwise.
|
|
97
98
|
"""
|
|
98
|
-
return not any(
|
|
99
|
-
|
|
99
|
+
return execution.outcome != "passed" and not any(
|
|
100
|
+
self.line_modified_by_target_commit(file_path, line_number)
|
|
100
101
|
for file_path in execution.coverage
|
|
101
102
|
for line_number in execution.coverage[file_path]
|
|
102
103
|
if file_path in self.lines_changed
|
|
@@ -20,16 +20,18 @@ from pytest_flakefighters.flakefighters.abstract_flakefighter import FlakeFighte
|
|
|
20
20
|
|
|
21
21
|
class TracebackMatching(FlakeFighter):
|
|
22
22
|
"""
|
|
23
|
-
Simple text-based matching classifier from Section II.A of
|
|
23
|
+
Simple text-based matching classifier from Section II.A of
|
|
24
|
+
`Alshammari et al. (2024) <https://doi.org/10.1109/ICST60714.2024.00031>`_.
|
|
24
25
|
We implement text-based matching on the failure logs for each test. Each failure log is represented by its failure
|
|
25
26
|
exception and stacktrace.
|
|
27
|
+
|
|
28
|
+
:ivar run_live: Run detection "live" after each test. Otherwise run as a postprocessing step after the test suite.
|
|
26
29
|
"""
|
|
27
30
|
|
|
28
31
|
def __init__(self, run_live: bool, previous_runs: list[Run], root: str = "."):
|
|
29
32
|
super().__init__(run_live)
|
|
30
33
|
self.root = os.path.abspath(root)
|
|
31
34
|
self.previous_runs = previous_runs
|
|
32
|
-
print("TracebackMatching")
|
|
33
35
|
|
|
34
36
|
@classmethod
|
|
35
37
|
def from_config(cls, config: dict):
|
|
@@ -119,8 +121,11 @@ class TracebackMatching(FlakeFighter):
|
|
|
119
121
|
|
|
120
122
|
class CosineSimilarity(TracebackMatching):
|
|
121
123
|
"""
|
|
122
|
-
TF-IDF cosine similarity matching classifier from Section II.C of
|
|
124
|
+
TF-IDF cosine similarity matching classifier from Section II.C of
|
|
125
|
+
`Alshammari et al. (2024) <https://doi.org/10.1109/ICST60714.2024.00031>`_.
|
|
123
126
|
Test executions are classified as flaky if the stack trace is sufficiently similar to a previous flaky execution.
|
|
127
|
+
|
|
128
|
+
:ivar run_live: Run detection "live" after each test. Otherwise run as a postprocessing step after the test suite.
|
|
124
129
|
"""
|
|
125
130
|
|
|
126
131
|
def __init__(self, run_live: bool, previous_runs: list[Run], root: str = ".", threshold: float = 1):
|
|
@@ -16,7 +16,7 @@ class Profiler:
|
|
|
16
16
|
|
|
17
17
|
:ivar coverage_data: The (potentially) covered lines for each module.
|
|
18
18
|
:ivar function_defs: The lines that define a given function in a given module, accessed as
|
|
19
|
-
|
|
19
|
+
`function_defs[module][function]`.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
def __init__(self):
|
pytest_flakefighters/main.py
CHANGED
|
@@ -132,7 +132,12 @@ def pytest_configure(config: pytest.Config):
|
|
|
132
132
|
|
|
133
133
|
flakefighters = []
|
|
134
134
|
if flakefighter_configs is not None:
|
|
135
|
-
|
|
135
|
+
if isinstance(flakefighter_configs, str):
|
|
136
|
+
flakefighter_configs = yaml.safe_load(flakefighter_configs)
|
|
137
|
+
elif hasattr(flakefighter_configs, "value"):
|
|
138
|
+
flakefighter_configs = yaml.safe_load(flakefighter_configs.value)
|
|
139
|
+
else:
|
|
140
|
+
raise TypeError(f"Unexpected type for config: {type(flakefighter_configs)}")
|
|
136
141
|
for flakefighter in algorithms:
|
|
137
142
|
if flakefighter.name in flakefighter_configs:
|
|
138
143
|
flakefighters.append(
|
pytest_flakefighters/plugin.py
CHANGED
|
@@ -193,7 +193,7 @@ class FlakeFighterPlugin: # pylint: disable=R0902
|
|
|
193
193
|
:param config: The pytest config object.
|
|
194
194
|
:returns: The test status.
|
|
195
195
|
"""
|
|
196
|
-
if getattr(report, "flaky", False):
|
|
196
|
+
if getattr(report, "flaky", False) and not report.passed:
|
|
197
197
|
return report.outcome, "F", ("FLAKY", {"yellow": True})
|
|
198
198
|
return None
|
|
199
199
|
|
|
@@ -81,7 +81,7 @@ class PreviouslyFlaky(FlakyFailure):
|
|
|
81
81
|
def rerun(self, report: pytest.TestReport) -> bool:
|
|
82
82
|
"""
|
|
83
83
|
:return: Boolean true if a test is a flaky failure or has previously been marked as flaky and has the same name
|
|
84
|
-
|
|
84
|
+
as the current test.
|
|
85
85
|
"""
|
|
86
86
|
return super().rerun(report) or any(test.name == report.nodeid for test in self.previously_flaky)
|
|
87
87
|
|
|
@@ -1,32 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-flakefighters
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Pytest plugin implementing flaky test failure detection and classification.
|
|
5
5
|
Author: TestFLARE Team
|
|
6
|
-
|
|
7
|
-
The MIT License (MIT)
|
|
8
|
-
|
|
9
|
-
Copyright (c) 2025 TestFLARE Team
|
|
10
|
-
|
|
11
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
-
in the Software without restriction, including without limitation the rights
|
|
14
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
-
furnished to do so, subject to the following conditions:
|
|
17
|
-
|
|
18
|
-
The above copyright notice and this permission notice shall be included in
|
|
19
|
-
all copies or substantial portions of the Software.
|
|
20
|
-
|
|
21
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
27
|
-
THE SOFTWARE.
|
|
28
|
-
|
|
29
|
-
Project-URL: Repository, https://github.com/test-flare/pytest-flakefighter
|
|
6
|
+
Project-URL: Repository, https://github.com/test-flare/pytest-flakefighters
|
|
30
7
|
Requires-Python: >=3.10
|
|
31
8
|
Description-Content-Type: text/markdown
|
|
32
9
|
License-File: LICENSE
|
|
@@ -49,6 +26,8 @@ Requires-Dist: pre_commit; extra == "dev"
|
|
|
49
26
|
Requires-Dist: sphinx-autoapi; extra == "dev"
|
|
50
27
|
Requires-Dist: sphinx_rtd_theme; extra == "dev"
|
|
51
28
|
Requires-Dist: tox>=4.31.0; extra == "dev"
|
|
29
|
+
Requires-Dist: myst_parser; extra == "dev"
|
|
30
|
+
Requires-Dist: nbsphinx; extra == "dev"
|
|
52
31
|
Dynamic: license-file
|
|
53
32
|
|
|
54
33
|
# Pytest FlakeFighters
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
_version.py,sha256=rdxBMYpwzYxiWk08QbPLHSAxHoDfeKWwyaJIAM0lSic,704
|
|
2
|
+
pytest_flakefighters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
pytest_flakefighters/database_management.py,sha256=MDwwpF8FwmFX6is9pVPye7qEOrjZXOsfXG2UI5I7uk4,7029
|
|
4
|
+
pytest_flakefighters/function_coverage.py,sha256=IgzWHMFgkVrc68ZjQ1o27tGxKa8WvcMcGW8RWnpFLVw,2187
|
|
5
|
+
pytest_flakefighters/main.py,sha256=N0yGSGA-ZLtsKRCtSCIdnw7RPVEtLnXUhnftQGHjujA,5430
|
|
6
|
+
pytest_flakefighters/plugin.py,sha256=0XcbZooY_hCwCI1Kg1YntiWQPUn_buDsWBcal0cbEtQ,8802
|
|
7
|
+
pytest_flakefighters/rerun_strategies.py,sha256=YI-spvm0dhB-gGM9IEgDz19NHvzD_XesZ8lDcBDGSJM,2536
|
|
8
|
+
pytest_flakefighters/flakefighters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
pytest_flakefighters/flakefighters/abstract_flakefighter.py,sha256=bchRwoNzQaFhSknT9wKDpbf3EiReHPsHsDhm5qi8y_o,1953
|
|
10
|
+
pytest_flakefighters/flakefighters/coverage_independence.py,sha256=5swoY1jOaaGFlZNX6PdejBFVd7Gpi3zsaW5W6toIzk8,4480
|
|
11
|
+
pytest_flakefighters/flakefighters/deflaker.py,sha256=g0vPS2sEiD9XWFVu_FEZAw2pVkw9vGMWFa7Do1C3sck,5388
|
|
12
|
+
pytest_flakefighters/flakefighters/traceback_matching.py,sha256=LheOEqCvrBDrZJm4RK4ZFFcebWs4ggP7qRiUPg8HQpM,6926
|
|
13
|
+
pytest_flakefighters-0.1.5.dist-info/licenses/LICENSE,sha256=tTzR2CWQMPOp-mQIQqi0cTRkaogeBUmW06blQsBLdQg,1082
|
|
14
|
+
pytest_flakefighters-0.1.5.dist-info/METADATA,sha256=oJo4dnKiNGWO0-kPdvAz1zyCESfAWTh87k_-P8KRwf0,4390
|
|
15
|
+
pytest_flakefighters-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
pytest_flakefighters-0.1.5.dist-info/entry_points.txt,sha256=xockvN1AszN2XqaET77JDIRdOafgm3DdvOtHgVw-aDU,424
|
|
17
|
+
pytest_flakefighters-0.1.5.dist-info/top_level.txt,sha256=bWwe0xVZ_l2CP8KSnztW6FafZKQZ7zUTMa1U32geY28,30
|
|
18
|
+
pytest_flakefighters-0.1.5.dist-info/RECORD,,
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
pytest_flakefighters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
pytest_flakefighters/database_management.py,sha256=MDwwpF8FwmFX6is9pVPye7qEOrjZXOsfXG2UI5I7uk4,7029
|
|
3
|
-
pytest_flakefighters/function_coverage.py,sha256=_WAENobGFbvlbT_CZO6_Ohf8lWaspi5DrWLZd4BdbxY,2183
|
|
4
|
-
pytest_flakefighters/main.py,sha256=u2tgDVLcQ7bbCb55aLG7Nqu5KVx_9GyRAuMBdojCHeM,5148
|
|
5
|
-
pytest_flakefighters/plugin.py,sha256=Y3eQRK58ydO-c77PpnQ8cjWFtOVHop4yf8iAPKEO6TU,8780
|
|
6
|
-
pytest_flakefighters/rerun_strategies.py,sha256=nu6V6sqIMTVqkMBiYek30pe_zolGtdHQwTrgtj13ZG4,2532
|
|
7
|
-
pytest_flakefighters/flakefighters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
pytest_flakefighters/flakefighters/abstract_flakefighter.py,sha256=bchRwoNzQaFhSknT9wKDpbf3EiReHPsHsDhm5qi8y_o,1953
|
|
9
|
-
pytest_flakefighters/flakefighters/coverage_independence.py,sha256=6Ic5SN1Np7vQbvNSRgWwiSF9ReQ293mvNwcn0ZS5js8,4349
|
|
10
|
-
pytest_flakefighters/flakefighters/deflaker.py,sha256=L0pPCWTaKaK_lr7qGh4uhI1ofJXgDr9m-CCjOk-_2KM,5248
|
|
11
|
-
pytest_flakefighters/flakefighters/traceback_matching.py,sha256=DVH8OeoDFmBQW277ap_-e2xe8UBJWkZl5HH-iMdb_Ag,6605
|
|
12
|
-
pytest_flakefighters-0.0.0.dist-info/licenses/LICENSE,sha256=tTzR2CWQMPOp-mQIQqi0cTRkaogeBUmW06blQsBLdQg,1082
|
|
13
|
-
pytest_flakefighters-0.0.0.dist-info/METADATA,sha256=rm_arh8KcYnTVM-qEaJNFyC_JSRvJ7hYhJugNak-9vg,5574
|
|
14
|
-
pytest_flakefighters-0.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
-
pytest_flakefighters-0.0.0.dist-info/entry_points.txt,sha256=xockvN1AszN2XqaET77JDIRdOafgm3DdvOtHgVw-aDU,424
|
|
16
|
-
pytest_flakefighters-0.0.0.dist-info/top_level.txt,sha256=mRzzeCn_6fy5c4knXqUVx2n0d86SvnOpeJcSRUevhWg,21
|
|
17
|
-
pytest_flakefighters-0.0.0.dist-info/RECORD,,
|
|
File without changes
|
{pytest_flakefighters-0.0.0.dist-info → pytest_flakefighters-0.1.5.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{pytest_flakefighters-0.0.0.dist-info → pytest_flakefighters-0.1.5.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|