Skip to content

pytest: Enhance JSON report parsing to handle user properties#1079

Merged
ono-max merged 2 commits intomainfrom
support-deps
Jul 18, 2025
Merged

pytest: Enhance JSON report parsing to handle user properties#1079
ono-max merged 2 commits intomainfrom
support-deps

Conversation

@ono-max
Copy link
Contributor

@ono-max ono-max commented Jul 18, 2025

Example script

import pytest

@pytest.mark.order(1)
@pytest.mark.dependency(name="a")
@pytest.mark.xfail(reason="deliberate fail")
def test_a():
    assert False

@pytest.mark.dependency(name="b")
def test_b():
    pass

@pytest.mark.order(2)
@pytest.mark.dependency(name="c", depends=["a"])
def test_c():
    pass

@pytest.mark.dependency(name="d", depends=["b"])
def test_d():
    pass

@pytest.mark.dependency(name="e", depends=["b", "c"])
def test_e():
    pass

Example report files

{"pytest_version": "8.4.1", "$report_type": "SessionStart"}
{"nodeid": "", "outcome": "passed", "longrepr": null, "result": null, "sections": [], "$report_type": "CollectReport"}
{"nodeid": "tests/test_funcs2.py", "outcome": "passed", "longrepr": null, "result": null, "sections": [], "$report_type": "CollectReport"}
{"nodeid": "tests/test_funcs2.py::test_a", "location": ["tests/test_funcs2.py", 2, "test_a"], "keywords": {"test_a": 1, "xfail": 1, "dependency": 1, "order": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "setup", "user_properties": [["name", "xfail"], ["args", []], ["kwargs", {"reason": "deliberate fail"}], ["name", "dependency"], ["args", []], ["kwargs", {"name": "a"}], ["name", "order"], ["args", [1]], ["kwargs", {}]], "sections": [], "duration": 5.191704258322716e-05, "start": 1752817144.704347, "stop": 1752817144.704399, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_a", "location": ["tests/test_funcs2.py", 2, "test_a"], "keywords": {"test_a": 1, "xfail": 1, "dependency": 1, "order": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "skipped", "longrepr": {"reprcrash": {"path": "/Users/ono-max/src/github.com/launchableinc/cli/tests/data/pytest/tests/test_funcs2.py", "lineno": 7, "message": "assert False"}, "reprtraceback": {"reprentries": [{"type": "ReprEntry", "data": {"lines": ["    @pytest.mark.order(1)", "    @pytest.mark.dependency(name=\"a\")", "    @pytest.mark.xfail(reason=\"deliberate fail\")", "    def test_a():", ">       assert False", "E       assert False"], "reprfuncargs": {"args": []}, "reprlocals": null, "reprfileloc": {"path": "tests/data/pytest/tests/test_funcs2.py", "lineno": 7, "message": "AssertionError"}, "style": "long"}}], "extraline": null, "style": "long"}, "sections": [], "chain": [[{"reprentries": [{"type": "ReprEntry", "data": {"lines": ["    @pytest.mark.order(1)", "    @pytest.mark.dependency(name=\"a\")", "    @pytest.mark.xfail(reason=\"deliberate fail\")", "    def test_a():", ">       assert False", "E       assert False"], "reprfuncargs": {"args": []}, "reprlocals": null, "reprfileloc": {"path": "tests/data/pytest/tests/test_funcs2.py", "lineno": 7, "message": "AssertionError"}, "style": "long"}}], "extraline": null, "style": "long"}, {"path": "/Users/ono-max/src/github.com/launchableinc/cli/tests/data/pytest/tests/test_funcs2.py", "lineno": 7, "message": "assert False"}, null]]}, "when": "call", "user_properties": [["name", "xfail"], ["args", []], ["kwargs", {"reason": "deliberate fail"}], ["name", "dependency"], ["args", []], ["kwargs", {"name": "a"}], ["name", "order"], ["args", [1]], ["kwargs", {}]], "sections": [], "duration": 6.833299994468689e-05, "start": 1752817144.704504, "stop": 1752817144.704573, "wasxfail": "deliberate fail", "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_a", "location": ["tests/test_funcs2.py", 2, "test_a"], "keywords": {"test_a": 1, "xfail": 1, "dependency": 1, "order": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "teardown", "user_properties": [["name", "xfail"], ["args", []], ["kwargs", {"reason": "deliberate fail"}], ["name", "dependency"], ["args", []], ["kwargs", {"name": "a"}], ["name", "order"], ["args", [1]], ["kwargs", {}]], "sections": [], "duration": 4.841596819460392e-05, "start": 1752817144.7127922, "stop": 1752817144.712841, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_c", "location": ["tests/test_funcs2.py", 12, "test_c"], "keywords": {"test_c": 1, "dependency": 1, "order": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "skipped", "longrepr": ["/Users/ono-max/.local/share/virtualenvs/cli-tPknK2Me/lib/python3.12/site-packages/pytest_dependency.py", 101, "Skipped: test_c depends on a"], "when": "setup", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "c", "depends": ["a"]}], ["name", "order"], ["args", [2]], ["kwargs", {}]], "sections": [], "duration": 4.8083020374178886e-05, "start": 1752817144.7129972, "stop": 1752817144.713046, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_c", "location": ["tests/test_funcs2.py", 12, "test_c"], "keywords": {"test_c": 1, "dependency": 1, "order": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "teardown", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "c", "depends": ["a"]}], ["name", "order"], ["args", [2]], ["kwargs", {}]], "sections": [], "duration": 2.38749198615551e-05, "start": 1752817144.71315, "stop": 1752817144.713174, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_b", "location": ["tests/test_funcs2.py", 8, "test_b"], "keywords": {"test_b": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "setup", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "b"}]], "sections": [], "duration": 2.8582988306879997e-05, "start": 1752817144.713302, "stop": 1752817144.713331, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_b", "location": ["tests/test_funcs2.py", 8, "test_b"], "keywords": {"test_b": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "call", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "b"}]], "sections": [], "duration": 3.0750175938010216e-05, "start": 1752817144.713384, "stop": 1752817144.713415, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_b", "location": ["tests/test_funcs2.py", 8, "test_b"], "keywords": {"test_b": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "teardown", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "b"}]], "sections": [], "duration": 2.0791077986359596e-05, "start": 1752817144.713471, "stop": 1752817144.713492, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_d", "location": ["tests/test_funcs2.py", 17, "test_d"], "keywords": {"test_d": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "setup", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "d", "depends": ["b"]}]], "sections": [], "duration": 2.8250040486454964e-05, "start": 1752817144.71359, "stop": 1752817144.7136178, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_d", "location": ["tests/test_funcs2.py", 17, "test_d"], "keywords": {"test_d": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "call", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "d", "depends": ["b"]}]], "sections": [], "duration": 2.508307807147503e-05, "start": 1752817144.713665, "stop": 1752817144.71369, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_d", "location": ["tests/test_funcs2.py", 17, "test_d"], "keywords": {"test_d": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "teardown", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "d", "depends": ["b"]}]], "sections": [], "duration": 1.8167076632380486e-05, "start": 1752817144.713741, "stop": 1752817144.713759, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_e", "location": ["tests/test_funcs2.py", 21, "test_e"], "keywords": {"test_e": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "skipped", "longrepr": ["/Users/ono-max/.local/share/virtualenvs/cli-tPknK2Me/lib/python3.12/site-packages/pytest_dependency.py", 101, "Skipped: test_e depends on c"], "when": "setup", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "e", "depends": ["b", "c"]}]], "sections": [], "duration": 2.9750168323516846e-05, "start": 1752817144.71387, "stop": 1752817144.7139, "$report_type": "TestReport"}
{"nodeid": "tests/test_funcs2.py::test_e", "location": ["tests/test_funcs2.py", 21, "test_e"], "keywords": {"test_e": 1, "dependency": 1, "pytestmark": 1, "test_funcs2.py": 1, "tests": 1, "pytest": 1, "": 1}, "outcome": "passed", "longrepr": null, "when": "teardown", "user_properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "e", "depends": ["b", "c"]}]], "sections": [], "duration": 1.9834144040942192e-05, "start": 1752817144.713985, "stop": 1752817144.714005, "$report_type": "TestReport"}
{"exitstatus": 0, "$report_type": "SessionFinish"}

Example of data in PostgreSQL

1981c1a-3454-7b55-8883-655a08511dac |               2 |            4 | {"properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "e", "depends":
 ["b", "c"]}]]}                                                                                                                  | 01981c1a-344b-796e-8053-835ec2d
f2f68 | 2025-07-18 05:55:36.096224+00 | 2025-07-18 05:55:36.147081+00
 01981c1a-3453-7a83-90a0-8e836d6a763e |               2 |            4 | {"properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "d", "depends":
 ["b"]}]]}                                                                                                                       | 01981c1a-344b-796e-8052-9d844ec
64bbb | 2025-07-18 05:55:36.096192+00 | 2025-07-18 05:55:36.147081+00
 01981c1a-3453-7a83-909f-f07db118fc53 |               2 |            4 | {"properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "b"}]]}        
                                                                                                                                 | 01981c1a-344b-796e-8051-df1e74e
b4b76 | 2025-07-18 05:55:36.096158+00 | 2025-07-18 05:55:36.147081+00
 01981c1a-3453-7a83-909e-58575056e32f |               2 |            4 | {"properties": [["name", "dependency"], ["args", []], ["kwargs", {"name": "c", "depends": ["a"]}], ["name", "order"], ["args", [2]], ["kwargs", {}]]}                                                                     | 01981c1a-344b-796e-8050-19f4bdf50ee7 | 2025-07-18 05:55:36.096114+00 | 2025-07-18 05:55:36.147081+00
 01981c1a-3453-7a83-909d-269c8f78ce98 |               2 |            4 | {"properties": [["name", "xfail"], ["args", []], ["kwargs", {"reason": "deliberate fail"}], ["name", "dependency"], ["args", []], ["kwargs", {"name": "a"}], ["name", "order"], ["args", [1]], ["kwargs", {}]]}           | 01981c1a-344b-796e-804f-0bdbec85d812 | 2025-07-18 05:55:36.095827+00 | 2025-07-18 05:55:36.147081+00

@launchable-app

This comment has been minimized.

@ono-max ono-max requested a review from Konboi July 18, 2025 06:33
@sonarqubecloud
Copy link

@ono-max ono-max merged commit 4644a6f into main Jul 18, 2025
15 checks passed
@ono-max ono-max deleted the support-deps branch July 18, 2025 07:11
@github-actions github-actions bot mentioned this pull request Jul 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants