Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use pandas.to_timedelta function instead of invoking deprecated ctor arg #918

Merged
merged 19 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
# Release Notes

## 0.6.8 (unreleased)

### Changes

- use pandas.to_timedelta function to pass units to the TimeDeltaIndex object \[{pull}`918`\].

### Dependencies

- unpin nbval testing dependency.

## 0.6.7 (2023.08.24)

### Added

- added `weldx.exceptions` module with `WeldxException` \[{pull}`871`\] .
- added `weldx.exceptions` module with `WeldxException` \[{pull}`871`\].

### Fixes

Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ requires-python = ">=3.9"
dependencies = [
"numpy >=1.20",
"asdf >=2.15.1",
"pandas >=1.0",
"pandas >=1.5",
"xarray >=2022.9.0",
"scipy >=1.6.2",
"sympy >=1.6",
Expand All @@ -64,7 +64,7 @@ test = [
"pytest >=6",
"pytest-cov",
"pytest-xdist",
"nbval <0.10",
"nbval",
]
vis = [
"weldx_widgets >=0.2",
Expand Down Expand Up @@ -125,6 +125,7 @@ filterwarnings = [
"ignore::DeprecationWarning:traittypes.*:",
"ignore:Passing method to :FutureWarning:xarray.*:",
"error::pint.UnitStrippedWarning",
#"error::FutureWarning", # todo: we want to enable this, as it notifies us about upcoming failures due to upstream changes.
]

[tool.coverage.run]
Expand Down
2 changes: 1 addition & 1 deletion weldx/schemas/weldx.bam.de/weldx/time/time-0.1.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ examples:
values: !<asdf://weldx.bam.de/weldx/tags/time/datetimeindex-0.1.0>
start: !<asdf://weldx.bam.de/weldx/tags/time/timestamp-0.1.0> '2021-01-01T00:00:00'
end: !<asdf://weldx.bam.de/weldx/tags/time/timestamp-0.1.0> '2021-01-01T00:00:02'
freq: S
freq: s
min: !<asdf://weldx.bam.de/weldx/tags/time/timestamp-0.1.0> '2021-01-01T00:00:00'
max: !<asdf://weldx.bam.de/weldx/tags/time/timestamp-0.1.0> '2021-01-01T00:00:02'
reference_time: !<asdf://weldx.bam.de/weldx/tags/time/timestamp-0.1.0> '2021-01-01T00:00:00'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ examples:
!<asdf://weldx.bam.de/weldx/tags/time/timedeltaindex-0.1.0>
start: !<asdf://weldx.bam.de/weldx/tags/time/timedelta-0.1.0> P0DT0H0M0S
end: !<asdf://weldx.bam.de/weldx/tags/time/timedelta-0.1.0> P0DT0H0M10S
freq: 2S
freq: 2s
min: !<asdf://weldx.bam.de/weldx/tags/time/timedelta-0.1.0> P0DT0H0M0S
max: !<asdf://weldx.bam.de/weldx/tags/time/timedelta-0.1.0> P0DT0H0M10S
-
Expand Down
10 changes: 10 additions & 0 deletions weldx/tags/time/timedeltaindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

__all__ = ["TimedeltaIndexConverter"]

PANDAS_OLD_UNIT_SUFFIXES = dict(H="h", T="min", S="s", L="ms", U="us", N="ns")


def _handle_converted_pd_tdi_units(node: TaggedDict):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

backward compat @CagtayFabry

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changelog of pandas:

Units ‘H’, ‘T’, ‘S’, ‘L’, ‘U’ and ‘N’ are deprecated and will be removed in a future version. Please use ‘h’, ‘min’, ‘s’, ‘ms’, ‘us’, and ‘ns’ instead of ‘H’, ‘T’, ‘S’, ‘L’, ‘U’ and ‘N’.

"""Convert changed units in Pandas.Datetimeindex to valid values."""
for suf in PANDAS_OLD_UNIT_SUFFIXES:
node["freq"] = node["freq"].replace(suf, PANDAS_OLD_UNIT_SUFFIXES[suf])


class TimedeltaIndexConverter(WeldxConverter):
"""A simple implementation of serializing pandas TimedeltaIndex."""
Expand All @@ -33,6 +41,7 @@ def to_yaml_tree(self, obj: pd.TimedeltaIndex, tag: str, ctx) -> dict:
def from_yaml_tree(self, node: dict, tag: str, ctx):
"""Construct TimedeltaIndex from tree."""
if "freq" in node:
_handle_converted_pd_tdi_units(node)
return pd.timedelta_range(
start=node["start"], end=node["end"], freq=node["freq"]
)
Expand All @@ -43,6 +52,7 @@ def from_yaml_tree(self, node: dict, tag: str, ctx):
def shape_from_tagged(node: TaggedDict) -> list[int]:
"""Calculate the shape from static tagged tree instance."""
if "freq" in node:
_handle_converted_pd_tdi_units(node)
tdi_temp = pd.timedelta_range(
start=str(node["start"]), # can't handle TaggedString directly
end=str(node["end"]),
Expand Down
4 changes: 2 additions & 2 deletions weldx/tests/asdf_tests/test_asdf_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,12 +424,12 @@ def test_coordinate_system_manager_time_dependencies(
lcs_tdp_1_time_ref = pd.Timestamp("2000-03-17")
lcs_tdp_1 = tf.LocalCoordinateSystem(
coordinates=Q_([[1, 2, 3], [4, 5, 6]], "mm"),
time=pd.TimedeltaIndex([1, 2], "D"),
time=pd.to_timedelta([1, 2], "D"),
time_ref=lcs_tdp_1_time_ref,
)
lcs_tdp_2 = tf.LocalCoordinateSystem(
coordinates=Q_([[3, 7, 3], [9, 5, 8]], "mm"),
time=pd.TimedeltaIndex([1, 2], "D"),
time=pd.to_timedelta([1, 2], "D"),
time_ref=pd.Timestamp("2000-03-21"),
)

Expand Down
24 changes: 14 additions & 10 deletions weldx/tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,9 @@ class TestTimeSeries:

ME = MathematicalExpression
DTI = pd.DatetimeIndex
TDI = pd.TimedeltaIndex
TS = TimeSeries

time_discrete = pd.TimedeltaIndex([0, 1, 2, 3, 4], unit="s")
time_discrete = pd.to_timedelta([0, 1, 2, 3, 4], "s")
value_constant = Q_(1, "m")
values_discrete = Q_(np.array([10, 11, 12, 14, 16]), "mm")
me_expr_str = "a*t + b"
Expand All @@ -251,7 +250,7 @@ class TestTimeSeries:
"data, time, interpolation, shape_exp",
[
(Q_(1, "m"), None, None, (1,)),
(Q_([3, 7, 1], "m"), TDI([0, 1, 2], unit="s"), "step", (3,)),
(Q_([3, 7, 1], "m"), pd.to_timedelta([0, 1, 2], unit="s"), "step", (3,)),
(Q_([3, 7, 1], ""), Q_([0, 1, 2], "s"), "step", (3,)),
(Q_([3, 7, 1], ""), DTI(["2010", "2011", "2012"]), "step", (3,)),
],
Expand Down Expand Up @@ -329,12 +328,17 @@ def test_construction_expression(data, shape_exp, unit_exp):
@pytest.mark.parametrize(
"data, dims, coords, exception_type",
[
(Q_([1, 2, 3], "m"), "time", dict(time=TDI([1, 2, 3])), None),
(Q_([1, 2, 3], "m"), "a", dict(a=TDI([1, 2, 3])), KeyError),
(Q_([[1, 2]], "m"), ("a", "time"), dict(a=[2], time=TDI([1, 2])), None),
(Q_([1, 2, 3], "m"), "time", dict(time=pd.to_timedelta([1, 2, 3])), None),
(Q_([1, 2, 3], "m"), "a", dict(a=pd.to_timedelta([1, 2, 3])), KeyError),
(
Q_([[1, 2]], "m"),
("a", "time"),
dict(a=[2], time=pd.to_timedelta([1, 2])),
None,
),
(Q_([1, 2, 3], "m"), "time", None, KeyError),
(Q_([1, 2, 3], "m"), "time", dict(time=[1, 2, 3]), TypeError),
([1, 2, 3], "time", dict(time=TDI([1, 2, 3])), TypeError),
([1, 2, 3], "time", dict(time=pd.to_timedelta([1, 2, 3])), TypeError),
],
)
@pytest.mark.parametrize("reference_time", [None, "2000-01-01"])
Expand Down Expand Up @@ -382,7 +386,7 @@ def test_construction_exceptions(

# test_comparison -------------------------------------

time_wrong_values = TDI([0, 1, 2, 3, 5], unit="s")
time_wrong_values = pd.to_timedelta([0, 1, 2, 3, 5], "s")
values_discrete_wrong = Q_(np.array([10, 11, 12, 15, 16]), "mm")
values_unit_wrong = Q_(np.array([10, 11, 12, 14, 16]), "s")
values_unit_prefix_wrong = Q_(np.array([10, 11, 12, 14, 16]), "m")
Expand Down Expand Up @@ -426,9 +430,9 @@ def test_comparison(ts, ts_other, result_exp):

# test_interp_time -----------------------------------------------------------------

time_single = pd.TimedeltaIndex([2.1], "s")
time_single = pd.to_timedelta([2.1], "s")
time_single_q = Q_(2.1, "s")
time_mul = pd.TimedeltaIndex([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s")
time_mul = pd.to_timedelta([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s")
time_mul_q = Q_([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s")
results_exp_vec = [
[-8, 3, -3],
Expand Down
70 changes: 43 additions & 27 deletions weldx/tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import xarray as xr
from pandas import DatetimeIndex as DTI
from pandas import Timedelta, Timestamp, date_range
from pandas import TimedeltaIndex as TDI
from pint import DimensionalityError

from weldx.constants import Q_
Expand Down Expand Up @@ -77,7 +76,7 @@ def _initialize_time_type(

def _is_timedelta(cls_type):
"""Return ``True`` if the passed type is a timedelta type."""
return cls_type in [TDI, Timedelta, np.timedelta64] or (
return cls_type in [pd.to_timedelta, Timedelta, np.timedelta64] or (
cls_type is Time and not Time.is_absolute
)

Expand Down Expand Up @@ -143,7 +142,9 @@ def _get_init_exp_values(
val = [v + offset for v in delta_val]

val = val[0] if data_was_scalar else val
exp_timedelta = Timedelta(val, "s") if data_was_scalar else TDI(val, "s")
exp_timedelta = (
Timedelta(val, "s") if data_was_scalar else pd.to_timedelta(val, "s")
)

# expected datetime
exp_datetime = None
Expand All @@ -168,7 +169,7 @@ def _get_init_exp_values(
(str, "timedelta"),
(Time, "timedelta"),
(Q_, "timedelta"),
TDI,
pd.to_timedelta,
Timedelta,
np.timedelta64,
(str, "datetime"),
Expand Down Expand Up @@ -209,7 +210,7 @@ def test_init(
# 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]:
if not arr and input_type in [DTI, pd.to_timedelta]:
return

# create input values -----------------------------------
Expand Down Expand Up @@ -247,7 +248,7 @@ def test_init(
LocalCoordinateSystem(
coordinates=Q_(np.zeros((2, 3)), "mm"), time=["2000", "2001"]
),
TimeSeries(Q_([2, 4, 1], "m"), TDI([1, 2, 3], "s")),
TimeSeries(Q_([2, 4, 1], "m"), pd.to_timedelta([1, 2, 3], "s")),
TimeSeries(Q_([2, 4, 1], "m"), ["2001", "2002", "2003"]),
],
)
Expand All @@ -262,7 +263,7 @@ def test_init_from_time_dependent_types(time_dep_type):
@pytest.mark.parametrize(
"time, time_ref, raises",
[
(TDI([3, 2, 1]), None, ValueError),
(pd.to_timedelta([3, 2, 1]), None, ValueError),
(DTI(["2010", "2000"]), None, ValueError),
(["2010", "2000"], None, ValueError),
(Q_([3, 2, 1], "s"), None, ValueError),
Expand Down Expand Up @@ -290,7 +291,7 @@ def test_init_exception(time, time_ref, raises):
(str, "timedelta"),
(Time, "timedelta"),
(Q_, "timedelta"),
TDI,
pd.to_timedelta,
Timedelta,
np.timedelta64,
(str, "datetime"),
Expand Down Expand Up @@ -331,7 +332,7 @@ def test_add_timedelta(
# 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]:
if not other_is_array and other_type in [DTI, pd.to_timedelta]:
return

# skip __radd__ cases where we got conflicts with the other types' __add__
Expand All @@ -341,7 +342,7 @@ def test_add_timedelta(
np.timedelta64,
np.datetime64,
DTI,
TDI,
pd.to_timedelta,
):
return

Expand Down Expand Up @@ -392,7 +393,7 @@ def test_add_timedelta(
str,
Time,
Q_,
TDI,
pd.to_timedelta,
Timedelta,
np.timedelta64,
],
Expand Down Expand Up @@ -421,11 +422,16 @@ def test_add_datetime(
# 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]:
if not other_is_array and other_type in [DTI, pd.to_timedelta]:
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):
if not other_on_rhs and other_type in (
Q_,
np.ndarray,
np.timedelta64,
pd.to_timedelta,
):
return

# setup rhs
Expand Down Expand Up @@ -477,7 +483,7 @@ def _date_diff(date_1: str, date_2: str, unit: str) -> int:
(str, "timedelta"),
(Time, "timedelta"),
(Q_, "timedelta"),
TDI,
pd.to_timedelta,
Timedelta,
np.timedelta64,
(str, "datetime"),
Expand Down Expand Up @@ -532,7 +538,7 @@ def test_sub(
# 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]:
if not other_is_array and other_type in [DTI, pd.to_timedelta]:
return

# skip __rsub__ cases where we got conflicts with the other types' __sub__
Expand All @@ -542,7 +548,7 @@ def test_sub(
np.timedelta64,
np.datetime64,
DTI,
TDI,
pd.to_timedelta,
):
return

Expand Down Expand Up @@ -612,13 +618,16 @@ def test_sub(
"arg, expected",
[
# timedeltas
(TDI([42], unit="ns"), TDI([42], unit="ns")),
(pd.to_timedelta([42], unit="ns"), pd.to_timedelta([42], unit="ns")),
(pd.timedelta_range("0s", "20s", 10), pd.timedelta_range("0s", "20s", 10)),
(np.timedelta64(42), TDI([42], unit="ns")),
(np.array([-10, 0, 20]).astype("timedelta64[ns]"), TDI([-10, 0, 20], "ns")),
(Q_(42, "ns"), TDI([42], unit="ns")),
("10s", TDI(["10s"])),
(["5ms", "10s", "2D"], TDI(["5 ms", "10s", "2D"])),
(np.timedelta64(42), pd.to_timedelta([42], unit="ns")),
(
np.array([-10, 0, 20]).astype("timedelta64[ns]"),
pd.to_timedelta([-10, 0, 20], "ns"),
),
(Q_(42, "ns"), pd.to_timedelta([42], unit="ns")),
("10s", pd.to_timedelta(["10s"])),
(["5ms", "10s", "2D"], pd.to_timedelta(["5 ms", "10s", "2D"])),
# datetimes
(np.datetime64(50, "Y"), DTI(["2020-01-01"])),
("2020-01-01", DTI(["2020-01-01"])),
Expand Down Expand Up @@ -647,10 +656,10 @@ def test_pandas_index(arg, expected):
("1s", "ms", 1000),
("1s", "us", 1000000),
("1s", "ns", 1000000000),
(TDI([1, 2, 3], "s"), "s", [1, 2, 3]),
(TDI([1, 2, 3], "s"), "ms", np.array([1, 2, 3]) * 1e3),
(TDI([1, 2, 3], "s"), "us", np.array([1, 2, 3]) * 1e6),
(TDI([1, 2, 3], "s"), "ns", np.array([1, 2, 3]) * 1e9),
(pd.to_timedelta([1, 2, 3], "s"), "s", [1, 2, 3]),
(pd.to_timedelta([1, 2, 3], "s"), "ms", np.array([1, 2, 3]) * 1e3),
(pd.to_timedelta([1, 2, 3], "s"), "us", np.array([1, 2, 3]) * 1e6),
(pd.to_timedelta([1, 2, 3], "s"), "ns", np.array([1, 2, 3]) * 1e9),
("2020-01-01", "s", 0),
],
)
Expand Down Expand Up @@ -775,7 +784,14 @@ def test_resample_exceptions(values, number_or_interval, raises):
],
date_range("2020-02-01", periods=8, freq="1D"),
),
([TDI([1, 5]), TDI([2, 6, 7]), TDI([1, 3, 7])], TDI([1, 2, 3, 5, 6, 7])),
(
[
pd.to_timedelta([1, 5]),
pd.to_timedelta([2, 6, 7]),
pd.to_timedelta([1, 3, 7]),
],
pd.to_timedelta([1, 2, 3, 5, 6, 7]),
),
],
)
@pytest.mark.parametrize("test_instance", [True, False])
Expand Down
Loading
Loading