From 82b79b178768641268660ff773f5c1c084001f99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:06:33 +0100 Subject: [PATCH 1/2] Bump mamba-org/setup-micromamba from 1.8.0 to 1.8.1 (#914) Bumps [mamba-org/setup-micromamba](https://github.com/mamba-org/setup-micromamba) from 1.8.0 to 1.8.1. - [Release notes](https://github.com/mamba-org/setup-micromamba/releases) - [Commits](https://github.com/mamba-org/setup-micromamba/compare/v1.8.0...v1.8.1) --- updated-dependencies: - dependency-name: mamba-org/setup-micromamba dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_pkg.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/pytest.yml | 4 ++-- .github/workflows/pytest_asdf.yml | 2 +- .github/workflows/static_analysis.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_pkg.yml b/.github/workflows/build_pkg.yml index 5a3da2e81..2b3730742 100644 --- a/.github/workflows/build_pkg.yml +++ b/.github/workflows/build_pkg.yml @@ -41,7 +41,7 @@ jobs: fetch-depth: 0 # Fetch all history for all tags and branches - name: Setup Conda Environment - uses: mamba-org/setup-micromamba@v1.8.0 + uses: mamba-org/setup-micromamba@v1.8.1 with: environment-file: ./devtools/conda.recipe/build_env.yml environment-name: build_env diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9926871f7..32caec587 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -47,7 +47,7 @@ jobs: fetch-depth: 0 # Fetch all history for all tags and branches - name: Setup Conda Environment - uses: mamba-org/setup-micromamba@v1.8.0 + uses: mamba-org/setup-micromamba@v1.8.1 with: environment-file: ./doc/rtd_environment.yml environment-name: rtd diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index d6b5bd1d3..1e015e4a5 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -47,7 +47,7 @@ jobs: setup_requires: 'include' - name: Setup Conda Environment - uses: mamba-org/setup-micromamba@v1.8.0 + uses: mamba-org/setup-micromamba@v1.8.1 with: environment-file: ./environment.yml environment-name: weldx @@ -147,7 +147,7 @@ jobs: setup_requires: 'include' - name: Setup Conda Environment - uses: mamba-org/setup-micromamba@v1.8.0 + uses: mamba-org/setup-micromamba@v1.8.1 with: environment-file: ./environment.yml environment-name: weldx diff --git a/.github/workflows/pytest_asdf.yml b/.github/workflows/pytest_asdf.yml index b022a895e..511558463 100644 --- a/.github/workflows/pytest_asdf.yml +++ b/.github/workflows/pytest_asdf.yml @@ -33,7 +33,7 @@ jobs: setup_requires: 'include' - name: Setup Conda Environment - uses: mamba-org/setup-micromamba@v1.8.0 + uses: mamba-org/setup-micromamba@v1.8.1 with: environment-file: ./environment.yml environment-name: weldx diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 8da2bbf9d..1d092f4a8 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -49,7 +49,7 @@ jobs: key: ${{ runner.os }}-${{ hashFiles('./environment.yml') }} - name: Setup Conda Environment - uses: mamba-org/setup-micromamba@v1.8.0 + uses: mamba-org/setup-micromamba@v1.8.1 with: environment-file: ./environment.yml environment-name: weldx From ab583bea6d9b2d7a3d0525d71c57796022f0afda Mon Sep 17 00:00:00 2001 From: "Martin K. Scherer" Date: Tue, 12 Mar 2024 09:14:42 +0100 Subject: [PATCH 2/2] use pandas.to_timedelta function instead of invoking deprecated ctor arg (#918) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use pandas.to_timedelta function instead of invoking deprecated ctor (unit argument will be gone) * handle all old units * pin pandas >=1.5 * Update weldx/tags/time/timedeltaindex.py Co-authored-by: Çağtay Fabry --- CHANGELOG.md | 12 +- pyproject.toml | 5 +- .../weldx.bam.de/weldx/time/time-0.1.0.yaml | 2 +- .../weldx/time/timedeltaindex-0.1.0.yaml | 2 +- weldx/tags/time/timedeltaindex.py | 10 + weldx/tests/asdf_tests/test_asdf_core.py | 4 +- weldx/tests/test_core.py | 24 ++- weldx/tests/test_time.py | 70 ++++--- weldx/tests/test_utility.py | 10 +- .../tests/transformations/test_cs_manager.py | 59 +++--- weldx/tests/transformations/test_local_cs.py | 174 ++++++++++-------- weldx/time.py | 4 +- 12 files changed, 218 insertions(+), 158 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df56ffb2c..8c219869a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/pyproject.toml b/pyproject.toml index e65f52b13..d06cc4ff9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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", @@ -64,7 +64,7 @@ test = [ "pytest >=6", "pytest-cov", "pytest-xdist", - "nbval <0.10", + "nbval", ] vis = [ "weldx_widgets >=0.2", @@ -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] diff --git a/weldx/schemas/weldx.bam.de/weldx/time/time-0.1.0.yaml b/weldx/schemas/weldx.bam.de/weldx/time/time-0.1.0.yaml index ddb82852a..0274cb826 100644 --- a/weldx/schemas/weldx.bam.de/weldx/time/time-0.1.0.yaml +++ b/weldx/schemas/weldx.bam.de/weldx/time/time-0.1.0.yaml @@ -34,7 +34,7 @@ examples: values: ! start: ! '2021-01-01T00:00:00' end: ! '2021-01-01T00:00:02' - freq: S + freq: s min: ! '2021-01-01T00:00:00' max: ! '2021-01-01T00:00:02' reference_time: ! '2021-01-01T00:00:00' diff --git a/weldx/schemas/weldx.bam.de/weldx/time/timedeltaindex-0.1.0.yaml b/weldx/schemas/weldx.bam.de/weldx/time/timedeltaindex-0.1.0.yaml index cf83e4f85..e5a8c5587 100644 --- a/weldx/schemas/weldx.bam.de/weldx/time/timedeltaindex-0.1.0.yaml +++ b/weldx/schemas/weldx.bam.de/weldx/time/timedeltaindex-0.1.0.yaml @@ -13,7 +13,7 @@ examples: ! start: ! P0DT0H0M0S end: ! P0DT0H0M10S - freq: 2S + freq: 2s min: ! P0DT0H0M0S max: ! P0DT0H0M10S - diff --git a/weldx/tags/time/timedeltaindex.py b/weldx/tags/time/timedeltaindex.py index d6b72f574..b0aeac6eb 100644 --- a/weldx/tags/time/timedeltaindex.py +++ b/weldx/tags/time/timedeltaindex.py @@ -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): + """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.""" @@ -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"] ) @@ -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"]), diff --git a/weldx/tests/asdf_tests/test_asdf_core.py b/weldx/tests/asdf_tests/test_asdf_core.py index 67e92bdc9..dadc7c270 100644 --- a/weldx/tests/asdf_tests/test_asdf_core.py +++ b/weldx/tests/asdf_tests/test_asdf_core.py @@ -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"), ) diff --git a/weldx/tests/test_core.py b/weldx/tests/test_core.py index a8ac6cdd8..b70d111eb 100644 --- a/weldx/tests/test_core.py +++ b/weldx/tests/test_core.py @@ -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" @@ -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,)), ], @@ -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"]) @@ -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") @@ -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], diff --git a/weldx/tests/test_time.py b/weldx/tests/test_time.py index 8e979fdad..2ca0028ee 100644 --- a/weldx/tests/test_time.py +++ b/weldx/tests/test_time.py @@ -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_ @@ -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 ) @@ -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 @@ -168,7 +169,7 @@ def _get_init_exp_values( (str, "timedelta"), (Time, "timedelta"), (Q_, "timedelta"), - TDI, + pd.to_timedelta, Timedelta, np.timedelta64, (str, "datetime"), @@ -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 ----------------------------------- @@ -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"]), ], ) @@ -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), @@ -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"), @@ -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__ @@ -341,7 +342,7 @@ def test_add_timedelta( np.timedelta64, np.datetime64, DTI, - TDI, + pd.to_timedelta, ): return @@ -392,7 +393,7 @@ def test_add_timedelta( str, Time, Q_, - TDI, + pd.to_timedelta, Timedelta, np.timedelta64, ], @@ -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 @@ -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"), @@ -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__ @@ -542,7 +548,7 @@ def test_sub( np.timedelta64, np.datetime64, DTI, - TDI, + pd.to_timedelta, ): return @@ -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"])), @@ -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), ], ) @@ -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]) diff --git a/weldx/tests/test_utility.py b/weldx/tests/test_utility.py index 6658fd3a9..1caa7847a 100644 --- a/weldx/tests/test_utility.py +++ b/weldx/tests/test_utility.py @@ -333,7 +333,7 @@ def test_xr_fill_all(): "d1": np.array([-1, 1], dtype=float), "d2": np.array([-1, 1], dtype=int), "d3": pd.DatetimeIndex(["2020-05-01", "2020-05-03"]), - "d4": pd.TimedeltaIndex([0, 1, 2, 3], "s"), + "d4": pd.to_timedelta([0, 1, 2, 3], "s"), "d5": ["x", "y", "z"], }, ) @@ -352,7 +352,7 @@ def test_xr_fill_all(): "dtype": ["datetime64[ns]", "timedelta64[ns]"], }, d4={ - "values": pd.TimedeltaIndex([0, 1, 2, 3], "s"), + "values": pd.to_timedelta([0, 1, 2, 3], "s"), "dtype": ["datetime64[ns]", "timedelta64[ns]"], }, d5={"values": ["x", "y", "z"], "dtype": "