8000 REF: Stop mixing DTA/TDA into DTI/TDI by jbrockmendel · Pull Request #24476 · pandas-dev/pandas · GitHub
[go: up one dir, main page]

Skip to content

REF: Stop mixing DTA/TDA into DTI/TDI #24476

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

Merged
merged 25 commits into from
Dec 29, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
350b0ec
implement _index_data parts of #24024
jbrockmendel Dec 21, 2018
837c16a
implement _eadata, dispatch arithmetic methods to it
jbrockmendel Dec 21, 2018
e28ff51
dont mix DatetimeLikeArrayMixin into DatetimeIndexOpsMixin
jbrockmendel Dec 21, 2018
ba61a0d
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 21, 2018
fdf1770
dont inherit TimedeltaIndex from TimedeltaArray
jbrockmendel Dec 21, 2018
ed9e1de
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 21, 2018
ea3965d
dont inherit from DatetimeArray
jbrockmendel Dec 22, 2018
8ceab31
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 22, 2018
5b95d78
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 24, 2018
60cd35d
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 24, 2018
bbbd778
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 28, 2018
238b386
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 28, 2018
9d01424
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 28, 2018
a5e5d65
use ea_passthrough
jbrockmendel Dec 28, 2018
8000
21833f3
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 28, 2018
1ff0c4d
remove previously-overriden overridings
jbrockmendel Dec 28, 2018
3faed22
stop double-mixing
jbrockmendel Dec 28, 2018
e607edd
stop over-writing
jbrockmendel Dec 28, 2018
38e4bca
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 28, 2018
2afd6ab
handle+test object arrays
jbrockmendel Dec 29, 2018
43a162e
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 29, 2018
9ddf4bd
Remove unused import
jbrockmendel Dec 29, 2018
11dcef0
flake8 fixup
jbrockmendel Dec 29, 2018
6627f56
Merge branch 'master' of https://github.com/pandas-dev/pandas into in…
jbrockmendel Dec 29, 2018
f6a8951
edits per comments
jbrockmendel Dec 29, 2018
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
Prev Previous commit
Next Next commit
dont inherit from DatetimeArray
  • Loading branch information
jbrockmendel committed Dec 22, 2018
commit ea3965d6406757aae714baf2d35c0d048635eed0
6 changes: 3 additions & 3 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ class DatelikeOps(object):

def strftime(self, date_format):
from pandas import Index
return Index(self.format(date_format=date_format),
dtype=compat.text_type)
return Index(self._format_native_types(date_format=date_format))
strftime.__doc__ = """
Convert to Index using specified date_format.

Expand Down Expand Up @@ -1263,7 +1262,8 @@ def _ensure_datetimelike_to_i8(other, to_utc=False):

if lib.is_scalar(other) and isna(other):
return iNaT
elif isinstance(other, (PeriodArray, ABCIndexClass)):
elif isinstance(other, (PeriodArray, ABCIndexClass,
DatetimeLikeArrayMixin)):
# convert tz if needed
if getattr(other, 'tz', None) is not None:
if to_utc:
Expand Down
16 changes: 15 additions & 1 deletion pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
is_datetime64tz_dtype, is_extension_type, is_float_dtype, is_int64_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.generic import ABCIndexClass, ABCSeries, ABCDataFrame
from pandas.core.dtypes.missing import isna

from pandas.core import ops
Expand Down Expand Up @@ -113,6 +113,8 @@ def wrapper(self, other):
elif lib.is_scalar(other):
return ops.invalid_comparison(self, other, op)
else:
# TODO: figure out why the is_object_dtpye check is needed,
# without we fail to raise on tzawareness_compat
if isinstance(other, list) or is_object_dtype(other):
try:
other = type(self)(other)
Expand Down Expand Up @@ -471,6 +473,18 @@ def _validate_fill_value(self, fill_value):
"Got '{got}'.".format(got=fill_value))
return fill_value

# -----------------------------------------------------------------
# Rendering Methods

def _format_native_types(self, na_rep=u'NaT', date_format=None, **kwargs):
from pandas.io.formats.format import _get_format_datetime64_from_values
fmt = _get_format_datetime64_from_values(self, date_forma 10000 t)

return tslib.format_array_from_datetime(self.asi8,
tz=self.tz,
format=fmt,
na_rep=na_rep)

# -----------------------------------------------------------------
# Comparison Methods

Expand Down
1 change: 1 addition & 0 deletions pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def _td_array_cmp(cls, op):
meth = getattr(dtl.DatetimeLikeArrayMixin, opname)

def wrapper(self, other):

if _is_convertible_to_td(other) or other is NaT:
try:
other = _to_m8(other)
Expand Down
127 changes: 115 additions & 12 deletions pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import pandas.core.dtypes.concat as _concat
from pandas.core.dtypes.missing import isna

from pandas.core.arrays import ExtensionOpsMixin
from pandas.core.arrays.datetimes import (
DatetimeArrayMixin as DatetimeArray, _to_m8)
from pandas.core.base import _shared_docs
Expand Down Expand Up @@ -61,7 +62,7 @@ def _new_DatetimeIndex(cls, d):
return result


class DatetimeIndex(DatetimeArray, DatetimeIndexOpsMixin, Int64Index):
class DatetimeIndex(DatetimeIndexOpsMixin, Int64Index, ExtensionOpsMixin):
"""
Immutable ndarray of datetime64 data, represented internally as int64, and
which can be boxed to Timestamp objects that are subclasses of datetime and
Expand Down Expand Up @@ -205,6 +206,7 @@ def _join_i8_wrapper(joinf, **kwargs):
_object_ops = DatetimeArray._object_ops
_field_ops = DatetimeArray._field_ops
_datetimelike_ops = DatetimeArray._datetimelike_ops
_datetimelike_methods = DatetimeArray._datetimelike_methods

# --------------------------------------------------------------------
# Constructors
Expand All @@ -227,11 +229,12 @@ def __new__(cls, data=None,
"endpoints is deprecated. Use "
"`pandas.date_range` instead.",
FutureWarning, stacklevel=2)
result = cls._generate_range(start, end, periods,
freq=freq, tz=tz, normalize=normalize,
closed=closed, ambiguous=ambiguous)
result.name = name
return result
dtarr = DatetimeArray._generate_range(
start, end, periods,
Copy link
Contributor

Choose a reason for hiding this comment

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

should the warning message actually be in DTA._generate_range?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, the non-deprecated way it gets called is via date_range

freq=freq, tz=tz, normalize=normalize,
closed=closed, ambiguous=ambiguous)
return cls._simple_new(
dtarr._data, freq=dtarr.freq, tz=dtarr.tz, name=name)

if is_scalar(data):
raise TypeError("{cls}() must be called with a "
Expand Down Expand Up @@ -267,7 +270,11 @@ def _simple_new(cls, values, name=None, freq=None, tz=None, dtype=None):
# DatetimeArray._simple_new will accept either i8 or M8[ns] dtypes
assert isinstance(values, np.ndarray), type(values)

result = super(DatetimeIndex, cls)._simple_new(values, freq, tz)
dtarr = DatetimeArray._simple_new(values, freq=freq, tz=tz)
result = object.__new__(cls)
result._data = dtarr._data
result._freq = dtarr.freq
result._tz = dtarr.tz
result.name = name
# For groupby perf. See note in indexes/base about _index_data
result._index_data = result._data
Expand All @@ -281,6 +288,10 @@ def _eadata(self):
return DatetimeArray._simple_new(self._data, tz=self.tz,
freq=self.freq)

@property
def dtype(self):
return self._eadata.dtype

@property
def _values(self):
# tz-naive -> ndarray
Expand All @@ -301,6 +312,8 @@ def tz(self, value):
raise AttributeError("Cannot directly set timezone. Use tz_localize() "
"or tz_convert() as appropriate")

tzinfo = tz

@property
def size(self):
# TODO: Remove this when we have a DatetimeTZArray
Expand Down Expand Up @@ -625,7 +638,7 @@ def astype(self, dtype, copy=True):
def _get_time_micros(self):
values = self.asi8
if self.tz is not None and not timezones.is_utc(self.tz):
values = self._local_timestamps()
values = self._eadata._local_timestamps()
return fields.get_time_micros(values)

def to_series(self, keep_tz=None, index=None, name=None):
Expand Down Expand Up @@ -1138,6 +1151,97 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None):
month_name = wrap_array_method(DatetimeArray.month_name, True)
day_name = wrap_array_method(DatetimeArray.day_name, True)

@property
def date(self):
return self._eadata.date

@property
def time(self):
return self._eadata.time

@property
def timetz(self):
return self._eadata.timetz

def strftime(self, date_format):
return self._eadata.strftime(date_format)

def round(self, freq, ambiguous='raise', nonexistent='raise'):
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like you can (maybe?) remove road, floor, and ciel. I haven't run the tests, but a manual example works.

They should be dispatched via DatetimeArray._datetimelike_methods.

Copy link
Member Author

Choose a reason for hiding this comment

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

excellent, I'll give it a shot

Copy link
Contributor

Choose a reason for hiding this comment

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

did this work out?

Copy link
Member Author

Choose a reason for hiding this comment

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

tentatively yes. we'll see if the CI agrees in a bit

Copy link
Member Author

Choose a reason for hiding this comment

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

yep

result = self._eadata.round(
freq, ambiguous=ambiguous, nonexistent=nonexistent)
return type(self)._simple_new(
result._data, freq=result.freq, tz=result.tz)

def floor(self, freq, ambiguous='raise', nonexistent='raise'):
result = self._eadata.floor(
freq, ambiguous=ambiguous, nonexistent=nonexistent)
return type(self)._simple_new(
result._data, freq=result.freq, tz=result.tz)

def ceil(self, freq, ambiguous='raise', nonexistent='raise'):
result = self._eadata.ceil(
freq, ambiguous=ambiguous, nonexistent=nonexistent)
return type(self)._simple_new(
result._data, freq=result.freq, tz=result.tz)

@property
def offset(self):
"""
get/set the frequency of the instance
"""
msg = ('{cls}.offset has been deprecated and will be removed '
'in a future version; use {cls}.freq instead.'
.format(cls=type(self).__name__))
warnings.warn(msg, FutureWarning, stacklevel=2)
return self.freq

@offset.setter
def offset(self, value):
"""
get/set the frequency of the instance
"""
msg = ('{cls}.offset has been deprecated and will be removed '
'in a future version; use {cls}.freq instead.'
.format(cls=type(self).__name__))
warnings.warn(msg, FutureWarning, stacklevel=2)
self.freq = value

@property
def freq(self):
return self._freq

@freq.setter
def freq(self, value):
if value is not None:
# let DatetimeArray to validation
self._eadata.freq = value

self._freq = to_offset(value)

def __getitem__(self, key):
Copy link
Contributor

Choose a reason for hiding this comment

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

In #24024 we move __getitem__ to the base DatetimeIndexOpsMixin and DatetimeArrayMixin. That seems relatively easy to do if we're already changing __getitem__ here and in TimedeltaIndex, but it may not be possible yet.

result = self._eadata.__getitem__(key)
if is_scalar(result):
return result
elif result.ndim > 1:
# To support MPL which performs slicing with 2 dim
# even though it only has 1 dim by definition
assert isinstance(result, np.ndarray), result
return result
return type(self)(result, name=self.name)

def _has_same_tz(self, other):
return self._eadata._has_same_tz(other)

@property
def _box_func(self):
return lambda x: Timestamp(x, tz=self.tz)

def __array__(self, dtype=None):
return self._eadata.__array__(dtype=dtype)

def to_pydatetime(self):
return self._eadata.to_pydatetime()

# --------------------------------------------------------------------

@Substitution(klass='DatetimeIndex')
Expand Down Expand Up @@ -1475,13 +1579,12 @@ def date_range(start=None, end=None, periods=None, freq=None, tz=None,
if freq is None and com._any_none(periods, start, end):
freq = 'D'

result = DatetimeIndex._generate_range(
dtarr = DatetimeArray._generate_range(
start=start, end=end, periods=periods,
freq=freq, tz=tz, normalize=normalize,
closed=closed, **kwargs)

result.name = name
return result
return DatetimeIndex._simple_new(
dtarr._data, tz=dtarr.tz, freq=dtarr.freq, name=name)


def bdate_range(start=None, end=None, periods=None, freq='B', tz=None,
Expand Down
0