Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/_testing/asserters.py: 12%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

460 statements  

1from __future__ import annotations 

2 

3import operator 

4from typing import ( 

5 TYPE_CHECKING, 

6 Any, 

7 Literal, 

8 NoReturn, 

9 cast, 

10) 

11import warnings 

12 

13import numpy as np 

14 

15from pandas._libs import lib 

16from pandas._libs.missing import is_matching_na 

17from pandas._libs.sparse import SparseIndex 

18import pandas._libs.testing as _testing 

19from pandas._libs.tslibs.np_datetime import compare_mismatched_resolutions 

20from pandas.errors import Pandas4Warning 

21from pandas.util._decorators import ( 

22 deprecate_kwarg, 

23 set_module, 

24) 

25from pandas.util._exceptions import find_stack_level 

26 

27from pandas.core.dtypes.cast import construct_1d_object_array_from_listlike 

28from pandas.core.dtypes.common import ( 

29 is_bool, 

30 is_float_dtype, 

31 is_integer_dtype, 

32 is_number, 

33 is_numeric_dtype, 

34 needs_i8_conversion, 

35) 

36from pandas.core.dtypes.dtypes import ( 

37 CategoricalDtype, 

38 DatetimeTZDtype, 

39 ExtensionDtype, 

40 NumpyEADtype, 

41) 

42from pandas.core.dtypes.missing import array_equivalent 

43 

44import pandas as pd 

45from pandas import ( 

46 Categorical, 

47 CategoricalIndex, 

48 DataFrame, 

49 DatetimeIndex, 

50 Index, 

51 IntervalDtype, 

52 IntervalIndex, 

53 MultiIndex, 

54 PeriodIndex, 

55 RangeIndex, 

56 Series, 

57 TimedeltaIndex, 

58) 

59from pandas.core.arrays import ( 

60 DatetimeArray, 

61 ExtensionArray, 

62 IntervalArray, 

63 PeriodArray, 

64 TimedeltaArray, 

65) 

66from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin 

67from pandas.core.arrays.string_ import StringDtype 

68from pandas.core.indexes.api import safe_sort_index 

69 

70from pandas.io.formats.printing import pprint_thing 

71 

72if TYPE_CHECKING: 

73 from collections.abc import ( 

74 Container, 

75 Iterable, 

76 ) 

77 

78 from pandas._typing import DtypeObj 

79 

80 

81def assert_almost_equal( 

82 left: Any, 

83 right: Any, 

84 check_dtype: bool | Literal["equiv"] = "equiv", 

85 rtol: float = 1.0e-5, 

86 atol: float = 1.0e-8, 

87 **kwargs: Any, 

88) -> None: 

89 """ 

90 Check that the left and right objects are approximately equal. 

91 

92 By approximately equal, we refer to objects that are numbers or that 

93 contain numbers which may be equivalent to specific levels of precision. 

94 

95 Parameters 

96 ---------- 

97 left : object 

98 right : object 

99 check_dtype : bool or {'equiv'}, default 'equiv' 

100 Check dtype if both a and b are the same type. If 'equiv' is passed in, 

101 then `RangeIndex` and `Index` with int64 dtype are also considered 

102 equivalent when doing type checking. 

103 rtol : float, default 1e-5 

104 Relative tolerance. Only applied to numeric dtypes; values of other 

105 dtypes, such as interval, are always compared exactly. 

106 atol : float, default 1e-8 

107 Absolute tolerance. Only applied to numeric dtypes; values of other 

108 dtypes, such as interval, are always compared exactly. 

109 """ 

110 if isinstance(left, Index): 

111 assert_index_equal( 

112 left, 

113 right, 

114 check_exact=False, 

115 exact=check_dtype, 

116 rtol=rtol, 

117 atol=atol, 

118 **kwargs, 

119 ) 

120 

121 elif isinstance(left, Series): 

122 assert_series_equal( 

123 left, 

124 right, 

125 check_exact=False, 

126 check_dtype=check_dtype, 

127 rtol=rtol, 

128 atol=atol, 

129 **kwargs, 

130 ) 

131 

132 elif isinstance(left, DataFrame): 

133 assert_frame_equal( 

134 left, 

135 right, 

136 check_exact=False, 

137 check_dtype=check_dtype, 

138 rtol=rtol, 

139 atol=atol, 

140 **kwargs, 

141 ) 

142 

143 else: 

144 # Other sequences. 

145 if check_dtype: 

146 if is_number(left) and is_number(right): 

147 # Do not compare numeric classes, like np.float64 and float. 

148 pass 

149 elif is_bool(left) and is_bool(right): 

150 # Do not compare bool classes, like np.bool_ and bool. 

151 pass 

152 else: 

153 if isinstance(left, np.ndarray) or isinstance(right, np.ndarray): 

154 obj = "numpy array" 

155 else: 

156 obj = "Input" 

157 assert_class_equal(left, right, obj=obj) 

158 

159 # if we have "equiv", this becomes True 

160 _testing.assert_almost_equal( 

161 left, right, check_dtype=bool(check_dtype), rtol=rtol, atol=atol, **kwargs 

162 ) 

163 

164 

165def _check_isinstance(left: Any, right: Any, cls: type) -> None: 

166 """ 

167 Helper method for our assert_* methods that ensures that 

168 the two objects being compared have the right type before 

169 proceeding with the comparison. 

170 

171 Parameters 

172 ---------- 

173 left : The first object being compared. 

174 right : The second object being compared. 

175 cls : The class type to check against. 

176 

177 Raises 

178 ------ 

179 AssertionError : Either `left` or `right` is not an instance of `cls`. 

180 """ 

181 cls_name = cls.__name__ 

182 

183 if not isinstance(left, cls): 

184 raise AssertionError( 

185 f"{cls_name} Expected type {cls}, found {type(left)} instead" 

186 ) 

187 if not isinstance(right, cls): 

188 raise AssertionError( 

189 f"{cls_name} Expected type {cls}, found {type(right)} instead" 

190 ) 

191 

192 

193def assert_dict_equal( 

194 left: dict[Any, Any], right: dict[Any, Any], compare_keys: bool = True 

195) -> None: 

196 _check_isinstance(left, right, dict) 

197 _testing.assert_dict_equal(left, right, compare_keys=compare_keys) 

198 

199 

200def _resolve_check_freq( 

201 index: Index, check_freq: bool | lib.NoDefault 

202) -> bool | lib.NoDefault: 

203 """ 

204 Resolve an unspecified check_freq for a Series/DataFrame axis. 

205 

206 The hard freq check has long applied only to a flat DatetimeIndex or 

207 TimedeltaIndex, so preserve that. Freqs nested inside a MultiIndex level or 

208 inside Categorical categories were not checked before, so those go through 

209 the deprecation warning in assert_index_equal. GH#51920, GH#66761 

210 """ 

211 if check_freq is lib.no_default and isinstance( 

212 index, (DatetimeIndex, TimedeltaIndex) 

213 ): 

214 return True 

215 return check_freq 

216 

217 

218@set_module("pandas.testing") 

219def assert_index_equal( 

220 left: Index, 

221 right: Index, 

222 exact: bool | str | lib.NoDefault = lib.no_default, 

223 check_names: bool = True, 

224 check_exact: bool = True, 

225 check_categorical: bool = True, 

226 check_order: bool = True, 

227 rtol: float = 1.0e-5, 

228 atol: float = 1.0e-8, 

229 obj: str | None = None, 

230 *, 

231 check_freq: bool | lib.NoDefault = lib.no_default, 

232) -> None: 

233 """ 

234 Check that left and right Index are equal. 

235 

236 This function compares two Index objects and raises an ``AssertionError`` 

237 if they are not equal. It provides fine-grained control over which 

238 attributes to check, including dtype, names, and categorical properties. 

239 

240 Parameters 

241 ---------- 

242 left : Index 

243 The first index to compare. 

244 right : Index 

245 The second index to compare. 

246 exact : bool or {'equiv'}, default 'equiv' 

247 Whether to check the Index class, dtype and inferred_type 

248 are identical. If 'equiv', then RangeIndex can be substituted for 

249 Index with an int64 dtype as well. 

250 

251 .. deprecated:: 3.1.0 

252 The default value of 'equiv' has been deprecated and will be changed to 

253 True in the future. 

254 

255 check_names : bool, default True 

256 Whether to check the names attribute. 

257 check_exact : bool, default True 

258 Whether to compare number exactly. 

259 check_categorical : bool, default True 

260 Whether to compare internal Categorical exactly. 

261 check_order : bool, default True 

262 Whether to compare the order of index entries as well as their values. 

263 If True, both indexes must contain the same elements, in the same order. 

264 If False, both indexes must contain the same elements, but in any order. 

265 rtol : float, default 1e-5 

266 Relative tolerance. Only used when check_exact is False, and only 

267 applied to numeric dtypes; values of other dtypes, such as interval, 

268 are always compared exactly. 

269 atol : float, default 1e-8 

270 Absolute tolerance. Only used when check_exact is False, and only 

271 applied to numeric dtypes; values of other dtypes, such as interval, 

272 are always compared exactly. 

273 obj : str, default 'Index' or 'MultiIndex' 

274 Specify object name being compared, internally used to show appropriate 

275 assertion message. 

276 check_freq : bool, default True 

277 Whether to check the ``freq`` attribute on a DatetimeIndex or 

278 TimedeltaIndex. This check is skipped when ``check_order=False``, 

279 as sorting does not preserve ``freq``. 

280 

281 .. versionadded:: 3.1.0 

282 

283 .. deprecated:: 3.1.0 

284 Currently a ``freq`` mismatch only warns; in a future version 

285 ``check_freq=True`` will be the default and mismatches will 

286 raise. Pass ``check_freq`` explicitly to silence the warning. 

287 

288 See Also 

289 -------- 

290 testing.assert_series_equal : Check that two Series are equal. 

291 testing.assert_frame_equal : Check that two DataFrames are equal. 

292 

293 Examples 

294 -------- 

295 >>> from pandas import testing as tm 

296 >>> a = pd.Index([1, 2, 3]) 

297 >>> b = pd.Index([1, 2, 3]) 

298 >>> tm.assert_index_equal(a, b) 

299 """ 

300 __tracebackhide__ = True 

301 

302 if obj is None: 

303 obj = "MultiIndex" if isinstance(left, MultiIndex) else "Index" 

304 

305 def _check_rangeindex_index_int(left: Index, right: Index) -> bool: 

306 return ( 

307 isinstance(left, RangeIndex) 

308 and isinstance(right, Index) 

309 and not isinstance(right, RangeIndex) 

310 and is_integer_dtype(right.dtype) 

311 ) or ( 

312 isinstance(right, RangeIndex) 

313 and isinstance(left, Index) 

314 and not isinstance(left, RangeIndex) 

315 and is_integer_dtype(left.dtype) 

316 ) 

317 

318 if exact is lib.no_default: 

319 if _check_rangeindex_index_int(left, right): 

320 warnings.warn( 

321 "The default value of 'equiv' for the `exact` parameter is deprecated " 

322 "and will be changed to 'True' in a future version. Please set exact " 

323 "to the desired value to avoid seeing this warning", 

324 Pandas4Warning, 

325 stacklevel=find_stack_level(), 

326 ) 

327 exact = "equiv" 

328 

329 def _check_types(left: Index, right: Index, obj: str = "Index") -> None: 

330 if not exact: 

331 return 

332 

333 assert_class_equal(left, right, exact=exact, obj=obj) 

334 assert_attr_equal("inferred_type", left, right, obj=obj) 

335 

336 # Skip exact dtype checking when `check_categorical` is False 

337 if isinstance(left.dtype, CategoricalDtype) and isinstance( 

338 right.dtype, CategoricalDtype 

339 ): 

340 if check_categorical: 

341 assert_attr_equal("dtype", left, right, obj=obj) 

342 assert_index_equal( 

343 cast("CategoricalIndex", left).categories, 

344 cast("CategoricalIndex", right).categories, 

345 exact=exact, 

346 check_freq=check_freq, 

347 ) 

348 return 

349 

350 assert_attr_equal("dtype", left, right, obj=obj) 

351 

352 # instance validation 

353 _check_isinstance(left, right, Index) 

354 

355 # class / dtype comparison 

356 _check_types(left, right, obj=obj) 

357 

358 # level comparison 

359 if left.nlevels != right.nlevels: 

360 msg1 = f"{obj} levels are different" 

361 msg2 = f"{left.nlevels}, {left}" 

362 msg3 = f"{right.nlevels}, {right}" 

363 raise_assert_detail(obj, msg1, msg2, msg3) 

364 

365 # length comparison 

366 if len(left) != len(right): 

367 msg1 = f"{obj} length are different" 

368 msg2 = f"{len(left)}, {left}" 

369 msg3 = f"{len(right)}, {right}" 

370 raise_assert_detail(obj, msg1, msg2, msg3) 

371 

372 # If order doesn't matter then sort the index entries 

373 if not check_order: 

374 left = safe_sort_index(left) 

375 right = safe_sort_index(right) 

376 

377 # MultiIndex special comparison for little-friendly error messages 

378 if isinstance(left, MultiIndex): 

379 right = cast("MultiIndex", right) 

380 

381 # A freq mismatch in the levels is retried below on get_level_values, 

382 # which usually drops freq, so the levels comparison must not be what 

383 # emits the check_freq deprecation warning: it would warn in cases the 

384 # eventual check_freq=True default accepts. Resolve the sentinel to a 

385 # hard check here and let the retry decide. GH#66761 

386 levels_check_freq = True if check_freq is lib.no_default else check_freq 

387 

388 for level in range(left.nlevels): 

389 lobj = f"{obj} level [{level}]" 

390 try: 

391 # try comparison on levels/codes to avoid densifying MultiIndex 

392 assert_index_equal( 

393 left.levels[level], 

394 right.levels[level], 

395 exact=exact, 

396 check_names=check_names, 

397 check_exact=check_exact, 

398 check_categorical=check_categorical, 

399 check_freq=levels_check_freq, 

400 rtol=rtol, 

401 atol=atol, 

402 obj=lobj, 

403 ) 

404 assert_numpy_array_equal(left.codes[level], right.codes[level]) 

405 except AssertionError: 

406 llevel = left.get_level_values(level) 

407 rlevel = right.get_level_values(level) 

408 

409 assert_index_equal( 

410 llevel, 

411 rlevel, 

412 exact=exact, 

413 check_names=check_names, 

414 check_exact=check_exact, 

415 check_categorical=check_categorical, 

416 check_freq=check_freq, 

417 rtol=rtol, 

418 atol=atol, 

419 obj=lobj, 

420 ) 

421 # get_level_values may change dtype 

422 _check_types(left.levels[level], right.levels[level], obj=lobj) 

423 

424 # skip exact index checking when `check_categorical` is False 

425 elif check_exact and check_categorical: 

426 if not left.equals(right): 

427 # _values compare can raise TypeError (non-comparable 

428 # categoricals (GH#61935) 

429 try: 

430 mismatch = left._values != right._values 

431 except TypeError: 

432 raise_assert_detail( 

433 obj, 

434 "types are not comparable (non-matching categorical categories)", 

435 left, 

436 right, 

437 ) 

438 

439 if not isinstance(mismatch, np.ndarray): 

440 mismatch = cast("ExtensionArray", mismatch).fillna(True) 

441 

442 diff = np.sum(mismatch.astype(int)) * 100.0 / len(left) 

443 msg = f"{obj} values are different ({np.round(diff, 5)} %)" 

444 raise_assert_detail(obj, msg, left, right) 

445 else: 

446 # if we have "equiv", this becomes True 

447 exact_bool = bool(exact) 

448 _testing.assert_almost_equal( 

449 left._values, 

450 right._values, 

451 rtol=rtol, 

452 atol=atol, 

453 check_dtype=exact_bool, 

454 obj=obj, 

455 lobj=left, 

456 robj=right, 

457 ) 

458 

459 # metadata comparison 

460 if check_names: 

461 assert_attr_equal("names", left, right, obj=obj) 

462 if isinstance(left, PeriodIndex) or isinstance(right, PeriodIndex): 

463 assert_attr_equal("dtype", left, right, obj=obj) 

464 if isinstance(left, IntervalIndex) or isinstance(right, IntervalIndex): 

465 assert_interval_array_equal( 

466 cast("IntervalArray", left._values), 

467 cast("IntervalArray", right._values), 

468 ) 

469 

470 # freq is not preserved by sorting, so when check_order=False the freqs 

471 # of the sorted copies are meaningless and the check is skipped 

472 if ( 

473 check_order 

474 and isinstance(left, (DatetimeIndex, TimedeltaIndex)) 

475 and isinstance(right, (DatetimeIndex, TimedeltaIndex)) 

476 ): 

477 if check_freq is lib.no_default: 

478 if left.freq != right.freq: 

479 warnings.warn( 

480 "assert_index_equal will check the 'freq' attribute by " 

481 f"default in a future version; these freqs {left.freq!r} " 

482 f"and {right.freq!r} do not match. Pass check_freq=True " 

483 "or check_freq=False to silence this warning", 

484 Pandas4Warning, 

485 stacklevel=find_stack_level(), 

486 ) 

487 elif check_freq: 

488 assert_attr_equal("freq", left, right, obj=obj) 

489 

490 if check_categorical: 

491 if isinstance(left.dtype, CategoricalDtype) or isinstance( 

492 right.dtype, CategoricalDtype 

493 ): 

494 assert_categorical_equal( 

495 cast("Categorical", left._values), 

496 cast("Categorical", right._values), 

497 check_freq=check_freq, 

498 obj=f"{obj} category", 

499 ) 

500 

501 

502def assert_class_equal( 

503 left: Any, right: Any, exact: bool | str = True, obj: str = "Input" 

504) -> None: 

505 """ 

506 Checks classes are equal. 

507 """ 

508 __tracebackhide__ = True 

509 

510 def repr_class(x: Any) -> Any: 

511 if isinstance(x, Index): 

512 # return Index as it is to include values in the error message 

513 return x 

514 

515 return type(x).__name__ 

516 

517 def is_class_equiv(idx: Index) -> bool: 

518 """Classes that are a RangeIndex (sub-)instance or exactly an `Index` . 

519 

520 This only checks class equivalence. There is a separate check that the 

521 dtype is int64. 

522 """ 

523 return type(idx) is Index or isinstance(idx, RangeIndex) 

524 

525 if type(left) == type(right): 

526 return 

527 

528 if exact == "equiv": 

529 if is_class_equiv(left) and is_class_equiv(right): 

530 return 

531 

532 msg = f"{obj} classes are different" 

533 raise_assert_detail(obj, msg, repr_class(left), repr_class(right)) 

534 

535 

536def assert_attr_equal( 

537 attr: str, left: Any, right: Any, obj: str = "Attributes" 

538) -> None: 

539 """ 

540 Check attributes are equal. Both objects must have attribute. 

541 

542 Parameters 

543 ---------- 

544 attr : str 

545 Attribute name being compared. 

546 left : object 

547 right : object 

548 obj : str, default 'Attributes' 

549 Specify object name being compared, internally used to show appropriate 

550 assertion message 

551 """ 

552 __tracebackhide__ = True 

553 

554 left_attr = getattr(left, attr) 

555 right_attr = getattr(right, attr) 

556 

557 if left_attr is right_attr or is_matching_na(left_attr, right_attr): 

558 # e.g. both np.nan, both NaT, both pd.NA, ... 

559 return None 

560 

561 try: 

562 result = left_attr == right_attr 

563 except TypeError: 

564 # datetimetz on rhs may raise TypeError 

565 result = False 

566 if (left_attr is pd.NA) ^ (right_attr is pd.NA): 

567 result = False 

568 elif not isinstance(result, bool): 

569 result = result.all() 

570 

571 if ( 

572 not result 

573 and isinstance(left_attr, (tuple, list)) 

574 and type(left_attr) is type(right_attr) 

575 ): 

576 # MultiIndex labels (tuples) and Index.names (FrozenList) can contain 

577 # NA values that == does not treat as equal. 

578 try: 

579 result = array_equivalent( 

580 construct_1d_object_array_from_listlike(left_attr), 

581 construct_1d_object_array_from_listlike(right_attr), 

582 strict_nan=True, 

583 ) 

584 except TypeError: 

585 result = False 

586 

587 if not result: 

588 msg = f'Attribute "{attr}" are different' 

589 raise_assert_detail(obj, msg, left_attr, right_attr) 

590 return None 

591 

592 

593def assert_is_sorted(seq: Index | Series | np.ndarray | ExtensionArray) -> None: 

594 """Assert that the sequence is sorted.""" 

595 if isinstance(seq, (Index, Series)): 

596 seq = seq._values 

597 # sorting does not change precisions 

598 if isinstance(seq, np.ndarray): 

599 assert_numpy_array_equal(seq, np.sort(np.array(seq))) 

600 else: 

601 assert_extension_array_equal(seq, seq[seq.argsort()]) 

602 

603 

604def assert_categorical_equal( 

605 left: Categorical, 

606 right: Categorical, 

607 check_dtype: bool = True, 

608 check_category_order: bool = True, 

609 obj: str = "Categorical", 

610 *, 

611 check_freq: bool | lib.NoDefault = lib.no_default, 

612) -> None: 

613 """ 

614 Test that Categoricals are equivalent. 

615 

616 Parameters 

617 ---------- 

618 left : Categorical 

619 right : Categorical 

620 check_dtype : bool, default True 

621 Check that integer dtype of the codes are the same. 

622 check_category_order : bool, default True 

623 Whether the order of the categories should be compared, which 

624 implies identical integer codes. If False, only the resulting 

625 values are compared. The ordered attribute is 

626 checked regardless. 

627 obj : str, default 'Categorical' 

628 Specify object name being compared, internally used to show appropriate 

629 assertion message. 

630 check_freq : bool, default True 

631 Whether to check the ``freq`` attribute of DatetimeIndex or 

632 TimedeltaIndex categories. 

633 

634 .. versionadded:: 3.1.0 

635 

636 .. deprecated:: 3.1.0 

637 Currently a ``freq`` mismatch only warns; in a future version 

638 ``check_freq=True`` will be the default and mismatches will 

639 raise. Pass ``check_freq`` explicitly to silence the warning. 

640 """ 

641 _check_isinstance(left, right, Categorical) 

642 

643 exact: bool | str 

644 if isinstance(left.categories, RangeIndex) or isinstance( 

645 right.categories, RangeIndex 

646 ): 

647 exact = "equiv" 

648 else: 

649 # We still want to require exact matches for Index 

650 exact = True 

651 

652 if check_category_order: 

653 assert_index_equal( 

654 left.categories, 

655 right.categories, 

656 obj=f"{obj}.categories", 

657 exact=exact, 

658 check_freq=check_freq, 

659 ) 

660 assert_numpy_array_equal( 

661 left.codes, right.codes, check_dtype=check_dtype, obj=f"{obj}.codes" 

662 ) 

663 else: 

664 try: 

665 lc = left.categories.sort_values() 

666 rc = right.categories.sort_values() 

667 except TypeError: 

668 # e.g. '<' not supported between instances of 'int' and 'str' 

669 lc, rc = left.categories, right.categories 

670 assert_index_equal( 

671 lc, 

672 rc, 

673 obj=f"{obj}.categories", 

674 exact=exact, 

675 check_freq=check_freq, 

676 ) 

677 # GH#62008 Compare the values as objects. Taking the categories with 

678 # the raw codes would treat the -1 code used for NA as a positional 

679 # indexer for the last category, and filling instead would cast 

680 # integer categories to float64. 

681 assert_numpy_array_equal( 

682 left.astype(object), 

683 right.astype(object), 

684 obj=f"{obj}.values", 

685 ) 

686 

687 assert_attr_equal("ordered", left, right, obj=obj) 

688 

689 

690def assert_interval_array_equal( 

691 left: IntervalArray, 

692 right: IntervalArray, 

693 obj: str = "IntervalArray", 

694) -> None: 

695 """ 

696 Test that two IntervalArrays are equivalent. 

697 

698 Parameters 

699 ---------- 

700 left, right : IntervalArray 

701 The IntervalArrays to compare. 

702 obj : str, default 'IntervalArray' 

703 Specify object name being compared, internally used to show appropriate 

704 assertion message 

705 """ 

706 _check_isinstance(left, right, IntervalArray) 

707 

708 assert_equal(left._left, right._left, obj=f"{obj}.left") 

709 assert_equal(left._right, right._right, obj=f"{obj}.right") 

710 

711 assert_attr_equal("closed", left, right, obj=obj) 

712 

713 

714def assert_period_array_equal( 

715 left: PeriodArray, right: PeriodArray, obj: str = "PeriodArray" 

716) -> None: 

717 _check_isinstance(left, right, PeriodArray) 

718 

719 assert_numpy_array_equal(left._ndarray, right._ndarray, obj=f"{obj}._ndarray") 

720 assert_attr_equal("dtype", left, right, obj=obj) 

721 

722 

723def assert_datetime_array_equal( 

724 left: DatetimeArray, right: DatetimeArray, obj: str = "DatetimeArray" 

725) -> None: 

726 __tracebackhide__ = True 

727 _check_isinstance(left, right, DatetimeArray) 

728 

729 assert_numpy_array_equal(left._ndarray, right._ndarray, obj=f"{obj}._ndarray") 

730 assert_attr_equal("tz", left, right, obj=obj) 

731 

732 

733def assert_timedelta_array_equal( 

734 left: TimedeltaArray, right: TimedeltaArray, obj: str = "TimedeltaArray" 

735) -> None: 

736 __tracebackhide__ = True 

737 _check_isinstance(left, right, TimedeltaArray) 

738 assert_numpy_array_equal(left._ndarray, right._ndarray, obj=f"{obj}._ndarray") 

739 

740 

741def raise_assert_detail( 

742 obj: Any, 

743 message: str, 

744 left: Any, 

745 right: Any, 

746 diff: Any = None, 

747 first_diff: Any = None, 

748 index_values: Index | np.ndarray | None = None, 

749) -> NoReturn: 

750 __tracebackhide__ = True 

751 

752 msg = f"""{obj} are different 

753 

754{message}""" 

755 

756 if isinstance(index_values, Index): 

757 index_values = np.asarray(index_values) 

758 

759 if isinstance(index_values, np.ndarray): 

760 msg += f"\n[index]: {pprint_thing(index_values)}" 

761 

762 if isinstance(left, np.ndarray): 

763 left = pprint_thing(left) 

764 elif isinstance(left, (CategoricalDtype, StringDtype, NumpyEADtype)): 

765 left = repr(left) 

766 

767 if isinstance(right, np.ndarray): 

768 right = pprint_thing(right) 

769 elif isinstance(right, (CategoricalDtype, StringDtype, NumpyEADtype)): 

770 right = repr(right) 

771 

772 msg += f""" 

773[left]: {left} 

774[right]: {right}""" 

775 

776 if diff is not None: 

777 msg += f"\n[diff]: {diff}" 

778 

779 if first_diff is not None: 

780 msg += f"\n{first_diff}" 

781 

782 raise AssertionError(msg) 

783 

784 

785def assert_numpy_array_equal( 

786 left: Any, 

787 right: Any, 

788 strict_nan: bool = False, 

789 check_dtype: bool | Literal["equiv"] = True, 

790 err_msg: str | None = None, 

791 check_same: Literal["copy", "same"] | None = None, 

792 obj: str = "numpy array", 

793 index_values: Index | np.ndarray | None = None, 

794 *, 

795 class_obj: str | None = None, 

796) -> None: 

797 """ 

798 Check that 'np.ndarray' is equivalent. 

799 

800 Parameters 

801 ---------- 

802 left, right : numpy.ndarray or iterable 

803 The two arrays to be compared. 

804 strict_nan : bool, default False 

805 If True, consider NaN and None to be different. 

806 check_dtype : bool, default True 

807 Check dtype if both a and b are np.ndarray. 

808 err_msg : str, default None 

809 If provided, used as assertion message. 

810 check_same : None|'copy'|'same', default None 

811 Ensure left and right refer/do not refer to the same memory area. 

812 obj : str, default 'numpy array' 

813 Specify object name being compared, internally used to show appropriate 

814 assertion message. 

815 index_values : Index | numpy.ndarray, default None 

816 optional index (shared by both left and right), used in output. 

817 class_obj : str, default None 

818 Specify object name for class comparison, internally used to show 

819 appropriate assertion message. 

820 """ 

821 __tracebackhide__ = True 

822 

823 # instance validation 

824 # Show a detailed error message when classes are different 

825 assert_class_equal(left, right, obj=class_obj or obj) 

826 # both classes must be an np.ndarray 

827 _check_isinstance(left, right, np.ndarray) 

828 

829 def _get_base(obj: np.ndarray) -> Any: 

830 return obj.base if getattr(obj, "base", None) is not None else obj 

831 

832 left_base = _get_base(left) 

833 right_base = _get_base(right) 

834 

835 if check_same == "same": 

836 if left_base is not right_base: 

837 raise AssertionError(f"{left_base!r} is not {right_base!r}") 

838 elif check_same == "copy": 

839 if left_base is right_base: 

840 raise AssertionError(f"{left_base!r} is {right_base!r}") 

841 

842 def _raise(left: np.ndarray, right: np.ndarray, err_msg: str | None) -> NoReturn: 

843 if err_msg is None: 

844 if left.shape != right.shape: 

845 raise_assert_detail( 

846 obj, f"{obj} shapes are different", left.shape, right.shape 

847 ) 

848 

849 diff = 0.0 

850 # ravel so the count is over values, matching the `left.size` total 

851 for left_val, right_val in zip(left.ravel(), right.ravel(), strict=True): 

852 # count up differences 

853 if not array_equivalent(left_val, right_val, strict_nan=strict_nan): 

854 diff += 1 

855 

856 diff = diff * 100.0 / left.size 

857 msg = f"{obj} values are different ({np.round(diff, 5)} %)" 

858 raise_assert_detail(obj, msg, left, right, index_values=index_values) 

859 

860 raise AssertionError(err_msg) 

861 

862 # compare shape and values 

863 if not array_equivalent(left, right, strict_nan=strict_nan): 

864 _raise(left, right, err_msg) 

865 

866 if check_dtype: 

867 if isinstance(left, np.ndarray) and isinstance(right, np.ndarray): 

868 assert_attr_equal("dtype", left, right, obj=obj) 

869 

870 

871@set_module("pandas.testing") 

872def assert_extension_array_equal( 

873 left: ExtensionArray, 

874 right: ExtensionArray, 

875 check_dtype: bool | Literal["equiv"] = True, 

876 index_values: Index | np.ndarray | None = None, 

877 check_exact: bool | lib.NoDefault = lib.no_default, 

878 rtol: float | lib.NoDefault = lib.no_default, 

879 atol: float | lib.NoDefault = lib.no_default, 

880 obj: str = "ExtensionArray", 

881) -> None: 

882 """ 

883 Check that left and right ExtensionArrays are equal. 

884 

885 This method compares two ``ExtensionArray`` instances for equality, 

886 including checks for missing values, the dtype of the arrays, and 

887 the exactness of the comparison (or tolerance when comparing floats). 

888 

889 Parameters 

890 ---------- 

891 left, right : ExtensionArray 

892 The two arrays to compare. 

893 check_dtype : bool, default True 

894 Whether to check if the ExtensionArray dtypes are identical. 

895 index_values : Index | numpy.ndarray, default None 

896 Optional index (shared by both left and right), used in output. 

897 check_exact : bool, default False 

898 Whether to compare number exactly. 

899 

900 .. versionchanged:: 2.2.0 

901 

902 Defaults to True for integer dtypes if none of 

903 ``check_exact``, ``rtol`` and ``atol`` are specified. 

904 rtol : float, default 1e-5 

905 Relative tolerance. Only used when check_exact is False, and only 

906 applied to numeric dtypes; values of other dtypes, such as interval, 

907 are always compared exactly. 

908 atol : float, default 1e-8 

909 Absolute tolerance. Only used when check_exact is False, and only 

910 applied to numeric dtypes; values of other dtypes, such as interval, 

911 are always compared exactly. 

912 obj : str, default 'ExtensionArray' 

913 Specify object name being compared, internally used to show appropriate 

914 assertion message. 

915 

916 .. versionadded:: 2.0.0 

917 

918 See Also 

919 -------- 

920 testing.assert_series_equal : Check that left and right ``Series`` are equal. 

921 testing.assert_frame_equal : Check that left and right ``DataFrame`` are equal. 

922 testing.assert_index_equal : Check that left and right ``Index`` are equal. 

923 

924 Notes 

925 ----- 

926 Missing values are checked separately from valid values. 

927 A mask of missing values is computed for each and checked to match. 

928 The remaining all-valid values are cast to object dtype and checked. 

929 

930 Examples 

931 -------- 

932 >>> from pandas import testing as tm 

933 >>> a = pd.Series([1, 2, 3, 4]) 

934 >>> b, c = a.array, a.array 

935 >>> tm.assert_extension_array_equal(b, c) 

936 """ 

937 if ( 

938 check_exact is lib.no_default 

939 and rtol is lib.no_default 

940 and atol is lib.no_default 

941 ): 

942 check_exact = ( 

943 is_numeric_dtype(left.dtype) and not is_float_dtype(left.dtype) 

944 ) or (is_numeric_dtype(right.dtype) and not is_float_dtype(right.dtype)) 

945 elif check_exact is lib.no_default: 

946 check_exact = False 

947 

948 rtol = rtol if rtol is not lib.no_default else 1.0e-5 

949 atol = atol if atol is not lib.no_default else 1.0e-8 

950 

951 assert isinstance(left, ExtensionArray), "left is not an ExtensionArray" 

952 assert isinstance(right, ExtensionArray), "right is not an ExtensionArray" 

953 if check_dtype: 

954 assert_attr_equal("dtype", left, right, obj=f"Attributes of {obj}") 

955 

956 if ( 

957 isinstance(left, DatetimeLikeArrayMixin) 

958 and isinstance(right, DatetimeLikeArrayMixin) 

959 and type(right) == type(left) 

960 ): 

961 # GH 52449 

962 if not check_dtype and left.dtype.kind in "mM": 

963 if not isinstance(left.dtype, np.dtype): 

964 l_unit = cast("DatetimeTZDtype", left.dtype).unit 

965 else: 

966 l_unit = np.datetime_data(left.dtype)[0] 

967 if not isinstance(right.dtype, np.dtype): 

968 r_unit = cast("DatetimeTZDtype", right.dtype).unit 

969 else: 

970 r_unit = np.datetime_data(right.dtype)[0] 

971 if ( 

972 l_unit != r_unit 

973 and compare_mismatched_resolutions( 

974 left._ndarray, right._ndarray, operator.eq 

975 ).all() 

976 ): 

977 return 

978 # Avoid slow object-dtype comparisons 

979 # np.asarray for case where we have an np.MaskedArray 

980 assert_numpy_array_equal( 

981 np.asarray(left.asi8), 

982 np.asarray(right.asi8), 

983 index_values=index_values, 

984 obj=obj, 

985 ) 

986 return 

987 

988 left_na = np.asarray(left.isna()) 

989 right_na = np.asarray(right.isna()) 

990 assert_numpy_array_equal( 

991 left_na, right_na, obj=f"{obj} NA mask", index_values=index_values 

992 ) 

993 

994 # Specifically for StringArrayNumpySemantics, validate here we have a valid array 

995 if ( 

996 isinstance(left.dtype, StringDtype) 

997 and left.dtype.storage == "python" 

998 and left.dtype.na_value is np.nan 

999 ): 

1000 assert np.all( 

1001 [np.isnan(val) for val in left._ndarray[left_na]] # type: ignore[attr-defined] 

1002 ), "wrong missing value sentinels" 

1003 if ( 

1004 isinstance(right.dtype, StringDtype) 

1005 and right.dtype.storage == "python" 

1006 and right.dtype.na_value is np.nan 

1007 ): 

1008 assert np.all( 

1009 [np.isnan(val) for val in right._ndarray[right_na]] # type: ignore[attr-defined] 

1010 ), "wrong missing value sentinels" 

1011 

1012 left_valid = left[~left_na].to_numpy(dtype=object) 

1013 right_valid = right[~right_na].to_numpy(dtype=object) 

1014 if check_exact: 

1015 assert_numpy_array_equal( 

1016 left_valid, right_valid, obj=obj, index_values=index_values 

1017 ) 

1018 else: 

1019 _testing.assert_almost_equal( 

1020 left_valid, 

1021 right_valid, 

1022 check_dtype=bool(check_dtype), 

1023 rtol=rtol, 

1024 atol=atol, 

1025 obj=obj, 

1026 index_values=index_values, 

1027 ) 

1028 

1029 

1030# This could be refactored to use the NDFrame.equals method 

1031@set_module("pandas.testing") 

1032@deprecate_kwarg(Pandas4Warning, "check_datetimelike_compat", new_arg_name=None) 

1033def assert_series_equal( 

1034 left: Series, 

1035 right: Series, 

1036 check_dtype: bool | Literal["equiv"] = True, 

1037 check_index_type: bool | Literal["equiv"] = "equiv", 

1038 check_series_type: bool = True, 

1039 check_names: bool = True, 

1040 check_exact: bool | lib.NoDefault = lib.no_default, 

1041 check_datetimelike_compat: bool = False, 

1042 check_categorical: bool = True, 

1043 check_category_order: bool = True, 

1044 check_freq: bool | lib.NoDefault = lib.no_default, 

1045 check_flags: bool = True, 

1046 rtol: float | lib.NoDefault = lib.no_default, 

1047 atol: float | lib.NoDefault = lib.no_default, 

1048 obj: str = "Series", 

1049 *, 

1050 check_index: bool = True, 

1051 check_like: bool = False, 

1052) -> None: 

1053 """ 

1054 Check that left and right Series are equal. 

1055 

1056 This function compares two Series and raises an ``AssertionError`` if they 

1057 are not equal. It provides fine-grained control over which attributes to 

1058 check, including dtype, index, names, and categorical properties. 

1059 

1060 Parameters 

1061 ---------- 

1062 left : Series 

1063 First Series to compare. 

1064 right : Series 

1065 Second Series to compare. 

1066 check_dtype : bool, default True 

1067 Whether to check the Series dtype is identical. 

1068 check_index_type : bool or {'equiv'}, default 'equiv' 

1069 Whether to check the Index class, dtype and inferred_type 

1070 are identical. 

1071 check_series_type : bool, default True 

1072 Whether to check the Series class is identical. 

1073 check_names : bool, default True 

1074 Whether to check the Series and Index names attribute. 

1075 check_exact : bool, default False 

1076 Whether to compare number exactly. This also applies when checking 

1077 Index equivalence. 

1078 

1079 .. versionchanged:: 2.2.0 

1080 

1081 Defaults to True for integer dtypes if none of 

1082 ``check_exact``, ``rtol`` and ``atol`` are specified. 

1083 

1084 .. versionchanged:: 3.0.0 

1085 

1086 check_exact for comparing the Indexes defaults to True by 

1087 checking if an Index is of integer dtypes. 

1088 

1089 When ``check_exact=True``, the comparison of object-dtype values 

1090 containing nested :class:`numpy.ndarray` objects takes the type of 

1091 the nested object into account. In particular, a nested 

1092 ``numpy.ndarray`` is not considered equivalent to a Python 

1093 ``list``, Python ``tuple``, or a pandas 

1094 :class:`~pandas.api.extensions.ExtensionArray` merely because the 

1095 contained values are the same. 

1096 

1097 check_datetimelike_compat : bool, default False 

1098 Compare datetime-like which is comparable ignoring dtype. 

1099 

1100 .. deprecated:: 3.0 

1101 

1102 check_categorical : bool, default True 

1103 Whether to compare internal Categorical exactly. 

1104 check_category_order : bool, default True 

1105 Whether to compare category order of internal Categoricals. 

1106 check_freq : bool, default True 

1107 Whether to check the `freq` attribute on a DatetimeIndex or TimedeltaIndex. 

1108 The index check is skipped if ``check_index=False`` or ``check_like=True``. 

1109 

1110 .. deprecated:: 3.1.0 

1111 The ``freq`` attribute of a :class:`DatetimeIndex`/ 

1112 :class:`TimedeltaIndex` MultiIndex level or Categorical categories is 

1113 not yet checked by default; a mismatch currently only warns and will 

1114 raise in a future version. Pass ``check_freq`` explicitly to silence 

1115 the warning. 

1116 check_flags : bool, default True 

1117 Whether to check the `flags` attribute. 

1118 rtol : float, default 1e-5 

1119 Relative tolerance. Only used when check_exact is False, and only 

1120 applied to numeric dtypes; values of other dtypes, such as interval, 

1121 are always compared exactly. 

1122 atol : float, default 1e-8 

1123 Absolute tolerance. Only used when check_exact is False, and only 

1124 applied to numeric dtypes; values of other dtypes, such as interval, 

1125 are always compared exactly. 

1126 obj : str, default 'Series' 

1127 Specify object name being compared, internally used to show appropriate 

1128 assertion message. 

1129 check_index : bool, default True 

1130 Whether to check index equivalence. If False, then compare only values. 

1131 check_like : bool, default False 

1132 If True, ignore the order of the index. Must be False if check_index is False. 

1133 Note: same labels must be with the same data. 

1134 

1135 See Also 

1136 -------- 

1137 testing.assert_index_equal : Check that two Indexes are equal. 

1138 testing.assert_frame_equal : Check that two DataFrames are equal. 

1139 

1140 Examples 

1141 -------- 

1142 >>> from pandas import testing as tm 

1143 >>> a = pd.Series([1, 2, 3, 4]) 

1144 >>> b = pd.Series([1, 2, 3, 4]) 

1145 >>> tm.assert_series_equal(a, b) 

1146 """ 

1147 __tracebackhide__ = True 

1148 if ( 

1149 check_exact is lib.no_default 

1150 and rtol is lib.no_default 

1151 and atol is lib.no_default 

1152 ): 

1153 check_exact = ( 

1154 is_numeric_dtype(left.dtype) and not is_float_dtype(left.dtype) 

1155 ) or (is_numeric_dtype(right.dtype) and not is_float_dtype(right.dtype)) 

1156 left_index_dtypes = ( 

1157 [left.index.dtype] 

1158 if left.index.nlevels == 1 

1159 else cast("MultiIndex", left.index).dtypes 

1160 ) 

1161 right_index_dtypes = ( 

1162 [right.index.dtype] 

1163 if right.index.nlevels == 1 

1164 else cast("MultiIndex", right.index).dtypes 

1165 ) 

1166 check_exact_index = all( 

1167 dtype.kind in "iu" for dtype in left_index_dtypes 

1168 ) or all(dtype.kind in "iu" for dtype in right_index_dtypes) 

1169 elif check_exact is lib.no_default: 

1170 check_exact = False 

1171 check_exact_index = False 

1172 else: 

1173 check_exact_index = check_exact 

1174 

1175 rtol = rtol if rtol is not lib.no_default else 1.0e-5 

1176 atol = atol if atol is not lib.no_default else 1.0e-8 

1177 

1178 if not check_index and check_like: 

1179 raise ValueError("check_like must be False if check_index is False") 

1180 

1181 # instance validation 

1182 _check_isinstance(left, right, Series) 

1183 

1184 if check_series_type: 

1185 assert_class_equal(left, right, obj=obj) 

1186 

1187 # length comparison 

1188 if len(left) != len(right): 

1189 msg1 = f"{len(left)}, {left.index}" 

1190 msg2 = f"{len(right)}, {right.index}" 

1191 raise_assert_detail(obj, "Series length are different", msg1, msg2) 

1192 

1193 if check_flags: 

1194 assert left.flags == right.flags, f"{left.flags!r} != {right.flags!r}" 

1195 

1196 if check_index: 

1197 # GH #38183 

1198 assert_index_equal( 

1199 left.index, 

1200 right.index, 

1201 exact=check_index_type, 

1202 check_names=check_names, 

1203 check_exact=check_exact_index, 

1204 check_categorical=check_categorical, 

1205 check_order=not check_like, 

1206 check_freq=_resolve_check_freq(left.index, check_freq), 

1207 rtol=rtol, 

1208 atol=atol, 

1209 obj=f"{obj}.index", 

1210 ) 

1211 

1212 if check_like: 

1213 left = left.reindex_like(right) 

1214 

1215 if check_dtype: 

1216 # We want to skip exact dtype checking when `check_categorical` 

1217 # is False. We'll still raise if only one is a `Categorical`, 

1218 # regardless of `check_categorical` 

1219 if ( 

1220 isinstance(left.dtype, CategoricalDtype) 

1221 and isinstance(right.dtype, CategoricalDtype) 

1222 and not check_categorical 

1223 ): 

1224 pass 

1225 else: 

1226 assert_attr_equal("dtype", left, right, obj=f"Attributes of {obj}") 

1227 if check_exact: 

1228 left_values = left._values 

1229 right_values = right._values 

1230 # Only check exact if dtype is numeric 

1231 if isinstance(left_values, ExtensionArray) and isinstance( 

1232 right_values, ExtensionArray 

1233 ): 

1234 assert_extension_array_equal( 

1235 left_values, 

1236 right_values, 

1237 check_dtype=check_dtype, 

1238 index_values=left.index, 

1239 obj=str(obj), 

1240 ) 

1241 else: 

1242 # convert both to NumPy if not, check_dtype would raise earlier 

1243 lv, rv = left_values, right_values 

1244 if isinstance(left_values, ExtensionArray): 

1245 lv = left_values.to_numpy() 

1246 if isinstance(right_values, ExtensionArray): 

1247 rv = right_values.to_numpy() 

1248 assert_numpy_array_equal( 

1249 lv, 

1250 rv, 

1251 check_dtype=check_dtype, 

1252 obj=str(obj), 

1253 class_obj=f"{obj} values", 

1254 index_values=left.index, 

1255 ) 

1256 elif check_datetimelike_compat and ( 

1257 needs_i8_conversion(left.dtype) or needs_i8_conversion(right.dtype) 

1258 ): 

1259 # we want to check only if we have compat dtypes 

1260 # e.g. integer and M|m are NOT compat, but we can simply check 

1261 # the values in that case 

1262 

1263 # datetimelike may have different objects (e.g. datetime.datetime 

1264 # vs Timestamp) but will compare equal 

1265 if not Index(left._values).equals(Index(right._values)): 

1266 msg = ( 

1267 f"[datetimelike_compat=True] {left._values} " 

1268 f"is not equal to {right._values}." 

1269 ) 

1270 raise AssertionError(msg) 

1271 elif isinstance(left.dtype, IntervalDtype) and isinstance( 

1272 right.dtype, IntervalDtype 

1273 ): 

1274 assert_interval_array_equal( 

1275 cast("IntervalArray", left.array), cast("IntervalArray", right.array) 

1276 ) 

1277 elif isinstance(left.dtype, CategoricalDtype) or isinstance( 

1278 right.dtype, CategoricalDtype 

1279 ): 

1280 _testing.assert_almost_equal( 

1281 left._values, 

1282 right._values, 

1283 rtol=rtol, 

1284 atol=atol, 

1285 check_dtype=bool(check_dtype), 

1286 obj=str(obj), 

1287 index_values=left.index, 

1288 ) 

1289 elif isinstance(left.dtype, ExtensionDtype) and isinstance( 

1290 right.dtype, ExtensionDtype 

1291 ): 

1292 assert_extension_array_equal( 

1293 left._values, 

1294 right._values, 

1295 rtol=rtol, 

1296 atol=atol, 

1297 check_dtype=check_dtype, 

1298 index_values=left.index, 

1299 obj=str(obj), 

1300 ) 

1301 elif is_extension_array_dtype_and_needs_i8_conversion( 

1302 left.dtype, right.dtype 

1303 ) or is_extension_array_dtype_and_needs_i8_conversion(right.dtype, left.dtype): 

1304 assert_extension_array_equal( 

1305 left._values, 

1306 right._values, 

1307 check_dtype=check_dtype, 

1308 index_values=left.index, 

1309 obj=str(obj), 

1310 ) 

1311 elif needs_i8_conversion(left.dtype) and needs_i8_conversion(right.dtype): 

1312 # DatetimeArray or TimedeltaArray 

1313 assert_extension_array_equal( 

1314 left._values, 

1315 right._values, 

1316 check_dtype=check_dtype, 

1317 index_values=left.index, 

1318 obj=str(obj), 

1319 ) 

1320 else: 

1321 _testing.assert_almost_equal( 

1322 left._values, 

1323 right._values, 

1324 rtol=rtol, 

1325 atol=atol, 

1326 check_dtype=bool(check_dtype), 

1327 obj=str(obj), 

1328 index_values=left.index, 

1329 ) 

1330 

1331 # metadata comparison 

1332 if check_names: 

1333 assert_attr_equal("name", left, right, obj=obj) 

1334 

1335 if check_categorical: 

1336 if isinstance(left.dtype, CategoricalDtype) or isinstance( 

1337 right.dtype, CategoricalDtype 

1338 ): 

1339 assert_categorical_equal( 

1340 left._values, 

1341 right._values, 

1342 obj=f"{obj} category", 

1343 check_category_order=check_category_order, 

1344 check_freq=check_freq, 

1345 ) 

1346 

1347 

1348# This could be refactored to use the NDFrame.equals method 

1349@set_module("pandas.testing") 

1350@deprecate_kwarg(Pandas4Warning, "check_datetimelike_compat", new_arg_name=None) 

1351# stacklevel=3 to account for the extra frame from the stacked decorator above 

1352@deprecate_kwarg(Pandas4Warning, "by_blocks", new_arg_name=None, stacklevel=3) 

1353def assert_frame_equal( 

1354 left: DataFrame, 

1355 right: DataFrame, 

1356 check_dtype: bool | Literal["equiv"] = True, 

1357 check_index_type: bool | Literal["equiv"] = "equiv", 

1358 check_column_type: bool | Literal["equiv"] = "equiv", 

1359 check_frame_type: bool = True, 

1360 check_names: bool = True, 

1361 by_blocks: bool = False, 

1362 check_exact: bool | lib.NoDefault = lib.no_default, 

1363 check_datetimelike_compat: bool = False, 

1364 check_categorical: bool = True, 

1365 check_like: bool = False, 

1366 check_freq: bool | lib.NoDefault = lib.no_default, 

1367 check_flags: bool = True, 

1368 rtol: float | lib.NoDefault = lib.no_default, 

1369 atol: float | lib.NoDefault = lib.no_default, 

1370 obj: str = "DataFrame", 

1371) -> None: 

1372 """ 

1373 Check that left and right DataFrame are equal. 

1374 

1375 This function is intended to compare two DataFrames and output any 

1376 differences. It is mostly intended for use in unit tests. 

1377 Additional parameters allow varying the strictness of the 

1378 equality checks performed. 

1379 

1380 Parameters 

1381 ---------- 

1382 left : DataFrame 

1383 First DataFrame to compare. 

1384 right : DataFrame 

1385 Second DataFrame to compare. 

1386 check_dtype : bool, default True 

1387 Whether to check the DataFrame dtype is identical. 

1388 check_index_type : bool or {'equiv'}, default 'equiv' 

1389 Whether to check the Index class, dtype and inferred_type 

1390 are identical. 

1391 check_column_type : bool or {'equiv'}, default 'equiv' 

1392 Whether to check the columns class, dtype and inferred_type 

1393 are identical. Is passed as the ``exact`` argument of 

1394 :func:`assert_index_equal`. 

1395 check_frame_type : bool, default True 

1396 Whether to check the DataFrame class is identical. 

1397 check_names : bool, default True 

1398 Whether to check that the `names` attribute for both the `index` 

1399 and `column` attributes of the DataFrame is identical. 

1400 by_blocks : bool, default False 

1401 Specify how to compare internal data. If False, compare by columns. 

1402 If True, compare by blocks. 

1403 

1404 .. deprecated:: 3.1 

1405 check_exact : bool, default False 

1406 Whether to compare number exactly. If False, the comparison uses the 

1407 relative tolerance (``rtol``) and absolute tolerance (``atol``) 

1408 parameters to determine if two values are considered close, 

1409 according to the formula: ``|a - b| <= (atol + rtol * |b|)``. 

1410 

1411 .. versionchanged:: 2.2.0 

1412 

1413 Defaults to True for integer dtypes if none of 

1414 ``check_exact``, ``rtol`` and ``atol`` are specified. 

1415 

1416 .. versionchanged:: 3.0.0 

1417 

1418 When ``check_exact=True``, the comparison of object-dtype values 

1419 containing nested :class:`numpy.ndarray` objects takes the type of 

1420 the nested object into account. In particular, a nested 

1421 ``numpy.ndarray`` is not considered equivalent to a Python 

1422 ``list``, Python ``tuple``, or a pandas 

1423 :class:`~pandas.api.extensions.ExtensionArray` merely because the 

1424 contained values are the same. 

1425 

1426 check_datetimelike_compat : bool, default False 

1427 Compare datetime-like which is comparable ignoring dtype. 

1428 

1429 .. deprecated:: 3.0 

1430 

1431 check_categorical : bool, default True 

1432 Whether to compare internal Categorical exactly. 

1433 check_like : bool, default False 

1434 If True, ignore the order of index & columns. 

1435 Note: index labels must match their respective rows 

1436 (same as in columns) - same labels must be with the same data. 

1437 check_freq : bool, default True 

1438 Whether to check the `freq` attribute on a DatetimeIndex or TimedeltaIndex 

1439 index or columns. The index and columns checks are skipped if 

1440 ``check_like=True``. 

1441 

1442 .. deprecated:: 3.1.0 

1443 The ``freq`` attribute of :class:`DatetimeIndex`/:class:`TimedeltaIndex` 

1444 columns, MultiIndex levels, and Categorical categories is not yet 

1445 checked by default; a mismatch currently only warns and will raise in 

1446 a future version. Pass ``check_freq`` explicitly to silence the 

1447 warning. 

1448 check_flags : bool, default True 

1449 Whether to check the `flags` attribute. 

1450 rtol : float, default 1e-5 

1451 Relative tolerance. Only used when check_exact is False, and only 

1452 applied to numeric dtypes; values of other dtypes, such as interval, 

1453 are always compared exactly. 

1454 atol : float, default 1e-8 

1455 Absolute tolerance. Only used when check_exact is False, and only 

1456 applied to numeric dtypes; values of other dtypes, such as interval, 

1457 are always compared exactly. 

1458 obj : str, default 'DataFrame' 

1459 Specify object name being compared, internally used to show appropriate 

1460 assertion message. 

1461 

1462 See Also 

1463 -------- 

1464 assert_series_equal : Equivalent method for asserting Series equality. 

1465 DataFrame.equals : Check DataFrame equality. 

1466 

1467 Examples 

1468 -------- 

1469 This example shows comparing two DataFrames that are equal 

1470 but with columns of differing dtypes. 

1471 

1472 >>> from pandas.testing import assert_frame_equal 

1473 >>> df1 = pd.DataFrame({"a": [1, 2], "b": [3, 4]}) 

1474 >>> df2 = pd.DataFrame({"a": [1, 2], "b": [3.0, 4.0]}) 

1475 

1476 df1 equals itself. 

1477 

1478 >>> assert_frame_equal(df1, df1) 

1479 

1480 df1 differs from df2 as column 'b' is of a different type. 

1481 

1482 >>> assert_frame_equal(df1, df2) 

1483 Traceback (most recent call last): 

1484 ... 

1485 AssertionError: Attributes of DataFrame.iloc[:, 1] (column name="b") are different 

1486 

1487 Attribute "dtype" are different 

1488 [left]: int64 

1489 [right]: float64 

1490 

1491 Ignore differing dtypes in columns with check_dtype. 

1492 

1493 >>> assert_frame_equal(df1, df2, check_dtype=False) 

1494 """ 

1495 __tracebackhide__ = True 

1496 _rtol = rtol if rtol is not lib.no_default else 1.0e-5 

1497 _atol = atol if atol is not lib.no_default else 1.0e-8 

1498 _check_exact = check_exact if check_exact is not lib.no_default else False 

1499 

1500 # instance validation 

1501 _check_isinstance(left, right, DataFrame) 

1502 

1503 # The flat-index freq has long been checked by default, so preserve that 

1504 # hard check; the columns freq check is new and goes through the deprecation 

1505 # warning in assert_index_equal (passing check_freq unresolved). GH#51920 

1506 _check_freq = _resolve_check_freq(left.index, check_freq) 

1507 

1508 if check_frame_type: 

1509 assert isinstance(left, type(right)) 

1510 # assert_class_equal(left, right, obj=obj) 

1511 

1512 # shape comparison 

1513 if left.shape != right.shape: 

1514 raise_assert_detail( 

1515 obj, f"{obj} shape mismatch", f"{left.shape!r}", f"{right.shape!r}" 

1516 ) 

1517 

1518 if check_flags: 

1519 assert left.flags == right.flags, f"{left.flags!r} != {right.flags!r}" 

1520 

1521 # index comparison 

1522 assert_index_equal( 

1523 left.index, 

1524 right.index, 

1525 exact=check_index_type, 

1526 check_names=check_names, 

1527 check_exact=_check_exact, 

1528 check_categorical=check_categorical, 

1529 check_order=not check_like, 

1530 check_freq=_check_freq, 

1531 rtol=_rtol, 

1532 atol=_atol, 

1533 obj=f"{obj}.index", 

1534 ) 

1535 

1536 # column comparison 

1537 assert_index_equal( 

1538 left.columns, 

1539 right.columns, 

1540 exact=check_column_type, 

1541 check_names=check_names, 

1542 check_exact=_check_exact, 

1543 check_categorical=check_categorical, 

1544 check_order=not check_like, 

1545 check_freq=check_freq, 

1546 rtol=_rtol, 

1547 atol=_atol, 

1548 obj=f"{obj}.columns", 

1549 ) 

1550 

1551 if check_like: 

1552 left = left.reindex_like(right) 

1553 

1554 # compare by blocks 

1555 if by_blocks: 

1556 rblocks = right._to_dict_of_blocks() 

1557 lblocks = left._to_dict_of_blocks() 

1558 for dtype in list(set(list(lblocks.keys()) + list(rblocks.keys()))): 

1559 assert dtype in lblocks 

1560 assert dtype in rblocks 

1561 assert_frame_equal( 

1562 lblocks[dtype], 

1563 rblocks[dtype], 

1564 check_dtype=check_dtype, 

1565 check_freq=check_freq, 

1566 obj=obj, 

1567 ) 

1568 

1569 # compare by columns 

1570 else: 

1571 for i, col in enumerate(left.columns): 

1572 # We have already checked that columns match, so we can do 

1573 # fast location-based lookups 

1574 lcol = left._ixs(i, axis=1) 

1575 rcol = right._ixs(i, axis=1) 

1576 

1577 # GH #38183 

1578 # use check_index=False, because we do not want to run 

1579 # assert_index_equal for each column, 

1580 # as we already checked it for the whole dataframe before. 

1581 with warnings.catch_warnings(): 

1582 warnings.filterwarnings( 

1583 "ignore", 

1584 message="the 'check_datetimelike_compat' keyword", 

1585 category=Pandas4Warning, 

1586 ) 

1587 assert_series_equal( 

1588 lcol, 

1589 rcol, 

1590 check_dtype=check_dtype, 

1591 check_index_type=check_index_type, 

1592 check_exact=check_exact, 

1593 check_names=check_names, 

1594 check_datetimelike_compat=check_datetimelike_compat, 

1595 check_categorical=check_categorical, 

1596 # check_index=False above, so this governs only the 

1597 # categorical categories, whose freq goes through the 

1598 # deprecation rather than the index's hard check 

1599 check_freq=check_freq, 

1600 obj=f'{obj}.iloc[:, {i}] (column name="{col}")', 

1601 rtol=rtol, 

1602 atol=atol, 

1603 check_index=False, 

1604 check_flags=False, 

1605 ) 

1606 

1607 

1608def assert_equal(left: Any, right: Any, **kwargs: Any) -> None: 

1609 """ 

1610 Wrapper for tm.assert_*_equal to dispatch to the appropriate test function. 

1611 

1612 Parameters 

1613 ---------- 

1614 left, right : Index, Series, DataFrame, ExtensionArray, or np.ndarray 

1615 The two items to be compared. 

1616 **kwargs 

1617 All keyword arguments are passed through to the underlying assert method. 

1618 """ 

1619 __tracebackhide__ = True 

1620 

1621 if isinstance(left, Index): 

1622 # retain the long-standing hard freq check for datetimelike Index; 

1623 # the check_freq deprecation in assert_index_equal only warns by 

1624 # default. GH#51920 

1625 if isinstance(left, (DatetimeIndex, TimedeltaIndex)): 

1626 kwargs.setdefault("check_freq", True) 

1627 assert_index_equal(left, right, **kwargs) 

1628 elif isinstance(left, Series): 

1629 assert_series_equal(left, right, **kwargs) 

1630 elif isinstance(left, DataFrame): 

1631 assert_frame_equal(left, right, **kwargs) 

1632 elif isinstance(left, IntervalArray): 

1633 assert_interval_array_equal(left, right, **kwargs) 

1634 elif isinstance(left, PeriodArray): 

1635 assert_period_array_equal(left, right, **kwargs) 

1636 elif isinstance(left, DatetimeArray): 

1637 assert_datetime_array_equal(left, right, **kwargs) 

1638 elif isinstance(left, TimedeltaArray): 

1639 assert_timedelta_array_equal(left, right, **kwargs) 

1640 elif isinstance(left, ExtensionArray): 

1641 assert_extension_array_equal(left, right, **kwargs) 

1642 elif isinstance(left, np.ndarray): 

1643 assert_numpy_array_equal(left, right, **kwargs) 

1644 elif isinstance(left, str): 

1645 assert kwargs == {} 

1646 assert left == right 

1647 else: 

1648 assert kwargs == {} 

1649 assert_almost_equal(left, right) 

1650 

1651 

1652def assert_sp_array_equal(left: Any, right: Any) -> None: 

1653 """ 

1654 Check that the left and right SparseArray are equal. 

1655 

1656 Parameters 

1657 ---------- 

1658 left : SparseArray 

1659 right : SparseArray 

1660 """ 

1661 _check_isinstance(left, right, pd.arrays.SparseArray) 

1662 

1663 assert_numpy_array_equal(left.sp_values, right.sp_values) 

1664 

1665 # SparseIndex comparison 

1666 assert isinstance(left.sp_index, SparseIndex) 

1667 assert isinstance(right.sp_index, SparseIndex) 

1668 

1669 left_index = left.sp_index 

1670 right_index = right.sp_index 

1671 

1672 if not left_index.equals(right_index): 

1673 raise_assert_detail( 

1674 "SparseArray.index", "index are not equal", left_index, right_index 

1675 ) 

1676 else: 

1677 # Just ensure a 

1678 pass 

1679 

1680 assert_attr_equal("fill_value", left, right) 

1681 assert_attr_equal("dtype", left, right) 

1682 assert_numpy_array_equal(left.to_dense(), right.to_dense()) 

1683 

1684 

1685def assert_contains_all(iterable: Iterable[Any], dic: Container[Any]) -> None: 

1686 for k in iterable: 

1687 assert k in dic, f"Did not contain item: {k!r}" 

1688 

1689 

1690def assert_copy(iter1: Iterable[Any], iter2: Iterable[Any], **eql_kwargs: Any) -> None: 

1691 """ 

1692 iter1, iter2: iterables that produce elements 

1693 comparable with assert_almost_equal 

1694 

1695 Checks that the elements are equal, but not 

1696 the same object. (Does not check that items 

1697 in sequences are also not the same object) 

1698 """ 

1699 for elem1, elem2 in zip(iter1, iter2, strict=True): 

1700 assert_almost_equal(elem1, elem2, **eql_kwargs) 

1701 msg = ( 

1702 f"Expected object {type(elem1)!r} and object {type(elem2)!r} to be " 

1703 "different objects, but they were the same object." 

1704 ) 

1705 assert elem1 is not elem2, msg 

1706 

1707 

1708def is_extension_array_dtype_and_needs_i8_conversion( 

1709 left_dtype: DtypeObj, right_dtype: DtypeObj 

1710) -> bool: 

1711 """ 

1712 Checks that we have the combination of an ExtensionArraydtype and 

1713 a dtype that should be converted to int64 

1714 

1715 Returns 

1716 ------- 

1717 bool 

1718 

1719 Related to issue #37609 

1720 """ 

1721 return isinstance(left_dtype, ExtensionDtype) and needs_i8_conversion(right_dtype) 

1722 

1723 

1724def assert_indexing_slices_equivalent(ser: Series, l_slc: slice, i_slc: slice) -> None: 

1725 """ 

1726 Check that ser.iloc[i_slc] matches ser.loc[l_slc] and, if applicable, 

1727 ser[l_slc]. 

1728 """ 

1729 expected = ser.iloc[i_slc] 

1730 

1731 assert_series_equal(ser.loc[l_slc], expected) 

1732 

1733 if not is_integer_dtype(ser.index): 

1734 # For integer indices, .loc and plain getitem are position-based. 

1735 assert_series_equal(ser[l_slc], expected) 

1736 

1737 

1738def assert_metadata_equivalent( 

1739 left: DataFrame | Series, right: DataFrame | Series | None = None 

1740) -> None: 

1741 """ 

1742 Check that ._metadata attributes are equivalent. 

1743 """ 

1744 for attr in left._metadata: 

1745 val = getattr(left, attr, None) 

1746 if right is None: 

1747 assert val is None 

1748 else: 

1749 assert val == getattr(right, attr, None)