1+ from __future__ import annotations
2+
3+ from collections .abc import Generator
4+ from collections .abc import Iterable
5+ from collections .abc import Mapping
6+ from typing import TYPE_CHECKING
17from typing import Any
2- from typing import Generator
3- from typing import Iterable
4- from typing import List
5- from typing import Mapping
6- from typing import Optional
7- from typing import Tuple
88
99import pytest
1010from _pytest ._io .saferepr import saferepr
1111from _pytest .assertion .util import _compare_eq_any
12- from _pytest .config import Config
12+
13+ if TYPE_CHECKING :
14+ from _pytest .config import Config
1315
1416
1517class UnorderedList (list ):
16- def __init__ (self , expected : Iterable , check_type : bool = True ):
18+ def __init__ (self , expected : Iterable , * , check_type : bool = True ) -> None :
1719 if not isinstance (expected , Iterable ):
20+ msg = f"cannot make unordered comparisons to non-iterable: { expected !r} "
1821 raise TypeError (
19- "cannot make unordered comparisons to non-iterable: {!r}" . format ( expected )
22+ msg ,
2023 )
2124 if isinstance (expected , Mapping ):
22- raise TypeError ("cannot make unordered comparisons to mapping: {!r}" .format (expected ))
25+ msg = f"cannot make unordered comparisons to mapping: { expected !r} "
26+ raise TypeError (msg )
2327 super ().__init__ (expected )
24- self ._expected_type = type (expected ) if check_type else None
28+ self .expected_type = type (expected ) if check_type else None
2529
2630 def __eq__ (self , actual : object ) -> bool :
27- if self ._expected_type is not None and self ._expected_type != type (actual ):
31+ if self .expected_type is not None and self .expected_type is not type (actual ):
2832 return False
2933 if not isinstance (actual , Iterable ):
3034 return self .copy () == actual
@@ -37,16 +41,16 @@ def __eq__(self, actual: object) -> bool:
3741 def __ne__ (self , actual : object ) -> bool :
3842 return not (self == actual )
3943
40- def compare_to (self , other : List ) -> Tuple [ List , List ]:
44+ def compare_to (self , other : list ) -> tuple [ list , list ]:
4145 extra_left = list (self )
42- extra_right = []
43- reordered = []
46+ extra_right : list [ Any ] = []
47+ reordered : list [ Any ] = []
4448 placeholder = object ()
4549 for elem in other :
46- try :
50+ if elem in extra_left :
4751 i = extra_left .index (elem )
4852 reordered .append (extra_left .pop (i ))
49- except ValueError :
53+ else :
5054 extra_right .append (elem )
5155 reordered .append (placeholder )
5256 placeholder_fillers = extra_left .copy ()
@@ -59,7 +63,7 @@ def compare_to(self, other: List) -> Tuple[List, List]:
5963 return extra_left , extra_right
6064
6165
62- def unordered (* args : Any , check_type : Optional [ bool ] = None ) -> UnorderedList :
66+ def unordered (* args : Any , check_type : bool | None = None ) -> UnorderedList :
6367 if len (args ) == 1 :
6468 if check_type is None :
6569 check_type = not isinstance (args [0 ], Generator )
@@ -69,60 +73,61 @@ def unordered(*args: Any, check_type: Optional[bool] = None) -> UnorderedList:
6973
7074def unordered_deep (obj : Any ) -> Any :
7175 if isinstance (obj , dict ):
72- return dict (( k , unordered_deep (v )) for k , v in obj .items ())
73- if isinstance (obj , list ) or isinstance ( obj , tuple ):
74- return unordered (( unordered_deep (x ) for x in obj ) )
76+ return { k : unordered_deep (v ) for k , v in obj .items ()}
77+ if isinstance (obj , ( list , tuple ) ):
78+ return unordered (unordered_deep (x ) for x in obj )
7579 return obj
7680
7781
78- def _compare_eq_unordered (left : Iterable , right : Iterable ) -> Tuple [ List , List ]:
79- extra_left = []
82+ def _compare_eq_unordered (left : Iterable , right : Iterable ) -> tuple [ list , list ]:
83+ extra_left : list [ Any ] = []
8084 extra_right = list (right )
8185 for elem in left :
82- try :
86+ if elem in extra_right :
8387 extra_right .remove (elem )
84- except ValueError :
88+ else :
8589 extra_left .append (elem )
8690 return extra_left , extra_right
8791
8892
8993def pytest_assertrepr_compare (
90- config : Config , op : str , left : Any , right : Any
91- ) -> Optional [List [str ]]:
94+ config : Config ,
95+ op : str ,
96+ left : Any ,
97+ right : Any ,
98+ ) -> list [str ] | None :
9299 if (isinstance (left , UnorderedList ) or isinstance (right , UnorderedList )) and op == "==" :
93100 verbose = config .getoption ("verbose" )
94101 left_repr = saferepr (left )
95102 right_repr = saferepr (right )
96- result = ["{ } {} {}" . format ( left_repr , op , right_repr ) ]
97- left_type = left ._expected_type if isinstance (left , UnorderedList ) else type (left )
98- right_type = right ._expected_type if isinstance (right , UnorderedList ) else type (right )
103+ result = [f" { left_repr } { op } { right_repr } " ]
104+ left_type = left .expected_type if isinstance (left , UnorderedList ) else type (left )
105+ right_type = right .expected_type if isinstance (right , UnorderedList ) else type (right )
99106 if left_type and right_type and left_type != right_type :
100107 result .append ("Type mismatch:" )
101- result .append ("{ } != {}" . format ( left_type , right_type ) )
108+ result .append (f" { left_type } != { right_type } " )
102109 extra_left , extra_right = _compare_eq_unordered (left , right )
103110 if len (extra_left ) == 1 and len (extra_right ) == 1 :
104111 result .append ("One item replaced:" )
105- if pytest .version_tuple < (8 , 0 , 0 ):
112+ if pytest .version_tuple < (8 , 0 , 0 ): # pragma: no cover
106113 result .extend (
107- _compare_eq_any (extra_left [0 ], extra_right [0 ], verbose = verbose ) # type: ignore
114+ _compare_eq_any (extra_left [0 ], extra_right [0 ], verbose = verbose ), # type: ignore[call-arg]
108115 )
109116 else :
110117 result .extend (
111118 _compare_eq_any (
112119 extra_left [0 ],
113120 extra_right [0 ],
114- highlighter = config .get_terminal_writer ()._highlight ,
121+ highlighter = config .get_terminal_writer ()._highlight , # noqa: SLF001
115122 verbose = verbose ,
116- )
123+ ),
117124 )
118125 else :
119126 if extra_left :
120127 result .append ("Extra items in the left sequence:" )
121- for item in extra_left :
122- result .append (saferepr (item ))
128+ result .extend (saferepr (item ) for item in extra_left )
123129 if extra_right :
124130 result .append ("Extra items in the right sequence:" )
125- for item in extra_right :
126- result .append (saferepr (item ))
131+ result .extend (saferepr (item ) for item in extra_right )
127132 return result
128133 return None
0 commit comments