22
22
from pint .errors import DimensionalityError
23
23
24
24
from pint_pandas import PintArray , PintType
25
- from pint_pandas .pint_array import dtypemap
25
+ from pint_pandas .pint_array import dtypemap , pandas_version_info
26
26
27
27
ureg = PintType .ureg
28
28
@@ -328,6 +328,10 @@ def test_apply_simple_series(self, data):
328
328
@pytest .mark .parametrize ("na_action" , [None , "ignore" ])
329
329
def test_map (self , data_missing , na_action ):
330
330
s = pd .Series (data_missing )
331
+ if pandas_version_info < (2 , 1 ) and na_action is not None :
332
+ pytest .skip (
333
+ "Pandas EA map function only accepts None as na_action parameter"
334
+ )
331
335
result = s .map (lambda x : x , na_action = na_action )
332
336
expected = s
333
337
tm .assert_series_equal (result , expected )
@@ -338,10 +342,6 @@ def test_insert_invalid(self):
338
342
339
343
340
344
class TestArithmeticOps (base .BaseArithmeticOpsTests ):
341
- # With Pint 0.21, series and scalar need to have compatible units for
342
- # the arithmetic to work
343
- # series & scalar
344
-
345
345
divmod_exc = None
346
346
series_scalar_exc = None
347
347
frame_scalar_exc = None
@@ -428,31 +428,73 @@ def _get_expected_exception(
428
428
# Fall through...
429
429
return exc
430
430
431
+ # The following methods are needed to work with Pandas < 2.1
432
+ def _check_divmod_op (self , s , op , other , exc = None ):
433
+ # divmod has multiple return values, so check separately
434
+ if exc is None :
435
+ result_div , result_mod = op (s , other )
436
+ if op is divmod :
437
+ expected_div , expected_mod = s // other , s % other
438
+ else :
439
+ expected_div , expected_mod = other // s , other % s
440
+ tm .assert_series_equal (result_div , expected_div )
441
+ tm .assert_series_equal (result_mod , expected_mod )
442
+ else :
443
+ with pytest .raises (exc ):
444
+ divmod (s , other )
445
+
446
+ def _get_exception (self , data , op_name ):
447
+ if data .data .dtype == pd .core .dtypes .dtypes .PandasDtype ("complex128" ):
448
+ if op_name in ["__floordiv__" , "__rfloordiv__" , "__mod__" , "__rmod__" ]:
449
+ return op_name , TypeError
450
+ if op_name in ["__pow__" , "__rpow__" ]:
451
+ return op_name , DimensionalityError
452
+
453
+ return op_name , None
454
+
431
455
def test_arith_series_with_scalar (self , data , all_arithmetic_operators ):
456
+ # With Pint 0.21, series and scalar need to have compatible units for
457
+ # the arithmetic to work
432
458
# series & scalar
433
- op_name = all_arithmetic_operators
434
- ser = pd .Series (data )
435
- self .check_opname (ser , op_name , ser .iloc [0 ])
436
-
437
- def test_arith_frame_with_scalar (self , data , all_arithmetic_operators ):
438
- # frame & scalar
439
- op_name = all_arithmetic_operators
440
- df = pd .DataFrame ({"A" : data })
441
- self .check_opname (df , op_name , data [0 ])
459
+ if pandas_version_info < (2 , 1 ):
460
+ op_name , exc = self ._get_exception (data , all_arithmetic_operators )
461
+ s = pd .Series (data )
462
+ self .check_opname (s , op_name , s .iloc [0 ], exc = exc )
463
+ else :
464
+ op_name = all_arithmetic_operators
465
+ ser = pd .Series (data )
466
+ self .check_opname (ser , op_name , ser .iloc [0 ])
442
467
443
468
def test_arith_series_with_array (self , data , all_arithmetic_operators ):
444
469
# ndarray & other series
445
- op_name = all_arithmetic_operators
446
- ser = pd .Series (data )
447
- self .check_opname (ser , op_name , pd .Series ([ser .iloc [0 ]] * len (ser )))
470
+ if pandas_version_info < (2 , 1 ):
471
+ op_name , exc = self ._get_exception (data , all_arithmetic_operators )
472
+ ser = pd .Series (data )
473
+ self .check_opname (ser , op_name , pd .Series ([ser .iloc [0 ]] * len (ser )), exc )
474
+ else :
475
+ op_name = all_arithmetic_operators
476
+ ser = pd .Series (data )
477
+ self .check_opname (ser , op_name , pd .Series ([ser .iloc [0 ]] * len (ser )))
478
+
479
+ def test_arith_frame_with_scalar (self , data , all_arithmetic_operators ):
480
+ # frame & scalar
481
+ if pandas_version_info < (2 , 1 ):
482
+ op_name , exc = self ._get_exception (data , all_arithmetic_operators )
483
+ df = pd .DataFrame ({"A" : data })
484
+ self .check_opname (df , op_name , data [0 ], exc = exc )
485
+ else :
486
+ op_name = all_arithmetic_operators
487
+ df = pd .DataFrame ({"A" : data })
488
+ self .check_opname (df , op_name , data [0 ])
448
489
449
490
# parameterise this to try divisor not equal to 1 Mm
450
491
@pytest .mark .parametrize ("numeric_dtype" , _base_numeric_dtypes , indirect = True )
451
492
def test_divmod (self , data ):
452
- s = pd .Series (data )
453
- self ._check_divmod_op (s , divmod , 1 * ureg .Mm )
454
- self ._check_divmod_op (1 * ureg .Mm , ops .rdivmod , s )
493
+ ser = pd .Series (data )
494
+ self ._check_divmod_op (ser , divmod , 1 * ureg .Mm )
495
+ self ._check_divmod_op (1 * ureg .Mm , ops .rdivmod , ser )
455
496
497
+ @pytest .mark .parametrize ("numeric_dtype" , _base_numeric_dtypes , indirect = True )
456
498
def test_divmod_series_array (self , data , data_for_twos ):
457
499
ser = pd .Series (data )
458
500
self ._check_divmod_op (ser , divmod , data )
@@ -615,6 +657,12 @@ def test_setitem_2d_values(self, data):
615
657
616
658
617
659
class TestAccumulate (base .BaseAccumulateTests ):
660
+ @pytest .mark .parametrize ("skipna" , [True , False ])
661
+ def test_accumulate_series_raises (self , data , all_numeric_accumulations , skipna ):
662
+ if pandas_version_info < (2 , 1 ):
663
+ # Should this be skip? Historic code simply used pass.
664
+ pass
665
+
618
666
def _supports_accumulation (self , ser : pd .Series , op_name : str ) -> bool :
619
667
return True
620
668
0 commit comments