Repository: vaexio/vaex

Issue:
Pandas 0.25 compatibility with .dt accessor
Pandas 0.25 seems to have more issues than those in https://github.com/vaexio/vaex/pull/226
Maybe this is a pandas issue or expected behaviour, otherwise we should open an issue at the pandas repo.
cc @xhochy @datapythonista

Basically, pandas does not seem to accept read-only buffers for dt.hour.

```
 11 assert df.date.dt.hour.values.tolist() == pandas_df.date.dt.hour.values.tolist()
     12 assert df.date.dt.minute.values.tolist() == pandas_df.date.dt.minute.values.tolist()
     13 assert df.date.dt.second.values.tolist() == pandas_df.date.dt.second.values.tolist()

~/src/vaex/packages/vaex-core/vaex/expression.py in values(self)
    194     @property
    195     def values(self):
--> 196         return self.evaluate()
    197 
    198     @property

~/src/vaex/packages/vaex-core/vaex/expression.py in evaluate(self, i1, i2, out, selection)
    529 
    530     def evaluate(self, i1=None, i2=None, out=None, selection=None):
--> 531         return self.ds.evaluate(self, i1, i2, out=out, selection=selection)
    532 
    533     # TODO: it is not so elegant we need to have a custom version of this

~/src/vaex/packages/vaex-core/vaex/dataframe.py in evaluate(self, expression, i1, i2, out, selection, filtered, internal)
   4764         if out is not None:
   4765             scope.buffers[expression] = out
-> 4766         value = scope.evaluate(expression)
   4767         if isinstance(value, ColumnString) and not internal:
   4768             value = value.to_numpy()

~/src/vaex/packages/vaex-core/vaex/scopes.py in evaluate(self, expression, out)
     90             # logger.debug("in eval")
     91             # eval("def f(")
---> 92             result = eval(expression, expression_namespace, self)
     93             self.values[expression] = result
     94             # if out is not None:

<string> in <module>

~/src/vaex/packages/vaex-core/vaex/functions.py in dt_hour(x)
    536     """
    537     import pandas as pd
--> 538     return pd.Series(x).dt.hour.values
    539 
    540 @register_function(scope='dt', as_property=True)

~/miniconda3/envs/dev/lib/python3.6/site-packages/pandas/core/accessor.py in _getter(self)
     77         def _create_delegator_property(name):
     78             def _getter(self):
---> 79                 return self._delegate_property_get(name)
     80 
     81             def _setter(self, new_values):

~/miniconda3/envs/dev/lib/python3.6/site-packages/pandas/core/indexes/accessors.py in _delegate_property_get(self, name)
     65         values = self._get_values()
     66 
---> 67         result = getattr(values, name)
     68 
     69         # maybe need to upcast (ints)

~/miniconda3/envs/dev/lib/python3.6/site-packages/pandas/core/accessor.py in _getter(self)
     77         def _create_delegator_property(name):
     78             def _getter(self):
---> 79                 return self._delegate_property_get(name)
     80 
     81             def _setter(self, new_values):

~/miniconda3/envs/dev/lib/python3.6/site-packages/pandas/core/indexes/datetimelike.py in _delegate_property_get(self, name, *args, **kwargs)
    802 
    803     def _delegate_property_get(self, name, *args, **kwargs):
--> 804         result = getattr(self._data, name)
    805         if name not in self._raw_properties:
    806             result = Index(result, name=self.name)

~/miniconda3/envs/dev/lib/python3.6/site-packages/pandas/core/arrays/datetimes.py in f(self)
    138 
    139         else:
--> 140             result = fields.get_date_field(values, field)
    141             result = self._maybe_mask_results(
    142                 result, fill_value=None, convert="float64"

pandas/_libs/tslibs/fields.pyx in pandas._libs.tslibs.fields.get_date_field()

~/miniconda3/envs/dev/lib/python3.6/site-packages/pandas/_libs/tslibs/fields.cpython-36m-darwin.so in View.MemoryView.memoryview_cwrapper()

~/miniconda3/envs/dev/lib/python3.6/site-packages/pandas/_libs/tslibs/fields.cpython-36m-darwin.so in View.MemoryView.memoryview.__cinit__()

ValueError: buffer source array is read-only
```


Discussion:

Resolving patch:
diff --git a/packages/vaex-core/vaex/functions.py b/packages/vaex-core/vaex/functions.py
--- a/packages/vaex-core/vaex/functions.py
+++ b/packages/vaex-core/vaex/functions.py
@@ -274,7 +274,7 @@ def dt_dayofweek(x):
     2  3
     """
     import pandas as pd
-    return pd.Series(x).dt.dayofweek.values
+    return pd.Series(_pandas_dt_fix(x)).dt.dayofweek.values
 
 @register_function(scope='dt', as_property=True)
 def dt_dayofyear(x):
@@ -303,7 +303,7 @@ def dt_dayofyear(x):
     2  316
     """
     import pandas as pd
-    return pd.Series(x).dt.dayofyear.values
+    return pd.Series(_pandas_dt_fix(x)).dt.dayofyear.values
 
 @register_function(scope='dt', as_property=True)
 def dt_is_leap_year(x):
@@ -332,7 +332,7 @@ def dt_is_leap_year(x):
     2  False
     """
     import pandas as pd
-    return pd.Series(x).dt.is_leap_year.values
+    return pd.Series(_pandas_dt_fix(x)).dt.is_leap_year.values
 
 @register_function(scope='dt', as_property=True)
 def dt_year(x):
@@ -361,7 +361,7 @@ def dt_year(x):
     2  2015
     """
     import pandas as pd
-    return pd.Series(x).dt.year.values
+    return pd.Series(_pandas_dt_fix(x)).dt.year.values
 
 @register_function(scope='dt', as_property=True)
 def dt_month(x):
@@ -390,7 +390,7 @@ def dt_month(x):
     2  11
     """
     import pandas as pd
-    return pd.Series(x).dt.month.values
+    return pd.Series(_pandas_dt_fix(x)).dt.month.values
 
 @register_function(scope='dt', as_property=True)
 def dt_month_name(x):
@@ -448,7 +448,7 @@ def dt_day(x):
     2  12
     """
     import pandas as pd
-    return pd.Series(x).dt.day.values
+    return pd.Series(_pandas_dt_fix(x)).dt.day.values
 
 @register_function(scope='dt', as_property=True)
 def dt_day_name(x):
@@ -506,7 +506,7 @@ def dt_weekofyear(x):
     2  46
     """
     import pandas as pd
-    return pd.Series(x).dt.weekofyear.values
+    return pd.Series(_pandas_dt_fix(x)).dt.weekofyear.values
 
 @register_function(scope='dt', as_property=True)
 def dt_hour(x):
@@ -535,7 +535,7 @@ def dt_hour(x):
     2  11
     """
     import pandas as pd
-    return pd.Series(x).dt.hour.values
+    return pd.Series(_pandas_dt_fix(x)).dt.hour.values
 
 @register_function(scope='dt', as_property=True)
 def dt_minute(x):
@@ -564,7 +564,7 @@ def dt_minute(x):
     2  34
     """
     import pandas as pd
-    return pd.Series(x).dt.minute.values
+    return pd.Series(_pandas_dt_fix(x)).dt.minute.values
 
 @register_function(scope='dt', as_property=True)
 def dt_second(x):
@@ -593,7 +593,7 @@ def dt_second(x):
     2  22
     """
     import pandas as pd
-    return pd.Series(x).dt.second.values
+    return pd.Series(_pandas_dt_fix(x)).dt.second.values
 
 
 ########## string operations ##########


Test patch: