Skip to content

Commit

Permalink
Move to lxml
Browse files Browse the repository at this point in the history
  • Loading branch information
EnricoMi committed May 23, 2022
1 parent c8ce9bb commit bd5367a
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 7 deletions.
27 changes: 23 additions & 4 deletions python/publish/junit.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import os
from collections import defaultdict
from typing import Optional, Iterable, Union, Any, List, Dict
from typing import Optional, Iterable, Union, Tuple, List, Dict

import junitparser
from junitparser import Element, JUnitXml, TestCase, TestSuite, Skipped
from junitparser.junitparser import etree

from publish.unittestresults import ParsedUnitTestResults, UnitTestCase, ParseError

try:
import lxml
lxml_available = True
except ImportError:
lxml_available = False


def get_results(results: Union[Element, List[Element]], status: Optional[str] = None) -> List[Element]:
"""
Expand Down Expand Up @@ -97,10 +103,24 @@ def end(self, tag: Union[str, bytes]) -> Element:
if self._stack:
self._stack.pop()

def close(self) -> Element:
# when lxml is around, we have to return an ElementTree here, otherwise
# XMLParser(target=...).parse(..., parser=...)
# returns an Element, not a ElementTree, but junitparser expects an ElementTree
#
# https://lxml.de/parsing.html:
# Note that the parser does not build a tree when using a parser target. The result of the parser run is
# whatever the target object returns from its .close() method. If you want to return an XML tree here, you
# have to create it programmatically in the target object.
if lxml_available:
return lxml.etree.ElementTree(super().close())
else:
return super().close()


def parse_junit_xml_files(files: Iterable[str], time_factor: float = 1.0, drop_testcases: bool = False) -> ParsedUnitTestResults:
"""Parses junit xml files and returns aggregated statistics as a ParsedUnitTestResults."""
def parse(path: str) -> Union[str, Any]:
def parse(path: str) -> Union[JUnitXml, BaseException]:
if not os.path.exists(path):
return FileNotFoundError(f'File does not exist.')
if os.stat(path).st_size == 0:
Expand All @@ -114,8 +134,7 @@ def parse(path: str) -> Union[str, Any]:
except BaseException as e:
return e

parsed_files = [(result_file, parse(result_file))
for result_file in files]
parsed_files = [(result_file, parse(result_file)) for result_file in files]
junits = [(result_file, junit)
for result_file, junit in parsed_files
if not isinstance(junit, BaseException)]
Expand Down
3 changes: 2 additions & 1 deletion python/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ dataclasses;python_version<"3.7"
junitparser==2.5.0
PyGithub==1.55
urllib3==1.26.9
requests==2.27.1
requests==2.27.1
lxml==4.8.0
4 changes: 2 additions & 2 deletions python/test/test_junit.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def test_parse_junit_xml_files_with_non_xml_file(self):
parse_junit_xml_files([result_file]),
ParsedUnitTestResults(
files=1,
errors=[ParseError(file=result_file, message='File is not a valid XML file:\nsyntax error: line 1, column 0', line=1, column=0)],
errors=[ParseError(file=result_file, message="Start tag expected, '<' not found, line 1, column 1 (non-xml.xml, line 1)", line=None, column=None)],
suites=0,
suite_tests=0,
suite_skipped=0,
Expand All @@ -415,7 +415,7 @@ def test_parse_junit_xml_files_with_corrupt_xml_file(self):
parse_junit_xml_files([result_file]),
ParsedUnitTestResults(
files=1,
errors=[ParseError(file=result_file, message='File is not a valid XML file:\nno element found: line 11, column 21', line=11, column=21)],
errors=[ParseError(file=result_file, message='Premature end of data in tag skipped line 9, line 11, column 22 (corrupt-xml.xml, line 11)', line=None, column=None)],
suites=0,
suite_tests=0,
suite_skipped=0,
Expand Down

0 comments on commit bd5367a

Please sign in to comment.