def test_init( self, input_vals: Union[type, tuple[type, str]], set_time_ref: bool, scl: bool, arr: bool, ): """Test the `__init__` method of the time class. Parameters ---------- input_vals : Either a compatible time type or a tuple of two values. The tuple is needed in case the tested time type can either represent relative time values as well as absolute ones. In this case, the first value is the type. The second value is a string specifying if the type represents absolute ("datetime") or relative ("timedelta") values. set_time_ref : If `True`, a reference time will be passed to the `__init__` method scl : If `True`, the data of the passed type consists of a single value. arr : If `True`, the data of the passed type is an array """ input_type, is_timedelta = self._parse_time_type_test_input(input_vals) # skip matrix cases that do not work -------------------- if arr and input_type in [Timedelta, Timestamp]: return if not arr and input_type in [DTI, TDI]: return # create input values ----------------------------------- delta_val = [1, 2, 3] abs_val = [f"2000-01-01 16:00:0{v}" for v in delta_val] time = _initialize_time_type(input_type, delta_val, abs_val, is_timedelta, arr, scl) time_ref = "2000-01-01 15:00:00" if set_time_ref else None # create `Time` instance -------------------------------- time_class_instance = Time(time, time_ref) # check results ----------------------------------------- exp = self._get_init_exp_values(is_timedelta, time_ref, scl, delta_val, abs_val) assert time_class_instance.is_absolute == exp["is_absolute"] assert time_class_instance.reference_time == exp["time_ref"] assert np.all(time_class_instance.as_timedelta() == exp["timedelta"]) if exp["is_absolute"]: assert np.all(time_class_instance.as_datetime() == exp["datetime"]) else: with pytest.raises(TypeError): time_class_instance.as_datetime()
def test_sub( self, other_type, other_on_rhs: bool, unit: str, time_class_is_array: bool, time_class_is_timedelta: bool, other_is_array: bool, ): """Test the `__sub__` method of the `Time` class. Parameters ---------- other_type : The type of the other object other_on_rhs : If `True`, the other type is on the rhs of the + sign and on the lhs otherwise unit : The time unit to use time_class_is_array : If `True`, the `Time` instance contains 3 time values and 1 otherwise time_class_is_timedelta : If `True`, the `Time` instance represents a time delta and a datetime otherwise other_is_array : If `True`, the other time object contains 3 time values and 1 otherwise """ other_type, other_is_timedelta = self._parse_time_type_test_input( other_type) if other_on_rhs: lhs_is_array = time_class_is_array lhs_is_timedelta = time_class_is_timedelta rhs_is_array = other_is_array rhs_is_timedelta = other_is_timedelta else: lhs_is_array = other_is_array lhs_is_timedelta = other_is_timedelta rhs_is_array = time_class_is_array rhs_is_timedelta = time_class_is_timedelta # skip array cases where the type does not support arrays or scalars if other_type in [Timedelta, Timestamp] and other_is_array: return if not other_is_array and other_type in [DTI, TDI]: return # skip __rsub__ cases where we got conflicts with the other types' __sub__ if not other_on_rhs and other_type in ( Q_, np.ndarray, np.timedelta64, np.datetime64, DTI, TDI, ): return # skip cases where an absolute time is on the rhs, since pandas does # not support this case (and it does not make sense) if lhs_is_timedelta and not rhs_is_timedelta: return # skip cases where the lhs is a scalar and the rhs is an array because it will # always involve non monotonically increasing array values, which is forbidden. if rhs_is_array and not lhs_is_array: return # test values vals_lhs = [3, 5, 9] if lhs_is_array else [3] vals_rhs = [1, 2, 3] if rhs_is_array else [1] # setup rhs other_val = vals_rhs if other_on_rhs else vals_lhs if unit == "s": abs_val = [f"2000-01-01 10:00:0{v}" for v in other_val] else: abs_val = [f"2000-01-01 1{v}:00:00" for v in other_val] other = _initialize_time_type( other_type, other_val, abs_val, other_is_timedelta, other_is_array, not other_is_array, unit, ) # setup lhs time_class_values = vals_lhs if other_on_rhs else vals_rhs time_class_time_ref = None if time_class_is_timedelta else "2000-01-01 11:00:00" time_class = Time(Q_(time_class_values, unit), time_class_time_ref) # setup expected values sub = vals_rhs if other_is_array else vals_rhs[0] exp_val = np.array(vals_lhs) - sub if not other_is_timedelta: if time_class_is_timedelta: exp_val -= time_class_values[0] + exp_val[0] else: d = self._date_diff(time_class_time_ref, abs_val[0], unit) + vals_rhs[0] exp_val += d if other_on_rhs else (d + exp_val[0]) * -1 exp_time_ref = None if not other_is_timedelta and time_class_is_timedelta: exp_time_ref = abs_val[0] elif other_is_timedelta and not time_class_is_timedelta: exp_time_ref = time_class_time_ref exp = Time(Q_(exp_val, unit), exp_time_ref) # calculate and evaluate result res = time_class - other if other_on_rhs else other - time_class assert res.reference_time == exp.reference_time assert np.all(res.as_timedelta() == exp.as_timedelta()) assert np.all(res == exp)
def test_add_datetime( other_type, other_on_rhs: bool, time_class_is_array: bool, other_is_array: bool, ): """Test the `__add__` method if the `Time` class represents a datetime. Parameters ---------- other_type : The type of the other object other_on_rhs : If `True`, the other type is on the rhs of the + sign and on the lhs otherwise time_class_is_array : If `True`, the `Time` instance contains 3 time values and 1 otherwise other_is_array : If `True`, the other time object contains 3 time values and 1 otherwise """ # skip array cases where the type does not support arrays if other_type in [Timedelta, Timestamp] and other_is_array: return if not other_is_array and other_type in [DTI, TDI]: return # skip __radd__ cases where we got conflicts with the other types' __add__ if not other_on_rhs and other_type in (Q_, np.ndarray, np.timedelta64, TDI): return # setup rhs delta_val = [4, 6, 8] other = _initialize_time_type( other_type, delta_val, None, True, other_is_array, not other_is_array, "s", ) # setup lhs time_class_values = [1, 2, 3] if time_class_is_array else [1] time_class = Time(Q_(time_class_values, "s"), "2000-01-01 10:00:00") # setup expected values add = delta_val if other_is_array else delta_val[0] exp_val = np.array(time_class_values) + add exp_time_ref = time_class.reference_time exp = Time(Q_(exp_val, "s"), exp_time_ref) # calculate and evaluate result res = time_class + other if other_on_rhs else other + time_class assert res.reference_time == exp.reference_time assert np.all(res.as_timedelta() == exp.as_timedelta()) assert np.all(res == exp)
def test_add_timedelta( self, other_type, other_on_rhs: bool, unit: str, time_class_is_array: bool, other_is_array: bool, ): """Test the `__add__` method if the `Time` class represents a time delta. Parameters ---------- other_type : The type of the other object other_on_rhs : If `True`, the other type is on the rhs of the + sign and on the lhs otherwise unit : The time unit to use time_class_is_array : If `True`, the `Time` instance contains 3 time values and 1 otherwise other_is_array : If `True`, the other time object contains 3 time values and 1 otherwise """ other_type, is_timedelta = self._parse_time_type_test_input(other_type) # skip array cases where the type does not support arrays if other_type in [Timedelta, Timestamp] and other_is_array: return if not other_is_array and other_type in [DTI, TDI]: return # skip __radd__ cases where we got conflicts with the other types' __add__ if not other_on_rhs and other_type in ( Q_, np.ndarray, np.timedelta64, np.datetime64, DTI, TDI, ): return # setup rhs delta_val = [4, 6, 8] if unit == "s": abs_val = [f"2000-01-01 10:00:0{v}" for v in delta_val] else: abs_val = [f"2000-01-01 1{v}:00:00" for v in delta_val] other = _initialize_time_type( other_type, delta_val, abs_val, is_timedelta, other_is_array, not other_is_array, unit, ) # setup lhs time_class_values = [1, 2, 3] if time_class_is_array else [1] time_class = Time(Q_(time_class_values, unit)) # setup expected values add = delta_val if other_is_array else delta_val[0] exp_val = np.array(time_class_values) + add exp_val += 0 if is_timedelta else time_class_values[0] - exp_val[0] exp_time_ref = None if is_timedelta else abs_val[0] exp = Time(Q_(exp_val, unit), exp_time_ref) # calculate and evaluate result res = time_class + other if other_on_rhs else other + time_class assert res.reference_time == exp.reference_time assert np.all(res.as_timedelta() == exp.as_timedelta()) assert np.all(res == exp)