Skip to content

Commit e133932

Browse files
chore: junitxml tests: add more type annotations
1 parent 812ce76 commit e133932

File tree

1 file changed

+35
-32
lines changed

1 file changed

+35
-32
lines changed

testing/test_junitxml.py

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
from pathlib import Path
77
import platform
8+
from typing import Any
89
from typing import cast
910
from typing import TYPE_CHECKING
1011
from xml.dom import minidom
@@ -20,6 +21,7 @@
2021
from _pytest.reports import BaseReport
2122
from _pytest.reports import TestReport
2223
from _pytest.stash import Stash
24+
import _pytest.timing
2325
import pytest
2426

2527

@@ -61,52 +63,48 @@ def run_and_parse(pytester: Pytester, schema: xmlschema.XMLSchema) -> RunAndPars
6163
return RunAndParse(pytester, schema)
6264

6365

64-
def assert_attr(node, **kwargs):
66+
def assert_attr(node: minidom.Element, **kwargs: object) -> None:
6567
__tracebackhide__ = True
6668

67-
def nodeval(node, name):
69+
def nodeval(node: minidom.Element, name: str) -> str | None:
6870
anode = node.getAttributeNode(name)
69-
if anode is not None:
70-
return anode.value
71+
return anode.value if anode is not None else None
7172

7273
expected = {name: str(value) for name, value in kwargs.items()}
7374
on_node = {name: nodeval(node, name) for name in expected}
7475
assert on_node == expected
7576

7677

7778
class DomNode:
78-
def __init__(self, dom):
79+
def __init__(self, dom: minidom.Element | minidom.Document):
7980
self.__node = dom
8081

81-
def __repr__(self):
82+
def __repr__(self) -> str:
8283
return self.__node.toxml()
8384

84-
def find_first_by_tag(self, tag):
85+
def find_first_by_tag(self, tag: str) -> DomNode | None:
8586
return self.find_nth_by_tag(tag, 0)
8687

87-
def _by_tag(self, tag):
88-
return self.__node.getElementsByTagName(tag)
89-
9088
@property
91-
def children(self):
89+
def children(self) -> list[DomNode]:
9290
return [type(self)(x) for x in self.__node.childNodes]
9391

9492
@property
95-
def get_unique_child(self):
93+
def get_unique_child(self) -> DomNode:
9694
children = self.children
9795
assert len(children) == 1
9896
return children[0]
9997

100-
def find_nth_by_tag(self, tag, n):
101-
items = self._by_tag(tag)
98+
def find_nth_by_tag(self, tag: str, n: int) -> DomNode | None:
99+
items = self.__node.getElementsByTagName(tag)
102100
try:
103101
nth = items[n]
104102
except IndexError:
105-
pass
103+
return None
106104
else:
107105
return type(self)(nth)
108106

109-
def find_by_tag(self, tag):
107+
def find_by_tag(self, tag: str) -> list[DomNode]:
110108
t = type(self)
111109
return [t(x) for x in self.__node.getElementsByTagName(tag)]
112110

@@ -115,23 +113,25 @@ def __getitem__(self, key):
115113
if node is not None:
116114
return node.value
117115

118-
def assert_attr(self, **kwargs):
116+
def assert_attr(self, **kwargs: object) -> None:
119117
__tracebackhide__ = True
118+
assert isinstance(self.__node, minidom.Element)
120119
return assert_attr(self.__node, **kwargs)
121120

122-
def toxml(self):
121+
def toxml(self) -> str:
123122
return self.__node.toxml()
124123

125124
@property
126-
def text(self):
127-
return self.__node.childNodes[0].wholeText
125+
def text(self) -> str:
126+
return cast(str, self.__node.childNodes[0].wholeText)
128127

129128
@property
130-
def tag(self):
129+
def tag(self) -> str:
130+
assert isinstance(self.__node, minidom.Element)
131131
return self.__node.tagName
132132

133133
@property
134-
def next_sibling(self):
134+
def next_sibling(self) -> DomNode:
135135
return type(self)(self.__node.nextSibling)
136136

137137

@@ -225,7 +225,10 @@ def test_pass():
225225
assert start_time <= timestamp < datetime.now()
226226

227227
def test_timing_function(
228-
self, pytester: Pytester, run_and_parse: RunAndParse, mock_timing
228+
self,
229+
pytester: Pytester,
230+
run_and_parse: RunAndParse,
231+
mock_timing: _pytest.timing.MockTiming,
229232
) -> None:
230233
pytester.makepyfile(
231234
"""
@@ -255,7 +258,7 @@ def test_junit_duration_report(
255258
# mock LogXML.node_reporter so it always sets a known duration to each test report object
256259
original_node_reporter = LogXML.node_reporter
257260

258-
def node_reporter_wrapper(s, report):
261+
def node_reporter_wrapper(s: Any, report: TestReport) -> Any:
259262
report.duration = 1.0
260263
reporter = original_node_reporter(s, report)
261264
return reporter
@@ -499,9 +502,9 @@ def test_internal_error(
499502
def test_failure_function(
500503
self,
501504
pytester: Pytester,
502-
junit_logging,
505+
junit_logging: str,
503506
run_and_parse: RunAndParse,
504-
xunit_family,
507+
xunit_family: str,
505508
) -> None:
506509
pytester.makepyfile(
507510
"""
@@ -599,9 +602,9 @@ def test_func(arg1):
599602
assert result.ret
600603
node = dom.find_first_by_tag("testsuite")
601604
node.assert_attr(failures=3, tests=3)
602-
603-
for index, char in enumerate("<&'"):
604-
tnode = node.find_nth_by_tag("testcase", index)
605+
tnodes = node.find_by_tag("testcase")
606+
assert len(tnodes) == 3
607+
for tnode, char in zip(tnodes, "<&'"):
605608
tnode.assert_attr(
606609
classname="test_failure_escape", name=f"test_func[{char}]"
607610
)
@@ -944,12 +947,12 @@ class FakeConfig:
944947
if TYPE_CHECKING:
945948
workerinput = None
946949

947-
def __init__(self):
950+
def __init__(self) -> None:
948951
self.pluginmanager = self
949952
self.option = self
950953
self.stash = Stash()
951954

952-
def getini(self, name):
955+
def getini(self, name: object) -> str:
953956
return "pytest"
954957

955958
junitprefix = None
@@ -1468,7 +1471,7 @@ def test_pass():
14681471
result.stdout.no_fnmatch_line("*INTERNALERROR*")
14691472

14701473
items = sorted(
1471-
"%(classname)s %(name)s" % x # noqa: UP031
1474+
f"{x['classname']} {x['name']}"
14721475
# dom is a DomNode not a mapping, it's not possible to ** it.
14731476
for x in dom.find_by_tag("testcase")
14741477
)

0 commit comments

Comments
 (0)