55import os
66from pathlib import Path
77import platform
8+ from typing import Any
89from typing import cast
910from typing import TYPE_CHECKING
1011from xml .dom import minidom
2021from _pytest .reports import BaseReport
2122from _pytest .reports import TestReport
2223from _pytest .stash import Stash
24+ import _pytest .timing
2325import 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
7778class 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