From f69c485e03b935fea06d685a4dc153d3380c1f27 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:13:18 -0400 Subject: [PATCH 1/3] test(timestamp): add expression test for timestamp range with expression inputs --- ibis/tests/expr/test_timestamp.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ibis/tests/expr/test_timestamp.py b/ibis/tests/expr/test_timestamp.py index 45b8972d5dc4..e7c620eae99c 100644 --- a/ibis/tests/expr/test_timestamp.py +++ b/ibis/tests/expr/test_timestamp.py @@ -1,6 +1,6 @@ from __future__ import annotations -from datetime import datetime +from datetime import datetime, timedelta import numpy as np import pandas as pd @@ -184,3 +184,26 @@ def test_timestamp_field_access_on_time_failure( def test_integer_timestamp_fails(value): with pytest.raises(TypeError, match=r"Use ibis\.literal\(\.\.\.\)\.to_timestamp"): ibis.timestamp(value) + + +def test_timestamp_range_with_expr_inputs(): + start = ibis.now() - ibis.interval(days=1) + stop = ibis.now() + expr = ibis.range(start, stop, ibis.interval(seconds=1)) + + dtype = expr.type() + + assert dtype.is_array() + assert dtype.value_type.is_timestamp() + + +def test_timestamp_range_with_mixed_type_inputs(): + now = datetime.now() + t = ( + ibis.range(now - timedelta(days=2), ibis.now(), step=ibis.interval(minutes=1)) + .unnest() + .name("timestamp") + .as_table() + ) + assert t.columns == ["timestamp"] + assert t["timestamp"].type().is_timestamp() From c0c2173d1b0eeac123e1a8e0796aef50cee33d83 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:58:50 -0400 Subject: [PATCH 2/3] test(timestamps): add test for timestamp string inputs --- ibis/tests/expr/test_timestamp.py | 45 ++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/ibis/tests/expr/test_timestamp.py b/ibis/tests/expr/test_timestamp.py index e7c620eae99c..f24bd91718f4 100644 --- a/ibis/tests/expr/test_timestamp.py +++ b/ibis/tests/expr/test_timestamp.py @@ -186,24 +186,37 @@ def test_integer_timestamp_fails(value): ibis.timestamp(value) -def test_timestamp_range_with_expr_inputs(): - start = ibis.now() - ibis.interval(days=1) - stop = ibis.now() - expr = ibis.range(start, stop, ibis.interval(seconds=1)) +@pytest.mark.parametrize( + "start", + [ + "2002-01-01 00:00:00", + datetime(2002, 1, 1, 0, 0, 0), + ibis.timestamp("2002-01-01 00:00:00"), + ibis.timestamp(datetime(2002, 1, 1, 0, 0, 0)), + ibis.table({"start": "timestamp"}).start, + ], +) +@pytest.mark.parametrize( + "stop", + [ + "2002-01-02 00:00:00", + datetime(2002, 1, 2, 0, 0, 0), + ibis.timestamp("2002-01-02 00:00:00"), + ibis.timestamp(datetime(2002, 1, 2, 0, 0, 0)), + ibis.table({"stop": "timestamp"}).stop, + ], +) +@pytest.mark.parametrize("step", [ibis.interval(seconds=1), timedelta(seconds=1)]) +def test_timestamp_range_with_str_inputs(start, stop, step): + expr = ibis.range(start, stop, step) + + op = expr.op() + + assert op.start.dtype.is_timestamp() + assert op.stop.dtype.is_timestamp() + assert op.step.dtype.is_interval() dtype = expr.type() assert dtype.is_array() assert dtype.value_type.is_timestamp() - - -def test_timestamp_range_with_mixed_type_inputs(): - now = datetime.now() - t = ( - ibis.range(now - timedelta(days=2), ibis.now(), step=ibis.interval(minutes=1)) - .unnest() - .name("timestamp") - .as_table() - ) - assert t.columns == ["timestamp"] - assert t["timestamp"].type().is_timestamp() From 67e4240c87488af72959535abe569d3a786799f5 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:10:05 -0400 Subject: [PATCH 3/3] feat(api): accept more input types in `ibis.range` --- ibis/expr/api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ibis/expr/api.py b/ibis/expr/api.py index 6ec3e8e36c6c..f8aca6d68939 100644 --- a/ibis/expr/api.py +++ b/ibis/expr/api.py @@ -2237,7 +2237,9 @@ def _timestamp_range( step: datetime.timedelta | ir.IntervalValue, ) -> ir.ArrayValue: return ops.TimestampRange( - start=normalize_datetime(start), stop=normalize_datetime(stop), step=step + start=normalize_datetime(start) if isinstance(start, str) else start, + stop=normalize_datetime(stop) if isinstance(stop, str) else stop, + step=step, ).to_expr()