-
Notifications
You must be signed in to change notification settings - Fork 590
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
ENH: implement Time datatype #1105
Conversation
ibis/pandas/execution.py
Outdated
| pd.Series, | ||
| ) | ||
| def execute_time(op, data, scope=None): | ||
| return op.to_expr() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to do this to get it to return my correct node.
ibis/pandas/execution.py
Outdated
| ) | ||
| def execute_between_time(op, data, lower, upper, scope=None): | ||
|
|
||
| # TODO(jreback), this is most likely wrong |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this node is hit correctly, BUT I cannot get the data at this point (IOW the timestampseries)
column gives me the name of the column, but I don't have access to the table to select.
currently the impl is wrong (its going to be something like this (if data is a Series)
indexer = pd.DatetimeIndex(data).indexer_between_time(lower, upper)
then some other code (i have to convert to a boolean array)
5f79f90
to
20d3259
Compare
ibis/expr/api.py
Outdated
| @@ -643,7 +643,10 @@ def between(arg, lower, upper): | |||
| """ | |||
| lower = _ops.as_value_expr(lower) | |||
| upper = _ops.as_value_expr(upper) | |||
| op = _ops.Between(arg, lower, upper) | |||
| if isinstance(arg.op(), _ops.Time): | |||
| op = _ops.BetweenTime(arg, lower, upper) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need this if we have a time datatype, since you'll be able to do:
t.timestamp_col.time().between(lower, upper)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, but I have something wrong and its dispatching elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, actually I see what you're doing here now. Nevermind what I said.
|
|
||
| def test_time(): | ||
| ts = dt.time | ||
| assert str(ts) == "time" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add a test that checks the parsing of the time type , something like assert dt.validate_type('time').equals(dt.time)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ibis/expr/types.py
Outdated
| return False | ||
|
|
||
| def _can_compare(self, other): | ||
| return isinstance(other, (TemporalValue, StringValue)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it's intuitive to allow any TemporalValue here. I think allowing TimestampValue to TimeValue might be reasonable, but we definitely can't compare DateValues to TimeValues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are the postgres rules:
timestampcomparedate: allowedtimestampcomparetime: not alloweddatecomparetime: not allowed
So, you can pretty much only compare times with other time typed values. I think that's a reasonable default for now.
ibis/expr/types.py
Outdated
| @@ -1158,6 +1183,22 @@ class DateColumn(ColumnExpr, DateValue): | |||
| pass | |||
|
|
|||
|
|
|||
| class TimeScalar(ScalarExpr, TimeValue): | |||
| @property | |||
| def _factory(self): | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need this since there's no metadata attached to the time type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| @@ -1783,7 +1800,8 @@ def _timestamp_strftime(arg, format_str): | |||
| minute=_extract_field('minute', _ops.ExtractMinute), | |||
| second=_extract_field('second', _ops.ExtractSecond), | |||
| millisecond=_extract_field('millisecond', _ops.ExtractMillisecond), | |||
| truncate=_timestamp_truncate | |||
| truncate=_timestamp_truncate, | |||
| time=_timestamp_time, | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be modeled as an extract operation, so you should be able to do _extract_field('time', _ops.ExtractTime).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, we don't actually have a date() method. I'll put up a PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, nevermind on the extract.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is very different though. .time() simply gives back a time node w/o actually doing any ting under the hood. Then you have to calll .between(...) to actually do anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.time() should actually be doing something without needing any between.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's a type in many databases. Here's postgres:
ibis_testing=# select cast(timestamp_col as time) as "timestamp_col::time", timestamp_col from functional_alltypes limit 5;
timestamp_col::time | timestamp_col
---------------------+-----------------------
00:00:00 | 2010-06-01 00:00:00
00:01:00 | 2010-06-01 00:01:00
00:02:00.1 | 2010-06-01 00:02:00.1
00:03:00.3 | 2010-06-01 00:03:00.3
00:04:00.6 | 2010-06-01 00:04:00.6
(5 rows)
ibis/expr/operations.py
Outdated
| @@ -2363,6 +2367,11 @@ class ExtractMillisecond(ExtractTimestampField): | |||
| pass | |||
|
|
|||
|
|
|||
| class Time(TemporalUnaryOp): | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should inherit from UnaryOp since if you inherit from TemporalUnaryOp then date-typed columns will inherit the time() method and that doesn't make sense.
| @@ -643,7 +643,11 @@ def between(arg, lower, upper): | |||
| """ | |||
| lower = _ops.as_value_expr(lower) | |||
| upper = _ops.as_value_expr(upper) | |||
| op = _ops.Between(arg, lower, upper) | |||
|
|
|||
| if isinstance(arg.op(), _ops.Time): | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be if arg.type().equals(dt.time)
|
Looks like a GCS failure. I restarted the build. |
|
Appveyor looks good. We've been getting more pathological failures with our |
|
|
||
| Returns | ||
| ------- | ||
| Time node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be TimeValue
|
This needs additional tests:
These can go in |
|
ok pushed. how do I evaluate to a boolean this: |
|
@cpcloud I am missing some definition IOW it seems that somewhere you are overiding |
|
I just read through the Python 2.7.13 C source code for This is fundamentally a bug in Python 2, which is fixed in Python 3. Using this feature is going to be limited to Python 3 only or we drop support for Python 2 altogether. |
|
I think I've run into this issue before with |
|
What's annoying is that there's a hack that we use for :( |
7d8b5e7
to
0ed097e
Compare
ibis/expr/tests/test_value_exprs.py
Outdated
|
|
||
| # we cannot actually compare datetime.time objects and literals | ||
| # in a deferred way in python 2, they short circuit in the CPython | ||
| result = operator.eq(time(10, 0), literal('2017-04-01')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should compare a time to another time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ibis/pandas/tests/test_operations.py
Outdated
| @pytest.mark.skipif(not PY2, reason="testing for PY2") | ||
| def test_times_ops_py2(t, df): | ||
| with pytest.raises(ValueError): | ||
| t.plain_datetimes_naive.time().between('10:00', '10:00').execute() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you put only the part that fails underneath raises so that it's clear when reading the test where the code should fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
imlpmenet BetweenTime node closes ibis-project#1098
|
@cpcloud all green here. |
|
Looks good, merging. |
implement BetweenTime node
closes #1098
closes #1096