diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index eed48f9e46897..ee3521ae31949 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -89,7 +89,7 @@ Categorical Datetimelike ^^^^^^^^^^^^ - Bug in :meth:`Series.__setitem__` incorrectly casting ``np.timedelta64("NaT")`` to ``np.datetime64("NaT")`` when inserting into a :class:`Series` with datetime64 dtype (:issue:`27311`) -- +- Bug in :meth:`Series.dt` property lookups when the underlying data is read-only (:issue:`27529`) - diff --git a/pandas/_libs/tslibs/fields.pyx b/pandas/_libs/tslibs/fields.pyx index 2a41b5ff2339c..2ed85595f7e3a 100644 --- a/pandas/_libs/tslibs/fields.pyx +++ b/pandas/_libs/tslibs/fields.pyx @@ -45,7 +45,7 @@ def get_time_micros(ndarray[int64_t] dtindex): @cython.wraparound(False) @cython.boundscheck(False) -def build_field_sarray(int64_t[:] dtindex): +def build_field_sarray(const int64_t[:] dtindex): """ Datetime as int64 representation to a structured array of fields """ @@ -87,7 +87,7 @@ def build_field_sarray(int64_t[:] dtindex): @cython.wraparound(False) @cython.boundscheck(False) -def get_date_name_field(int64_t[:] dtindex, object field, object locale=None): +def get_date_name_field(const int64_t[:] dtindex, object field, object locale=None): """ Given a int64-based datetime index, return array of strings of date name based on requested field (e.g. weekday_name) @@ -137,7 +137,7 @@ def get_date_name_field(int64_t[:] dtindex, object field, object locale=None): @cython.wraparound(False) @cython.boundscheck(False) -def get_start_end_field(int64_t[:] dtindex, object field, +def get_start_end_field(const int64_t[:] dtindex, object field, object freqstr=None, int month_kw=12): """ Given an int64-based datetime index return array of indicators @@ -380,7 +380,7 @@ def get_start_end_field(int64_t[:] dtindex, object field, @cython.wraparound(False) @cython.boundscheck(False) -def get_date_field(int64_t[:] dtindex, object field): +def get_date_field(const int64_t[:] dtindex, object field): """ Given a int64-based datetime index, extract the year, month, etc., field and return an array of these values. @@ -542,7 +542,7 @@ def get_date_field(int64_t[:] dtindex, object field): @cython.wraparound(False) @cython.boundscheck(False) -def get_timedelta_field(int64_t[:] tdindex, object field): +def get_timedelta_field(const int64_t[:] tdindex, object field): """ Given a int64-based timedelta index, extract the days, hrs, sec., field and return an array of these values. diff --git a/pandas/tests/tslibs/test_fields.py b/pandas/tests/tslibs/test_fields.py new file mode 100644 index 0000000000000..cd729956a027c --- /dev/null +++ b/pandas/tests/tslibs/test_fields.py @@ -0,0 +1,31 @@ +import numpy as np + +from pandas._libs.tslibs import fields + +import pandas.util.testing as tm + + +def test_fields_readonly(): + # https://github.com/vaexio/vaex/issues/357 + # fields functions should't raise when we pass read-only data + dtindex = np.arange(5, dtype=np.int64) * 10 ** 9 * 3600 * 24 * 32 + dtindex.flags.writeable = False + + result = fields.get_date_name_field(dtindex, "month_name") + expected = np.array( + ["January", "February", "March", "April", "May"], dtype=np.object + ) + tm.assert_numpy_array_equal(result, expected) + + result = fields.get_date_field(dtindex, "Y") + expected = np.array([1970, 1970, 1970, 1970, 1970], dtype=np.int32) + tm.assert_numpy_array_equal(result, expected) + + result = fields.get_start_end_field(dtindex, "is_month_start", None) + expected = np.array([True, False, False, False, False], dtype=np.bool_) + tm.assert_numpy_array_equal(result, expected) + + # treat dtindex as timedeltas for this next one + result = fields.get_timedelta_field(dtindex, "days") + expected = np.arange(5, dtype=np.int32) * 32 + tm.assert_numpy_array_equal(result, expected)