junitparser 5.0.0__tar.gz → 5.0.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.
- {junitparser-5.0.0/junitparser.egg-info → junitparser-5.0.1}/PKG-INFO +7 -7
- {junitparser-5.0.0 → junitparser-5.0.1}/pyproject.toml +10 -8
- {junitparser-5.0.0 → junitparser-5.0.1/src}/junitparser/__init__.py +4 -2
- {junitparser-5.0.0 → junitparser-5.0.1/src}/junitparser/junitparser.py +39 -10
- junitparser-5.0.0/MANIFEST.in +0 -1
- junitparser-5.0.0/PKG-INFO +0 -323
- junitparser-5.0.0/junitparser.egg-info/SOURCES.txt +0 -26
- junitparser-5.0.0/junitparser.egg-info/dependency_links.txt +0 -1
- junitparser-5.0.0/junitparser.egg-info/entry_points.txt +0 -2
- junitparser-5.0.0/junitparser.egg-info/top_level.txt +0 -1
- junitparser-5.0.0/setup.cfg +0 -4
- junitparser-5.0.0/tests/data/jenkins.xml +0 -23
- junitparser-5.0.0/tests/data/no_fails.xml +0 -16
- junitparser-5.0.0/tests/data/no_suites_tag.xml +0 -15
- junitparser-5.0.0/tests/data/normal.xml +0 -18
- junitparser-5.0.0/tests/data/pytest_error.xml +0 -8
- junitparser-5.0.0/tests/data/pytest_success.xml +0 -6
- junitparser-5.0.0/tests/test_cli.py +0 -107
- junitparser-5.0.0/tests/test_fromfile.py +0 -203
- junitparser-5.0.0/tests/test_general.py +0 -800
- junitparser-5.0.0/tests/test_write.py +0 -284
- junitparser-5.0.0/tests/test_xunit2.py +0 -305
- {junitparser-5.0.0 → junitparser-5.0.1}/LICENSE +0 -0
- {junitparser-5.0.0 → junitparser-5.0.1}/README.rst +0 -0
- {junitparser-5.0.0 → junitparser-5.0.1/src}/junitparser/__main__.py +0 -0
- {junitparser-5.0.0 → junitparser-5.0.1/src}/junitparser/cli.py +0 -0
- {junitparser-5.0.0 → junitparser-5.0.1/src}/junitparser/py.typed +0 -0
- {junitparser-5.0.0 → junitparser-5.0.1/src}/junitparser/xunit2.py +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: junitparser
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.1
|
|
4
4
|
Summary: Manipulates JUnit/xUnit Result XML files
|
|
5
|
+
Keywords: junit,xunit,xml,parser
|
|
6
|
+
Author: Weiwei Wang
|
|
5
7
|
Author-email: Weiwei Wang <gastlygem@gmail.com>
|
|
6
8
|
License-Expression: Apache-2.0
|
|
7
|
-
|
|
8
|
-
Project-URL: Issues, https://github.com/weiwei/junitparser/issues
|
|
9
|
-
Project-URL: Documentation, https://junitparser.readthedocs.io/
|
|
10
|
-
Keywords: junit,xunit,xml,parser
|
|
9
|
+
License-File: LICENSE
|
|
11
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
12
11
|
Classifier: Intended Audience :: Developers
|
|
13
12
|
Classifier: Topic :: Text Processing
|
|
14
13
|
Classifier: Programming Language :: Python :: 3
|
|
15
14
|
Requires-Python: >=3.10
|
|
15
|
+
Project-URL: Homepage, https://github.com/weiwei/junitparser
|
|
16
|
+
Project-URL: Issues, https://github.com/weiwei/junitparser/issues
|
|
17
|
+
Project-URL: Documentation, https://junitparser.readthedocs.io/
|
|
16
18
|
Description-Content-Type: text/x-rst
|
|
17
|
-
License-File: LICENSE
|
|
18
|
-
Dynamic: license-file
|
|
19
19
|
|
|
20
20
|
junitparser -- Pythonic JUnit/xUnit Result XML Parser
|
|
21
21
|
======================================================
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["
|
|
3
|
-
build-backend = "
|
|
2
|
+
requires = ["uv_build>=0.11.7,<0.12.0"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "junitparser"
|
|
7
|
-
|
|
7
|
+
version = "5.0.1"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Weiwei Wang", email="gastlygem@gmail.com" },
|
|
10
10
|
]
|
|
@@ -30,8 +30,10 @@ Documentation = "https://junitparser.readthedocs.io/"
|
|
|
30
30
|
[project.scripts]
|
|
31
31
|
junitparser = "junitparser.cli:main"
|
|
32
32
|
|
|
33
|
-
[
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = [
|
|
35
|
+
"pre-commit>=4.6.0",
|
|
36
|
+
"pytest>=9.0.3",
|
|
37
|
+
"pytest-cov>=7.1.0",
|
|
38
|
+
"ruff>=0.15.12",
|
|
39
|
+
]
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from importlib.metadata import version as _dist_version
|
|
2
|
+
|
|
1
3
|
from .junitparser import (
|
|
2
4
|
Attr,
|
|
3
5
|
Element,
|
|
@@ -16,7 +18,7 @@ from .junitparser import (
|
|
|
16
18
|
TestSuite,
|
|
17
19
|
)
|
|
18
20
|
|
|
19
|
-
version = "
|
|
21
|
+
version = _dist_version("junitparser")
|
|
20
22
|
|
|
21
23
|
__all__ = [
|
|
22
24
|
"Attr",
|
|
@@ -34,5 +36,5 @@ __all__ = [
|
|
|
34
36
|
"SystemErr",
|
|
35
37
|
"TestCase",
|
|
36
38
|
"TestSuite",
|
|
37
|
-
"version"
|
|
39
|
+
"version",
|
|
38
40
|
]
|
|
@@ -8,6 +8,7 @@ This, according to the document, is Apache Ant's JUnit output.
|
|
|
8
8
|
|
|
9
9
|
See the documentation for other supported schemas.
|
|
10
10
|
"""
|
|
11
|
+
|
|
11
12
|
import io
|
|
12
13
|
import itertools
|
|
13
14
|
from copy import deepcopy
|
|
@@ -20,7 +21,12 @@ except ImportError:
|
|
|
20
21
|
from xml.etree import ElementTree as etree
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def write_xml(
|
|
24
|
+
def write_xml(
|
|
25
|
+
obj,
|
|
26
|
+
file_or_filename: Optional[Union[str, IO, Path]] = None,
|
|
27
|
+
*,
|
|
28
|
+
pretty: bool = False,
|
|
29
|
+
):
|
|
24
30
|
tree = etree.ElementTree(obj._elem)
|
|
25
31
|
if file_or_filename is None:
|
|
26
32
|
file_or_filename = obj.filepath
|
|
@@ -41,15 +47,25 @@ def write_xml(obj, file_or_filename: Optional[Union[str, IO, Path]] = None, *, p
|
|
|
41
47
|
xmlfile.write(content)
|
|
42
48
|
else:
|
|
43
49
|
if isinstance(file_or_filename, io.TextIOWrapper):
|
|
44
|
-
if
|
|
45
|
-
|
|
50
|
+
if (
|
|
51
|
+
file_or_filename.encoding is not None
|
|
52
|
+
and file_or_filename.encoding.lower() != "utf-8"
|
|
53
|
+
):
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"Only utf-8 encoding is supported: {file_or_filename.encoding}"
|
|
56
|
+
)
|
|
46
57
|
file_or_filename.buffer.write(content)
|
|
47
58
|
else:
|
|
48
59
|
file_or_filename.write(content)
|
|
49
60
|
else:
|
|
50
61
|
if isinstance(file_or_filename, io.TextIOWrapper):
|
|
51
|
-
if
|
|
52
|
-
|
|
62
|
+
if (
|
|
63
|
+
file_or_filename.encoding is not None
|
|
64
|
+
and file_or_filename.encoding.lower() != "utf-8"
|
|
65
|
+
):
|
|
66
|
+
raise ValueError(
|
|
67
|
+
f"Only utf-8 encoding is supported: {file_or_filename.encoding}"
|
|
68
|
+
)
|
|
53
69
|
tree.write(file_or_filename.buffer, encoding="utf-8", xml_declaration=True)
|
|
54
70
|
else:
|
|
55
71
|
tree.write(file_or_filename, encoding="utf-8", xml_declaration=True)
|
|
@@ -330,7 +346,12 @@ class TestCase(Element):
|
|
|
330
346
|
# JUnit TestCase children are final results, SystemOut and SystemErr
|
|
331
347
|
ITER_TYPES = {t._tag: t for t in (Failure, Error, Skipped, SystemOut, SystemErr)}
|
|
332
348
|
|
|
333
|
-
def __init__(
|
|
349
|
+
def __init__(
|
|
350
|
+
self,
|
|
351
|
+
name: str | None = None,
|
|
352
|
+
classname: str | None = None,
|
|
353
|
+
time: float | None = None,
|
|
354
|
+
):
|
|
334
355
|
super().__init__(self._tag)
|
|
335
356
|
if name is not None:
|
|
336
357
|
self.name = name
|
|
@@ -379,8 +400,11 @@ class TestCase(Element):
|
|
|
379
400
|
@result.setter
|
|
380
401
|
def result(self, value: Union[FinalResult, List[FinalResult]]):
|
|
381
402
|
# Check typing
|
|
382
|
-
if not (
|
|
383
|
-
|
|
403
|
+
if not (
|
|
404
|
+
isinstance(value, FinalResult)
|
|
405
|
+
or isinstance(value, list)
|
|
406
|
+
and all(isinstance(item, FinalResult) for item in value)
|
|
407
|
+
):
|
|
384
408
|
raise ValueError("Value must be either FinalResult or list of FinalResult")
|
|
385
409
|
|
|
386
410
|
# First remove all existing results
|
|
@@ -660,7 +684,9 @@ class TestSuite(Element):
|
|
|
660
684
|
"""Iterate through all testsuites."""
|
|
661
685
|
yield from self.iterchildren(type(self))
|
|
662
686
|
|
|
663
|
-
def write(
|
|
687
|
+
def write(
|
|
688
|
+
self, file_or_filename: Optional[Union[str, IO]] = None, *, pretty: bool = False
|
|
689
|
+
):
|
|
664
690
|
write_xml(self, file_or_filename=file_or_filename, pretty=pretty)
|
|
665
691
|
|
|
666
692
|
|
|
@@ -721,6 +747,7 @@ class JUnitXml(Element):
|
|
|
721
747
|
return self
|
|
722
748
|
|
|
723
749
|
def add_testsuite(self, suite: TestSuite):
|
|
750
|
+
suite = deepcopy(suite)
|
|
724
751
|
"""Add a testsuite."""
|
|
725
752
|
for existing_suite in self:
|
|
726
753
|
if existing_suite == suite:
|
|
@@ -786,7 +813,9 @@ class JUnitXml(Element):
|
|
|
786
813
|
instance.filepath = file if isinstance(file, str) else None
|
|
787
814
|
return instance
|
|
788
815
|
|
|
789
|
-
def write(
|
|
816
|
+
def write(
|
|
817
|
+
self, file_or_filename: Optional[Union[str, IO]] = None, *, pretty: bool = False
|
|
818
|
+
):
|
|
790
819
|
"""Write the object into a JUnit XML file.
|
|
791
820
|
|
|
792
821
|
If `file_or_filename` is not specified, it will write to the original filename.
|
junitparser-5.0.0/MANIFEST.in
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
include tests/data/*.xml
|
junitparser-5.0.0/PKG-INFO
DELETED
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: junitparser
|
|
3
|
-
Version: 5.0.0
|
|
4
|
-
Summary: Manipulates JUnit/xUnit Result XML files
|
|
5
|
-
Author-email: Weiwei Wang <gastlygem@gmail.com>
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/weiwei/junitparser
|
|
8
|
-
Project-URL: Issues, https://github.com/weiwei/junitparser/issues
|
|
9
|
-
Project-URL: Documentation, https://junitparser.readthedocs.io/
|
|
10
|
-
Keywords: junit,xunit,xml,parser
|
|
11
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: Topic :: Text Processing
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Requires-Python: >=3.10
|
|
16
|
-
Description-Content-Type: text/x-rst
|
|
17
|
-
License-File: LICENSE
|
|
18
|
-
Dynamic: license-file
|
|
19
|
-
|
|
20
|
-
junitparser -- Pythonic JUnit/xUnit Result XML Parser
|
|
21
|
-
======================================================
|
|
22
|
-
|
|
23
|
-
.. image:: https://github.com/weiwei/junitparser/actions/workflows/ci.yml/badge.svg?branch=master
|
|
24
|
-
:target: https://github.com/weiwei/junitparser/actions
|
|
25
|
-
.. image:: https://codecov.io/gh/weiwei/junitparser/branch/master/graph/badge.svg?token=UotlfRXNnK
|
|
26
|
-
:target: https://codecov.io/gh/weiwei/junitparser
|
|
27
|
-
|
|
28
|
-
junitparser handles JUnit/xUnit Result XML files. Use it to parse and manipulate
|
|
29
|
-
existing Result XML files, or create new JUnit/xUnit result XMLs from scratch.
|
|
30
|
-
|
|
31
|
-
Features
|
|
32
|
-
--------
|
|
33
|
-
|
|
34
|
-
* Parse or modify existing JUnit/xUnit XML files.
|
|
35
|
-
* Parse or modify non-standard or customized JUnit/xUnit XML files, by monkey
|
|
36
|
-
patching existing element definitions.
|
|
37
|
-
* Create JUnit/xUnit test results from scratch.
|
|
38
|
-
* Merge test result XML files.
|
|
39
|
-
* Specify XML parser. For example you can use lxml to speed things up.
|
|
40
|
-
* Invoke from command line, or `python -m junitparser`
|
|
41
|
-
|
|
42
|
-
Note on version 5
|
|
43
|
-
-----------------
|
|
44
|
-
|
|
45
|
-
Python 3.10 or above is now required. If you are still using Python 3.9 or below, please use version 4.0.2.
|
|
46
|
-
|
|
47
|
-
Note on version 2
|
|
48
|
-
-----------------
|
|
49
|
-
|
|
50
|
-
Version 2 improved support for pytest result XML files by fixing a few issues,
|
|
51
|
-
notably that there could be multiple <Failure> or <Error> entries. There is a
|
|
52
|
-
breaking change that ``TestCase.result`` is now a list instead of a single item.
|
|
53
|
-
If you are using this attribute, please update your code accordingly.
|
|
54
|
-
|
|
55
|
-
Installation
|
|
56
|
-
-------------
|
|
57
|
-
|
|
58
|
-
pip install junitparser
|
|
59
|
-
|
|
60
|
-
Usage
|
|
61
|
-
-----
|
|
62
|
-
|
|
63
|
-
You should be relatively familiar with the Junit XML format. If not, run
|
|
64
|
-
``pydoc`` on the exposed classes and functions to see how it's structured.
|
|
65
|
-
|
|
66
|
-
Create Junit XML format reports from scratch
|
|
67
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
68
|
-
|
|
69
|
-
You have some test result data, and you want to convert them into junit.xml
|
|
70
|
-
format.
|
|
71
|
-
|
|
72
|
-
.. code-block:: python
|
|
73
|
-
|
|
74
|
-
from junitparser import TestCase, TestSuite, JUnitXml, Skipped, Error
|
|
75
|
-
|
|
76
|
-
# Create cases
|
|
77
|
-
case1 = TestCase('case1', 'class.name', 0.5) # params are optional
|
|
78
|
-
case1.classname = "modified.class.name" # specify or change case attrs
|
|
79
|
-
case1.result = [Skipped()] # You can have a list of results
|
|
80
|
-
case2 = TestCase('case2')
|
|
81
|
-
case2.result = [Error('Example error message', 'the_error_type')]
|
|
82
|
-
|
|
83
|
-
# Create suite and add cases
|
|
84
|
-
suite = TestSuite('suite1')
|
|
85
|
-
suite.add_property('build', '55')
|
|
86
|
-
suite.add_testcase(case1)
|
|
87
|
-
suite.add_testcase(case2)
|
|
88
|
-
suite.remove_testcase(case2)
|
|
89
|
-
|
|
90
|
-
#Bulk add cases to suite
|
|
91
|
-
case3 = TestCase('case3')
|
|
92
|
-
case4 = TestCase('case4')
|
|
93
|
-
suite.add_testcases([case3, case4])
|
|
94
|
-
|
|
95
|
-
# Add suite to JunitXml
|
|
96
|
-
xml = JUnitXml()
|
|
97
|
-
xml.add_testsuite(suite)
|
|
98
|
-
xml.write('junit.xml')
|
|
99
|
-
|
|
100
|
-
Read and manipulate existing JUnit/xUnit XML files
|
|
101
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
102
|
-
|
|
103
|
-
You have some existing junit.xml files, and you want to modify the content.
|
|
104
|
-
|
|
105
|
-
.. code-block:: python
|
|
106
|
-
|
|
107
|
-
from junitparser import JUnitXml
|
|
108
|
-
|
|
109
|
-
xml = JUnitXml.fromfile('/path/to/junit.xml')
|
|
110
|
-
for suite in xml:
|
|
111
|
-
# handle suites
|
|
112
|
-
for case in suite:
|
|
113
|
-
# handle cases
|
|
114
|
-
xml.write() # Writes back to file
|
|
115
|
-
|
|
116
|
-
It is also possible to use a custom parser. For example lxml provides a plethora
|
|
117
|
-
of parsing options_. We can use them this way:
|
|
118
|
-
|
|
119
|
-
.. code-block:: python
|
|
120
|
-
|
|
121
|
-
from lxml.etree import XMLParser, parse
|
|
122
|
-
from junitparser import JUnitXml
|
|
123
|
-
|
|
124
|
-
def parse_func(file_path):
|
|
125
|
-
xml_parser = XMLParser(huge_tree=True)
|
|
126
|
-
return parse(file_path, xml_parser)
|
|
127
|
-
|
|
128
|
-
xml = JUnitXml.fromfile('/path/to/junit.xml', parse_func)
|
|
129
|
-
# process xml...
|
|
130
|
-
|
|
131
|
-
.. _options: https://lxml.de/api/lxml.etree.XMLParser-class.html
|
|
132
|
-
|
|
133
|
-
Merge XML files
|
|
134
|
-
~~~~~~~~~~~~~~~
|
|
135
|
-
|
|
136
|
-
You have two or more XML files, and you want to merge them into one.
|
|
137
|
-
|
|
138
|
-
.. code-block:: python
|
|
139
|
-
|
|
140
|
-
from junitparser import JUnitXml
|
|
141
|
-
|
|
142
|
-
xml1 = JUnitXml.fromfile('/path/to/junit1.xml')
|
|
143
|
-
xml2 = JUnitXml.fromfile('/path/to/junit2.xml')
|
|
144
|
-
|
|
145
|
-
newxml = xml1 + xml2
|
|
146
|
-
# Alternatively, merge in place
|
|
147
|
-
xml1 += xml2
|
|
148
|
-
|
|
149
|
-
Note that it won't check for duplicate entries. You need to deal with them on
|
|
150
|
-
your own.
|
|
151
|
-
|
|
152
|
-
Schema Support
|
|
153
|
-
~~~~~~~~~~~~~~~
|
|
154
|
-
|
|
155
|
-
By default junitparser supports the schema of windyroad_, which is a relatively
|
|
156
|
-
simple schema.
|
|
157
|
-
|
|
158
|
-
.. _windyroad: https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd
|
|
159
|
-
|
|
160
|
-
Junitparser also support extra schemas:
|
|
161
|
-
|
|
162
|
-
.. code-block:: python
|
|
163
|
-
|
|
164
|
-
# Extended with extra properties/attributes from the xunit2 schema.
|
|
165
|
-
from junitparser.xunit2 import TestCase, TestSuite, RerunFailure
|
|
166
|
-
|
|
167
|
-
# TestSuite supports system_err.
|
|
168
|
-
suite = TestSuite("mySuite")
|
|
169
|
-
suite.system_err = "System err"
|
|
170
|
-
|
|
171
|
-
# TestCase supports interim results.
|
|
172
|
-
case = TestCase("myCase")
|
|
173
|
-
rerun_failure = RerunFailure("Not found", "404")
|
|
174
|
-
rerun_failure.stack_trace = "Stack"
|
|
175
|
-
rerun_failure.system_err = "E404"
|
|
176
|
-
rerun_failure.system_out = "NOT FOUND"
|
|
177
|
-
case.add_interim_result(rerun_failure)
|
|
178
|
-
|
|
179
|
-
# TestCase supports properties.
|
|
180
|
-
case.add_property("cmake_labels", "cuda;tier2")
|
|
181
|
-
|
|
182
|
-
Currently supported schemas including:
|
|
183
|
-
|
|
184
|
-
- xunit2_, supported by pytest, Erlang/OTP, Maven Surefire, CppTest, etc.
|
|
185
|
-
|
|
186
|
-
.. _xunit2: https://github.com/jenkinsci/xunit-plugin/blob/xunit-2.3.2/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
|
|
187
|
-
|
|
188
|
-
PRs are welcome to support more schemas.
|
|
189
|
-
|
|
190
|
-
Create XML with custom attributes
|
|
191
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
192
|
-
|
|
193
|
-
You want to use an attribute that is not supported by default.
|
|
194
|
-
|
|
195
|
-
.. code-block:: python
|
|
196
|
-
|
|
197
|
-
from junitparser import TestCase, Attr, IntAttr, FloatAttr
|
|
198
|
-
|
|
199
|
-
# Add the custom attribute
|
|
200
|
-
TestCase.id = IntAttr('id')
|
|
201
|
-
TestCase.rate = FloatAttr('rate')
|
|
202
|
-
TestCase.custom = Attr('custom')
|
|
203
|
-
case = TestCase()
|
|
204
|
-
case.id = 123
|
|
205
|
-
case.rate = 0.95
|
|
206
|
-
case.custom = 'foobar'
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
Handling XML with custom element
|
|
210
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
211
|
-
|
|
212
|
-
There may be once in 1000 years you want to it this way, but anyways.
|
|
213
|
-
Suppose you want to add element CustomElement to TestCase.
|
|
214
|
-
|
|
215
|
-
.. code-block:: python
|
|
216
|
-
|
|
217
|
-
from junitparser import Element, Attr, TestSuite
|
|
218
|
-
|
|
219
|
-
# Create the new element by subclassing Element,
|
|
220
|
-
# and add custom attributes to it.
|
|
221
|
-
class CustomElement(Element):
|
|
222
|
-
_tag = 'custom'
|
|
223
|
-
foo = Attr()
|
|
224
|
-
bar = Attr()
|
|
225
|
-
|
|
226
|
-
testcase = TestCase()
|
|
227
|
-
custom = CustomElement()
|
|
228
|
-
testcase.append(custom)
|
|
229
|
-
# To find a single sub-element:
|
|
230
|
-
testcase.child(CustomElement)
|
|
231
|
-
# To iterate over custom elements:
|
|
232
|
-
for custom in testcase.iterchildren(CustomElement):
|
|
233
|
-
... # Do things with custom element
|
|
234
|
-
|
|
235
|
-
Handling custom XML attributes
|
|
236
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
237
|
-
|
|
238
|
-
Say you have some data stored in the XML as custom attributes and you want to
|
|
239
|
-
read them out:
|
|
240
|
-
|
|
241
|
-
.. code-block:: python
|
|
242
|
-
|
|
243
|
-
from junitparser import TestCase, Attr, JUnitXml
|
|
244
|
-
|
|
245
|
-
# Create the new element by subclassing Element or one of its child class,
|
|
246
|
-
# and add custom attributes to it.
|
|
247
|
-
class MyTestCase(TestCase):
|
|
248
|
-
foo = Attr()
|
|
249
|
-
|
|
250
|
-
xml = JUnitXml.fromfile('/path/to/junit.xml')
|
|
251
|
-
for suite in xml:
|
|
252
|
-
# handle suites
|
|
253
|
-
for case in suite:
|
|
254
|
-
my_case = MyTestCase.fromelem(case)
|
|
255
|
-
print(my_case.foo)
|
|
256
|
-
|
|
257
|
-
Command Line
|
|
258
|
-
------------
|
|
259
|
-
|
|
260
|
-
.. code-block:: console
|
|
261
|
-
|
|
262
|
-
$ junitparser --help
|
|
263
|
-
usage: junitparser [-h] [-v] {merge} ...
|
|
264
|
-
|
|
265
|
-
Junitparser CLI helper.
|
|
266
|
-
|
|
267
|
-
positional arguments:
|
|
268
|
-
{merge} command
|
|
269
|
-
merge Merge Junit XML format reports with junitparser.
|
|
270
|
-
verify Return a non-zero exit code if one of the testcases failed or errored.
|
|
271
|
-
|
|
272
|
-
optional arguments:
|
|
273
|
-
-h, --help show this help message and exit
|
|
274
|
-
-v, --version show program's version number and exit
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
.. code-block:: console
|
|
278
|
-
|
|
279
|
-
$ junitparser merge --help
|
|
280
|
-
usage: junitparser merge [-h] [--glob] paths [paths ...] output
|
|
281
|
-
|
|
282
|
-
positional arguments:
|
|
283
|
-
paths Original XML path(s).
|
|
284
|
-
output Merged XML Path, setting to "-" will output console
|
|
285
|
-
|
|
286
|
-
optional arguments:
|
|
287
|
-
-h, --help show this help message and exit
|
|
288
|
-
--glob Treat original XML path(s) as glob(s).
|
|
289
|
-
--suite-name SUITE_NAME
|
|
290
|
-
Name added to <testsuites>.
|
|
291
|
-
|
|
292
|
-
.. code-block:: console
|
|
293
|
-
|
|
294
|
-
$ junitparser verify --help
|
|
295
|
-
usage: junitparser verify [-h] [--glob] paths [paths ...]
|
|
296
|
-
|
|
297
|
-
positional arguments:
|
|
298
|
-
paths XML path(s) of reports to verify.
|
|
299
|
-
|
|
300
|
-
optional arguments:
|
|
301
|
-
-h, --help show this help message and exit
|
|
302
|
-
--glob Treat original XML path(s) as glob(s).
|
|
303
|
-
|
|
304
|
-
Test
|
|
305
|
-
----
|
|
306
|
-
|
|
307
|
-
The tests are written with python ``unittest``, to run them, use
|
|
308
|
-
`pytest <https://pypi.org/project/pytest/>`_::
|
|
309
|
-
|
|
310
|
-
pytest
|
|
311
|
-
|
|
312
|
-
If you get a failure like ``unsupported locale setting`` you may need to add
|
|
313
|
-
extra locales that the tests use. Refer to the steps used in the
|
|
314
|
-
`CI build workflow <.github/workflows/build.yml>`_::
|
|
315
|
-
|
|
316
|
-
sudo locale-gen en_US.UTF-8
|
|
317
|
-
sudo locale-gen de_DE.UTF-8
|
|
318
|
-
sudo update-locale
|
|
319
|
-
|
|
320
|
-
Contribute
|
|
321
|
-
----------
|
|
322
|
-
|
|
323
|
-
PRs are welcome!
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
LICENSE
|
|
2
|
-
MANIFEST.in
|
|
3
|
-
README.rst
|
|
4
|
-
pyproject.toml
|
|
5
|
-
junitparser/__init__.py
|
|
6
|
-
junitparser/__main__.py
|
|
7
|
-
junitparser/cli.py
|
|
8
|
-
junitparser/junitparser.py
|
|
9
|
-
junitparser/py.typed
|
|
10
|
-
junitparser/xunit2.py
|
|
11
|
-
junitparser.egg-info/PKG-INFO
|
|
12
|
-
junitparser.egg-info/SOURCES.txt
|
|
13
|
-
junitparser.egg-info/dependency_links.txt
|
|
14
|
-
junitparser.egg-info/entry_points.txt
|
|
15
|
-
junitparser.egg-info/top_level.txt
|
|
16
|
-
tests/test_cli.py
|
|
17
|
-
tests/test_fromfile.py
|
|
18
|
-
tests/test_general.py
|
|
19
|
-
tests/test_write.py
|
|
20
|
-
tests/test_xunit2.py
|
|
21
|
-
tests/data/jenkins.xml
|
|
22
|
-
tests/data/no_fails.xml
|
|
23
|
-
tests/data/no_suites_tag.xml
|
|
24
|
-
tests/data/normal.xml
|
|
25
|
-
tests/data/pytest_error.xml
|
|
26
|
-
tests/data/pytest_success.xml
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
junitparser
|
junitparser-5.0.0/setup.cfg
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<!-- according to https://llg.cubic.org/docs/junit/, <testsuite> can be child of <testsuite> -->
|
|
3
|
-
<testsuites>
|
|
4
|
-
<testsuite name="JUnitXmlReporter" errors="0" tests="0" failures="0" time="0" timestamp="2013-05-24T10:23:58" />
|
|
5
|
-
<testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="1" tests="3" failures="1" time="0.006" timestamp="2013-05-24T10:23:58">
|
|
6
|
-
<properties>
|
|
7
|
-
<property name="java.vendor" value="Sun Microsystems Inc." />
|
|
8
|
-
<property name="compiler.debug" value="on" />
|
|
9
|
-
<property name="project.jdk.classpath" value="jdk.classpath.1.6" />
|
|
10
|
-
</properties>
|
|
11
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default path to an empty string" time="0.006">
|
|
12
|
-
<failure message="test failure">Assertion failed</failure>
|
|
13
|
-
</testcase>
|
|
14
|
-
<testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="1" tests="2" failures="0" time="0.000" timestamp="2013-05-24T10:23:58">
|
|
15
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default consolidate to true" time="0">
|
|
16
|
-
<skipped />
|
|
17
|
-
</testcase>
|
|
18
|
-
<testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="0" tests="1" failures="0" time="0" timestamp="2013-05-24T10:23:58">
|
|
19
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default useDotNotation to true" time="0" />
|
|
20
|
-
</testsuite>
|
|
21
|
-
</testsuite>
|
|
22
|
-
</testsuite>
|
|
23
|
-
</testsuites>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<testsuites>
|
|
3
|
-
<testsuite name="JUnitXmlReporter" errors="0" tests="0" failures="0" time="0" timestamp="2013-05-24T10:23:58" />
|
|
4
|
-
<testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="1" tests="3" failures="1" time="0.006" timestamp="2013-05-24T10:23:58">
|
|
5
|
-
<properties>
|
|
6
|
-
<property name="java.vendor" value="Sun Microsystems Inc." />
|
|
7
|
-
<property name="compiler.debug" value="on" />
|
|
8
|
-
<property name="project.jdk.classpath" value="jdk.classpath.1.6" />
|
|
9
|
-
</properties>
|
|
10
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default path to an empty string" time="0.006"/>
|
|
11
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default consolidate to true" time="0">
|
|
12
|
-
<skipped />
|
|
13
|
-
</testcase>
|
|
14
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default useDotNotation to true" time="0" />
|
|
15
|
-
</testsuite>
|
|
16
|
-
</testsuites>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="1" tests="3" failures="1" time="0.006" timestamp="2013-05-24T10:23:58">
|
|
3
|
-
<properties>
|
|
4
|
-
<property name="java.vendor" value="Sun Microsystems Inc." />
|
|
5
|
-
<property name="compiler.debug" value="on" />
|
|
6
|
-
<property name="project.jdk.classpath" value="jdk.classpath.1.6" />
|
|
7
|
-
</properties>
|
|
8
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default path to an empty string" time="0.006">
|
|
9
|
-
<failure message="test failure">Assertion failed</failure>
|
|
10
|
-
</testcase>
|
|
11
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default consolidate to true" time="0">
|
|
12
|
-
<skipped />
|
|
13
|
-
</testcase>
|
|
14
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default useDotNotation to true" time="0" />
|
|
15
|
-
</testsuite>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<testsuites>
|
|
3
|
-
<testsuite name="JUnitXmlReporter" errors="0" tests="0" failures="0" time="0" timestamp="2013-05-24T10:23:58" />
|
|
4
|
-
<testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="1" tests="3" failures="1" time="0.006" timestamp="2013-05-24T10:23:58">
|
|
5
|
-
<properties>
|
|
6
|
-
<property name="java.vendor" value="Sun Microsystems Inc." />
|
|
7
|
-
<property name="compiler.debug" value="on" />
|
|
8
|
-
<property name="project.jdk.classpath" value="jdk.classpath.1.6" />
|
|
9
|
-
</properties>
|
|
10
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default path to an empty string" time="0.006">
|
|
11
|
-
<failure message="test failure">Assertion failed</failure>
|
|
12
|
-
</testcase>
|
|
13
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default consolidate to true" time="0">
|
|
14
|
-
<skipped />
|
|
15
|
-
</testcase>
|
|
16
|
-
<testcase classname="JUnitXmlReporter.constructor" name="should default useDotNotation to true" time="0" />
|
|
17
|
-
</testsuite>
|
|
18
|
-
</testsuites>
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<testsuites>
|
|
3
|
-
<testsuite name="pytest" errors="0" failures="1" skipped="0" tests="1" time="0.039" timestamp="2025-01-14T20:33:43.564504+01:00">
|
|
4
|
-
<testcase classname="tests.test_cli" name="test_merge" time="0.001">
|
|
5
|
-
<failure message="NameError: name 'file' is not defined" />
|
|
6
|
-
</testcase>
|
|
7
|
-
</testsuite>
|
|
8
|
-
</testsuites>
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<testsuites>
|
|
3
|
-
<testsuite name="pytest" errors="0" failures="0" skipped="0" tests="1" time="0.026" timestamp="2025-01-14T20:33:46.249864+01:00" >
|
|
4
|
-
<testcase classname="tests.test_fromfile" name="test_fromfile" time="0.001" />
|
|
5
|
-
</testsuite>
|
|
6
|
-
</testsuites>
|