def test_pow_float(self, op, idx, box): # test power calculations both ways, GH#14973 expected = pd.Float64Index(op(idx.values, 2.0)) idx = tm.box_expected(idx, box) expected = tm.box_expected(expected, box) result = op(idx, 2.0) tm.assert_equal(result, expected)
def test_modulo(self, idx, box): # GH#9244 expected = Index(idx.values % 2) idx = tm.box_expected(idx, box) expected = tm.box_expected(expected, box) result = idx % 2 tm.assert_equal(result, expected)
def test_objarr_add_str(self, box): ser = pd.Series(['x', np.nan, 'x']) expected = pd.Series(['xa', np.nan, 'xa']) ser = tm.box_expected(ser, box) expected = tm.box_expected(expected, box) result = ser + 'a' tm.assert_equal(result, expected)
def test_numeric_arr_rdiv_tdscalar(self, scalar_td, index, box): expected = TimedeltaIndex(['1 Day', '12 Hours']) index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = scalar_td / index tm.assert_equal(result, expected) with pytest.raises(TypeError): index / scalar_td
def test_numarr_with_dtype_add_nan(self, dtype, box): ser = pd.Series([1, 2, 3], dtype=dtype) expected = pd.Series([np.nan, np.nan, np.nan], dtype=dtype) ser = tm.box_expected(ser, box) expected = tm.box_expected(expected, box) result = np.nan + ser tm.assert_equal(result, expected) result = ser + np.nan tm.assert_equal(result, expected)
def test_numeric_arr_mul_tdscalar(self, scalar_td, index, box): # GH#19333 expected = pd.timedelta_range('1 days', '10 days') index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = index * scalar_td tm.assert_equal(result, expected) commute = scalar_td * index tm.assert_equal(commute, expected)
def test_numarr_with_dtype_add_int(self, dtype, box): ser = pd.Series([1, 2, 3], dtype=dtype) expected = pd.Series([2, 3, 4], dtype=dtype) ser = tm.box_expected(ser, box) expected = tm.box_expected(expected, box) result = 1 + ser tm.assert_equal(result, expected) result = ser + 1 tm.assert_equal(result, expected)
def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box): index = numeric_idx[1:3] expected = TimedeltaIndex(['3 Days', '36 Hours']) index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = three_days / index tm.assert_equal(result, expected) with pytest.raises(TypeError): index / three_days
def test_add_extension_scalar(self, other, box, op): # GH#22378 # Check that scalars satisfying is_extension_array_dtype(obj) # do not incorrectly try to dispatch to an ExtensionArray operation arr = pd.Series(['a', 'b', 'c']) expected = pd.Series([op(x, other) for x in arr]) arr = tm.box_expected(arr, box) expected = tm.box_expected(expected, box) result = op(arr, other) tm.assert_equal(result, expected)
def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box): # GH#19333 index = numeric_idx expected = pd.timedelta_range('0 days', '4 days') index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = index * scalar_td tm.assert_equal(result, expected) commute = scalar_td * index tm.assert_equal(commute, expected)
def test_td64arr_rmul_numeric_array(self, box, vector, dtype, tdser): # GH#4521 # divide/multiply by integers vector = vector.astype(dtype) expected = Series(['1180 Days', '1770 Days', 'NaT'], dtype='timedelta64[ns]') tdser = tm.box_expected(tdser, box) box = Series if (box is pd.Index and type(vector) is Series) else box expected = tm.box_expected(expected, box) result = vector * tdser tm.assert_equal(result, expected)
def test_td64arr_rfloordiv_tdscalar_explicit(self, box, scalar_td): # GH#18831 td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan expected = Series([1, 1, np.nan]) td1 = tm.box_expected(td1, box) expected = tm.box_expected(expected, box) # We can test __rfloordiv__ using this syntax, # see `test_timedelta_rfloordiv` result = td1.__rfloordiv__(scalar_td) tm.assert_equal(result, expected)
def test_divide_decimal(self, box): # resolves issue GH#9787 ser = Series([Decimal(10)]) expected = Series([Decimal(5)]) ser = tm.box_expected(ser, box) expected = tm.box_expected(expected, box) result = ser / Decimal(2) tm.assert_equal(result, expected) result = ser // Decimal(2) tm.assert_equal(result, expected)
def test_pi_add_offset_n_gt1_not_divisible(self, box_with_period): # GH#23215 # PeriodIndex with freq.n > 1 add offset with offset.n % freq.n != 0 pi = pd.PeriodIndex(['2016-01'], freq='2M') pi = tm.box_expected(pi, box_with_period) expected = pd.PeriodIndex(['2016-04'], freq='2M') expected = tm.box_expected(expected, box_with_period) result = pi + to_offset('3M') tm.assert_equal(result, expected) result = to_offset('3M') + pi tm.assert_equal(result, expected)
def test_pi_add_offset_n_gt1_not_divisible(self, box_with_array): # GH#23215 # PeriodIndex with freq.n > 1 add offset with offset.n % freq.n != 0 pi = pd.PeriodIndex(['2016-01'], freq='2M') expected = pd.PeriodIndex(['2016-04'], freq='2M') # FIXME: with transposing these tests fail pi = tm.box_expected(pi, box_with_array, transpose=False) expected = tm.box_expected(expected, box_with_array, transpose=False) result = pi + to_offset('3M') tm.assert_equal(result, expected) result = to_offset('3M') + pi tm.assert_equal(result, expected)
def test_parr_add_sub_tdt64_nat_array(self, box_with_array, other): pi = pd.period_range("1994-04-01", periods=9, freq="19D") expected = pd.PeriodIndex(["NaT"] * 9, freq="19D") obj = tm.box_expected(pi, box_with_array) expected = tm.box_expected(expected, box_with_array) result = obj + other tm.assert_equal(result, expected) result = other + obj tm.assert_equal(result, expected) result = obj - other tm.assert_equal(result, expected) with pytest.raises(TypeError): other - obj
def test_pi_add_offset_n_gt1(self, box): # GH#23215 # add offset to PeriodIndex with freq.n > 1 per = pd.Period('2016-01', freq='2M') pi = pd.PeriodIndex([per]) expected = pd.PeriodIndex(['2016-03'], freq='2M') pi = tm.box_expected(pi, box) expected = tm.box_expected(expected, box) result = pi + per.freq tm.assert_equal(result, expected) result = per.freq + pi tm.assert_equal(result, expected)
def test_pi_add_offset_n_gt1_not_divisible(self, box): # GH#23215 # PeriodIndex with freq.n > 1 add offset with offset.n % freq.n != 0 pi = pd.PeriodIndex(['2016-01'], freq='2M') pi = tm.box_expected(pi, box) expected = pd.PeriodIndex(['2016-04'], freq='2M') expected = tm.box_expected(expected, box) result = pi + to_offset('3M') tm.assert_equal(result, expected) result = to_offset('3M') + pi tm.assert_equal(result, expected)
def test_td64arr_add_intlike(self, box): # GH#19123 tdi = TimedeltaIndex(['59 days', '59 days', 'NaT']) ser = tm.box_expected(tdi, box) err = TypeError if box is not pd.Index else NullFrequencyError other = Series([20, 30, 40], dtype='uint8') # TODO: separate/parametrize with pytest.raises(err): ser + 1 with pytest.raises(err): ser - 1 with pytest.raises(err): ser + other with pytest.raises(err): ser - other with pytest.raises(err): ser + np.array(other) with pytest.raises(err): ser - np.array(other) with pytest.raises(err): ser + pd.Index(other) with pytest.raises(err): ser - pd.Index(other)
def test_td64arr_div_numeric_array(self, box, vector, dtype, tdser): # GH#4521 # divide/multiply by integers vector = vector.astype(dtype) expected = Series(['2.95D', '1D 23H 12m', 'NaT'], dtype='timedelta64[ns]') tdser = tm.box_expected(tdser, box) box = Series if (box is pd.Index and type(vector) is Series) else box expected = tm.box_expected(expected, box) result = tdser / vector tm.assert_equal(result, expected) with pytest.raises(TypeError): vector / tdser
def test_td64arr_sub_timestamp_raises(self, box): idx = TimedeltaIndex(['1 day', '2 day']) idx = tm.box_expected(idx, box) msg = "cannot subtract a datelike from|Could not operate" with tm.assert_raises_regex(TypeError, msg): idx - Timestamp('2011-01-01')
def test_parr_ops_errors(self, ng, box_with_array): idx = PeriodIndex(['2011-01', '2011-02', '2011-03', '2011-04'], freq='M', name='idx') obj = tm.box_expected(idx, box_with_array) msg = r"unsupported operand type\(s\)" with pytest.raises(TypeError, match=msg): obj + ng with pytest.raises(TypeError): # error message differs between PY2 and 3 ng + obj with pytest.raises(TypeError, match=msg): obj - ng with pytest.raises(TypeError): np.add(obj, ng) with pytest.raises(TypeError): np.add(ng, obj) with pytest.raises(TypeError): np.subtract(obj, ng) with pytest.raises(TypeError): np.subtract(ng, obj)
def test_parr_cmp_pi_mismatched_freq_raises(self, freq, box_with_array): # GH#13200 # different base freq base = PeriodIndex(['2011-01', '2011-02', '2011-03', '2011-04'], freq=freq) base = tm.box_expected(base, box_with_array) msg = "Input has different freq=A-DEC from " with pytest.raises(IncompatibleFrequency, match=msg): base <= Period('2011', freq='A') with pytest.raises(IncompatibleFrequency, match=msg): Period('2011', freq='A') >= base # TODO: Could parametrize over boxes for idx? idx = PeriodIndex(['2011', '2012', '2013', '2014'], freq='A') with pytest.raises(IncompatibleFrequency, match=msg): base <= idx # Different frequency msg = "Input has different freq=4M from " with pytest.raises(IncompatibleFrequency, match=msg): base <= Period('2011', freq='4M') with pytest.raises(IncompatibleFrequency, match=msg): Period('2011', freq='4M') >= base idx = PeriodIndex(['2011', '2012', '2013', '2014'], freq='4M') with pytest.raises(IncompatibleFrequency, match=msg): base <= idx
def test_parr_cmp_pi_mismatched_freq_raises(self, freq, box_with_array): # GH#13200 # different base freq base = PeriodIndex(["2011-01", "2011-02", "2011-03", "2011-04"], freq=freq) base = tm.box_expected(base, box_with_array) msg = "Input has different freq=A-DEC from " with pytest.raises(IncompatibleFrequency, match=msg): base <= Period("2011", freq="A") with pytest.raises(IncompatibleFrequency, match=msg): Period("2011", freq="A") >= base # TODO: Could parametrize over boxes for idx? idx = PeriodIndex(["2011", "2012", "2013", "2014"], freq="A") rev_msg = ( r"Input has different freq=(M|2M|3M) from " r"PeriodArray\(freq=A-DEC\)" ) idx_msg = rev_msg if box_with_array is tm.to_array else msg with pytest.raises(IncompatibleFrequency, match=idx_msg): base <= idx # Different frequency msg = "Input has different freq=4M from " with pytest.raises(IncompatibleFrequency, match=msg): base <= Period("2011", freq="4M") with pytest.raises(IncompatibleFrequency, match=msg): Period("2011", freq="4M") >= base idx = PeriodIndex(["2011", "2012", "2013", "2014"], freq="4M") rev_msg = r"Input has different freq=(M|2M|3M) from " r"PeriodArray\(freq=4M\)" idx_msg = rev_msg if box_with_array is tm.to_array else msg with pytest.raises(IncompatibleFrequency, match=idx_msg): base <= idx
def test_parr_add_sub_td64_nat(self, box): # GH#23320 special handling for timedelta64("NaT") pi = pd.period_range("1994-04-01", periods=9, freq="19D") other = np.timedelta64("NaT") expected = pd.PeriodIndex(["NaT"] * 9, freq="19D") obj = tm.box_expected(pi, box) expected = tm.box_expected(expected, box) result = obj + other tm.assert_equal(result, expected) result = other + obj tm.assert_equal(result, expected) result = obj - other tm.assert_equal(result, expected) with pytest.raises(TypeError): other - obj
def test_parr_sub_pi_mismatched_freq(self, box_with_array): rng = pd.period_range('1/1/2000', freq='D', periods=5) other = pd.period_range('1/6/2000', freq='H', periods=5) # TODO: parametrize over boxes for other? rng = tm.box_expected(rng, box_with_array) with pytest.raises(IncompatibleFrequency): rng - other
def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box): if box is not pd.Index and isinstance(three_days, pd.offsets.Tick): raise pytest.xfail("Tick division not implemented") index = numeric_idx[1:3] expected = TimedeltaIndex(['3 Days', '36 Hours']) index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = three_days / index tm.assert_equal(result, expected) with pytest.raises(TypeError): index / three_days
def test_numeric_arr_rdiv_tdscalar(self, scalar_td, index, box): if box is Series and type(scalar_td) is timedelta: raise pytest.xfail(reason="TODO: Figure out why this case fails") if box is pd.DataFrame and isinstance(scalar_td, timedelta): raise pytest.xfail(reason="TODO: Figure out why this case fails") expected = TimedeltaIndex(['1 Day', '12 Hours']) index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = scalar_td / index tm.assert_equal(result, expected) with pytest.raises(TypeError): index / scalar_td
def test_pi_add_offset_n_gt1(self, box_with_array, transpose): # GH#23215 # add offset to PeriodIndex with freq.n > 1 per = pd.Period("2016-01", freq="2M") pi = pd.PeriodIndex([per]) expected = pd.PeriodIndex(["2016-03"], freq="2M") pi = tm.box_expected(pi, box_with_array, transpose=transpose) expected = tm.box_expected(expected, box_with_array, transpose=transpose) result = pi + per.freq tm.assert_equal(result, expected) result = per.freq + pi tm.assert_equal(result, expected)
def test_numeric_arr_mul_tdscalar(self, scalar_td, index, box): # GH#19333 if (box in [Series, pd.DataFrame] and type(scalar_td) is timedelta and index.dtype == 'f8'): raise pytest.xfail(reason="Cannot multiply timedelta by float") expected = pd.timedelta_range('1 days', '10 days') index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = index * scalar_td tm.assert_equal(result, expected) commute = scalar_td * index tm.assert_equal(commute, expected)
def test_parr_cmp_pi(self, freq, box_with_array): # GH#13200 xbox = np.ndarray if box_with_array is pd.Index else box_with_array base = PeriodIndex(['2011-01', '2011-02', '2011-03', '2011-04'], freq=freq) base = tm.box_expected(base, box_with_array) # TODO: could also box idx? idx = PeriodIndex(['2011-02', '2011-01', '2011-03', '2011-05'], freq=freq) exp = np.array([False, False, True, False]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base == idx, exp) exp = np.array([True, True, False, True]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base != idx, exp) exp = np.array([False, True, False, False]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base > idx, exp) exp = np.array([True, False, False, True]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base < idx, exp) exp = np.array([False, True, True, False]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base >= idx, exp) exp = np.array([True, False, True, True]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base <= idx, exp)
def test_td64arr_add_str_invalid(self, box): # GH#13624 tdi = TimedeltaIndex(['1 day', '2 days']) tdi = tm.box_expected(tdi, box) with pytest.raises(TypeError): tdi + 'a' with pytest.raises(TypeError): 'a' + tdi
def test_parr_cmp_period_scalar2(self, box_with_array): xbox = box_with_array if box_with_array is not pd.Index else np.ndarray pi = pd.period_range('2000-01-01', periods=10, freq='D') val = Period('2000-01-04', freq='D') expected = [x > val for x in pi] ser = tm.box_expected(pi, box_with_array) expected = tm.box_expected(expected, xbox) result = ser > val tm.assert_equal(result, expected) val = pi[5] result = ser > val expected = [x > val for x in pi] expected = tm.box_expected(expected, xbox) tm.assert_equal(result, expected)
def test_parr_ops_errors(self, ng, func, box_with_array): idx = PeriodIndex(["2011-01", "2011-02", "2011-03", "2011-04"], freq="M", name="idx") obj = tm.box_expected(idx, box_with_array) msg = (r"unsupported operand type\(s\)|can only concatenate|" r"must be str|object to str implicitly") with pytest.raises(TypeError, match=msg): func(obj, ng)
def test_pi_add_sub_float(self, op, other, box): if box is pd.DataFrame and isinstance(other, np.ndarray): pytest.xfail(reason="Tries to broadcast incorrectly") dti = pd.DatetimeIndex(['2011-01-01', '2011-01-02'], freq='D') pi = dti.to_period('D') pi = tm.box_expected(pi, box) with pytest.raises(TypeError): op(pi, other)
def test_add_sub_timedeltalike_invalid(self, numeric_idx, other, box): left = tm.box_expected(numeric_idx, box) with pytest.raises(TypeError): left + other with pytest.raises(TypeError): other + left with pytest.raises(TypeError): left - other with pytest.raises(TypeError): other - left
def test_td64arr_add_sub_float(self, box, op, other): tdi = TimedeltaIndex(['-1 days', '-1 days']) tdi = tm.box_expected(tdi, box) if box is pd.DataFrame and op in [operator.add, operator.sub]: pytest.xfail(reason="Tries to align incorrectly, " "raises ValueError") with pytest.raises(TypeError): op(tdi, other)
def test_td64arr_sub_pi(self, box, tdi_freq, pi_freq): # GH#20049 subtracting PeriodIndex should raise TypeError tdi = TimedeltaIndex(['1 hours', '2 hours'], freq=tdi_freq) dti = Timestamp('2018-03-07 17:16:40') + tdi pi = dti.to_period(pi_freq) # TODO: parametrize over box for pi? tdi = tm.box_expected(tdi, box) with pytest.raises(TypeError): tdi - pi
def test_parr_add_sub_tdt64_nat_array(self, box_df_fail, other): # FIXME: DataFrame fails because when when operating column-wise # timedelta64 entries become NaT and are treated like datetimes box = box_df_fail pi = pd.period_range("1994-04-01", periods=9, freq="19D") expected = pd.PeriodIndex(["NaT"] * 9, freq="19D") obj = tm.box_expected(pi, box) expected = tm.box_expected(expected, box) result = obj + other tm.assert_equal(result, expected) result = other + obj tm.assert_equal(result, expected) result = obj - other tm.assert_equal(result, expected) with pytest.raises(TypeError): other - obj
def test_td64arr_add_sub_tdi(self, box, names): # GH#17250 make sure result dtype is correct # GH#19043 make sure names are propagated correctly tdi = TimedeltaIndex(['0 days', '1 day'], name=names[0]) ser = Series([Timedelta(hours=3), Timedelta(hours=4)], name=names[1]) expected = Series([Timedelta(hours=3), Timedelta(days=1, hours=4)], name=names[2]) ser = tm.box_expected(ser, box) expected = tm.box_expected(expected, box) result = tdi + ser tm.assert_equal(result, expected) if box is not pd.DataFrame: assert result.dtype == 'timedelta64[ns]' else: assert result.dtypes[0] == 'timedelta64[ns]' result = ser + tdi tm.assert_equal(result, expected) if box is not pd.DataFrame: assert result.dtype == 'timedelta64[ns]' else: assert result.dtypes[0] == 'timedelta64[ns]' expected = Series([Timedelta(hours=-3), Timedelta(days=1, hours=-4)], name=names[2]) expected = tm.box_expected(expected, box) result = tdi - ser tm.assert_equal(result, expected) if box is not pd.DataFrame: assert result.dtype == 'timedelta64[ns]' else: assert result.dtypes[0] == 'timedelta64[ns]' result = ser - tdi tm.assert_equal(result, -expected) if box is not pd.DataFrame: assert result.dtype == 'timedelta64[ns]' else: assert result.dtypes[0] == 'timedelta64[ns]'
def test_objarr_add_invalid(self, op, box): # invalid ops obj_ser = tm.makeObjectSeries() obj_ser.name = 'objects' obj_ser = tm.box_expected(obj_ser, box) with pytest.raises(Exception): op(obj_ser, 1) with pytest.raises(Exception): op(obj_ser, np.array(1, dtype=np.int64))
def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box): index = numeric_idx[1:3] broken = (isinstance(three_days, np.timedelta64) and three_days.dtype != 'm8[ns]') broken = broken or isinstance(three_days, pd.offsets.Tick) if box is not pd.Index and broken: # np.timedelta64(3, 'D') / 2 == np.timedelta64(1, 'D') raise pytest.xfail("timedelta64 not converted to nanos; " "Tick division not implemented") expected = TimedeltaIndex(['3 Days', '36 Hours']) index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) result = three_days / index tm.assert_equal(result, expected) with pytest.raises(TypeError): index / three_days
def test_parr_add_sub_datetime_scalar(self, other, box_with_array): # GH#23215 rng = pd.period_range('1/1/2000', freq='D', periods=3) rng = tm.box_expected(rng, box_with_array) with pytest.raises(TypeError): rng + other with pytest.raises(TypeError): other + rng with pytest.raises(TypeError): rng - other with pytest.raises(TypeError): other - rng
def test_objarr_add_invalid(self, op, box): # invalid ops if box is pd.DataFrame and op is ops.radd: pytest.xfail(reason="DataFrame op incorrectly casts the np.array" "case to M8[ns]") obj_ser = tm.makeObjectSeries() obj_ser.name = 'objects' obj_ser = tm.box_expected(obj_ser, box) with pytest.raises(Exception): op(obj_ser, 1) with pytest.raises(Exception): op(obj_ser, np.array(1, dtype=np.int64))
def test_parr_add_iadd_parr_raises(self, box_with_array): rng = pd.period_range('1/1/2000', freq='D', periods=5) other = pd.period_range('1/6/2000', freq='D', periods=5) # TODO: parametrize over boxes for other? rng = tm.box_expected(rng, box_with_array) # An earlier implementation of PeriodIndex addition performed # a set operation (union). This has since been changed to # raise a TypeError. See GH#14164 and GH#13077 for historical # reference. with pytest.raises(TypeError): rng + other with pytest.raises(TypeError): rng += other
def test_parr_add_sub_dt64_array_raises(self, box_with_array): rng = pd.period_range('1/1/2000', freq='D', periods=3) dti = pd.date_range('2016-01-01', periods=3) dtarr = dti.values rng = tm.box_expected(rng, box_with_array) with pytest.raises(TypeError): rng + dtarr with pytest.raises(TypeError): dtarr + rng with pytest.raises(TypeError): rng - dtarr with pytest.raises(TypeError): dtarr - rng
def test_parr_cmp_period_scalar(self, freq, box_with_array): # GH#13200 xbox = np.ndarray if box_with_array is pd.Index else box_with_array base = PeriodIndex(['2011-01', '2011-02', '2011-03', '2011-04'], freq=freq) base = tm.box_expected(base, box_with_array) per = Period('2011-02', freq=freq) exp = np.array([False, True, False, False]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base == per, exp) tm.assert_equal(per == base, exp) exp = np.array([True, False, True, True]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base != per, exp) tm.assert_equal(per != base, exp) exp = np.array([False, False, True, True]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base > per, exp) tm.assert_equal(per < base, exp) exp = np.array([True, False, False, False]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base < per, exp) tm.assert_equal(per > base, exp) exp = np.array([False, True, True, True]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base >= per, exp) tm.assert_equal(per <= base, exp) exp = np.array([True, True, False, False]) exp = tm.box_expected(exp, xbox) tm.assert_equal(base <= per, exp) tm.assert_equal(per >= base, exp)