Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ def asi8(self):
def nbytes(self):
return self._data.nbytes

def __array__(self, dtype=None):
# used for Timedelta/DatetimeArray, overwritten by PeriodArray
if is_object_dtype(dtype):
return np.array(list(self), dtype=object)
return self._data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would raise if dtype not in [None, object]


@property
def shape(self):
return (len(self),)
Expand Down
13 changes: 2 additions & 11 deletions pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

from pandas.core.dtypes.common import (
_INT64_DTYPE, _NS_DTYPE, is_categorical_dtype, is_datetime64_dtype,
is_datetime64tz_dtype, is_extension_type, is_float_dtype, is_int64_dtype,
is_object_dtype, is_period_dtype, is_string_dtype, is_timedelta64_dtype)
is_datetime64tz_dtype, is_extension_type, is_float_dtype, is_object_dtype,
is_period_dtype, is_string_dtype, is_timedelta64_dtype)
from pandas.core.dtypes.dtypes import DatetimeTZDtype
from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries
from pandas.core.dtypes.missing import isna
Expand Down Expand Up @@ -416,15 +416,6 @@ def _resolution(self):
# ----------------------------------------------------------------
# Array-Like / EA-Interface Methods

def __array__(self, dtype=None):
if is_object_dtype(dtype):
return np.array(list(self), dtype=object)
elif is_int64_dtype(dtype):
return self.asi8

# TODO: warn that conversion may be lossy?
return self._data.view(np.ndarray) # follow Index.__array__

def __iter__(self):
"""
Return an iterator over the boxed values
Expand Down
4 changes: 4 additions & 0 deletions pandas/core/arrays/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ def freq(self):
"""
return self.dtype.freq

def __array__(self, dtype=None):
# overriding DatetimelikeArray
return np.array(list(self), dtype=object)

# --------------------------------------------------------------------
# Vectorized analogues of Period properties

Expand Down
8 changes: 8 additions & 0 deletions pandas/core/indexes/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ class DatetimeIndexOpsMixin(DatetimeLikeArrayMixin):
_resolution = cache_readonly(DatetimeLikeArrayMixin._resolution.fget)
resolution = cache_readonly(DatetimeLikeArrayMixin.resolution.fget)

def __array__(self, dtype=None):
# TODO properly dispatch to EA
if is_period_dtype(self):
return self._data.__array__(dtype=dtype)
if is_object_dtype(dtype):
return np.array(list(self), dtype=object)
return self._data

def equals(self, other):
"""
Determines if two Index objects contain the same elements.
Expand Down
61 changes: 56 additions & 5 deletions pandas/tests/arrays/test_datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,26 @@ def test_array_object_dtype(self, tz_naive_fixture):
result = np.array(dti, dtype=object)
tm.assert_numpy_array_equal(result, expected)

def test_array(self, tz_naive_fixture):
def test_array(self, datetime_index):
arr = DatetimeArray(datetime_index)

result = np.asarray(arr)
expected = arr._data
assert result is expected
tm.assert_numpy_array_equal(result, expected)

result = np.asarray(arr, dtype=object)
expected = np.array(list(arr), dtype=object)
tm.assert_numpy_array_equal(result, expected)

# to other dtype always copies
result = np.asarray(arr, dtype='int64')
assert result is not arr.asi8
assert not np.may_share_memory(arr, result)
expected = arr.asi8.copy()
tm.assert_numpy_array_equal(result, expected)

def test_array_tz(self, tz_naive_fixture):
# GH#23524
tz = tz_naive_fixture
dti = pd.date_range('2016-01-01', periods=3, tz=tz)
Expand All @@ -150,7 +169,6 @@ def test_array(self, tz_naive_fixture):
assert result.base is not None

def test_array_i8_dtype(self, tz_naive_fixture):
# GH#23524
tz = tz_naive_fixture
dti = pd.date_range('2016-01-01', periods=3, tz=tz)
arr = DatetimeArray(dti)
Expand All @@ -162,10 +180,10 @@ def test_array_i8_dtype(self, tz_naive_fixture):
result = np.array(arr, dtype=np.int64)
tm.assert_numpy_array_equal(result, expected)

# check that we are not making copies when setting copy=False
# check that we are still making copies when setting copy=False
result = np.array(arr, dtype='i8', copy=False)
assert result.base is expected.base
assert result.base is not None
assert result.base is not expected.base
assert result.base is None

def test_from_array_keeps_base(self):
# Ensure that DatetimeArray._data.base isn't lost.
Expand Down Expand Up @@ -345,6 +363,26 @@ def test_int_properties(self, timedelta_index, propname):

tm.assert_numpy_array_equal(result, expected)

def test_array(self, timedelta_index):
arr = TimedeltaArray(timedelta_index)

result = np.asarray(arr)
expected = arr._data
assert result is expected
tm.assert_numpy_array_equal(result, expected)

# to object dtype
result = np.asarray(arr, dtype=object)
expected = np.array(list(arr), dtype=object)
tm.assert_numpy_array_equal(result, expected)

# to other dtype always copies
result = np.asarray(arr, dtype='int64')
assert result is not arr.asi8
assert not np.may_share_memory(arr, result)
expected = arr.asi8.copy()
tm.assert_numpy_array_equal(result, expected)

def test_take_fill_valid(self, timedelta_index):
tdi = timedelta_index
arr = TimedeltaArray(tdi)
Expand Down Expand Up @@ -418,3 +456,16 @@ def test_int_properties(self, period_index, propname):
expected = np.array(getattr(pi, propname))

tm.assert_numpy_array_equal(result, expected)

def test_array(self, period_index):
arr = PeriodArray(period_index)

result = np.asarray(arr)
expected = np.array(list(arr), dtype=object)
tm.assert_numpy_array_equal(result, expected)

result = np.asarray(arr, dtype=object)
tm.assert_numpy_array_equal(result, expected)

with pytest.raises(TypeError):
np.asarray(arr, dtype='int64')
5 changes: 5 additions & 0 deletions pandas/tests/extension/base/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pandas.core.dtypes.dtypes import ExtensionDtype

import pandas as pd
import pandas.util.testing as tm

from .base import BaseExtensionTests

Expand Down Expand Up @@ -33,6 +34,10 @@ def test_array_interface(self, data):
result = np.array(data)
assert result[0] == data[0]

result = np.array(data, dtype=object)
expected = np.array(list(data), dtype=object)
tm.assert_numpy_array_equal(result, expected)

def test_is_extension_array_dtype(self, data):
assert is_extension_array_dtype(data)
assert is_extension_array_dtype(data.dtype)
Expand Down