Skip to content

REF: share DTA/TDA.__init__ #47583

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 1 commit into from
Jul 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
78 changes: 78 additions & 0 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
algos,
lib,
)
from pandas._libs.arrays import NDArrayBacked
from pandas._libs.tslibs import (
BaseOffset,
IncompatibleFrequency,
Expand Down Expand Up @@ -1906,6 +1907,81 @@ class TimelikeOps(DatetimeLikeArrayMixin):
Common ops for TimedeltaIndex/DatetimeIndex, but not PeriodIndex.
"""

_default_dtype: np.dtype

def __init__(self, values, dtype=None, freq=lib.no_default, copy: bool = False):
values = extract_array(values, extract_numpy=True)
if isinstance(values, IntegerArray):
values = values.to_numpy("int64", na_value=iNaT)

inferred_freq = getattr(values, "_freq", None)
explicit_none = freq is None
freq = freq if freq is not lib.no_default else None

if isinstance(values, type(self)):
if explicit_none:
# don't inherit from values
pass
elif freq is None:
freq = values.freq
elif freq and values.freq:
freq = to_offset(freq)
freq, _ = validate_inferred_freq(freq, values.freq, False)

if dtype is not None:
dtype = pandas_dtype(dtype)
if not is_dtype_equal(dtype, values.dtype):
# TODO: we only have tests for this for DTA, not TDA (2022-07-01)
raise TypeError(
f"dtype={dtype} does not match data dtype {values.dtype}"
)

dtype = values.dtype
values = values._ndarray

elif dtype is None:
dtype = self._default_dtype

if not isinstance(values, np.ndarray):
raise ValueError(
f"Unexpected type '{type(values).__name__}'. 'values' must be a "
f"{type(self).__name__}, ndarray, or Series or Index "
"containing one of those."
)
if values.ndim not in [1, 2]:
raise ValueError("Only 1-dimensional input arrays are supported.")

if values.dtype == "i8":
# for compat with datetime/timedelta/period shared methods,
# we can sometimes get here with int64 values. These represent
# nanosecond UTC (or tz-naive) unix timestamps
values = values.view(self._default_dtype)

dtype = self._validate_dtype(values, dtype)

if freq == "infer":
raise ValueError(
f"Frequency inference not allowed in {type(self).__name__}.__init__. "
"Use 'pd.array()' instead."
)

if copy:
values = values.copy()
if freq:
freq = to_offset(freq)

NDArrayBacked.__init__(self, values=values, dtype=dtype)
self._freq = freq

if inferred_freq is None and freq is not None:
type(self)._validate_frequency(self, freq)

@classmethod
def _validate_dtype(cls, values, dtype):
raise AbstractMethodError(cls)

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

@cache_readonly
def _reso(self) -> int:
return get_unit_from_dtype(self._ndarray.dtype)
Expand All @@ -1917,6 +1993,8 @@ def _unit(self) -> str:
# "ExtensionDtype"; expected "Union[DatetimeTZDtype, dtype[Any]]"
return dtype_to_unit(self.dtype) # type: ignore[arg-type]

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

def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs):
if (
ufunc in [np.isnan, np.isinf, np.isfinite]
Expand Down
75 changes: 5 additions & 70 deletions pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
lib,
tslib,
)
from pandas._libs.arrays import NDArrayBacked
from pandas._libs.tslibs import (
BaseOffset,
NaT,
Expand All @@ -30,7 +29,6 @@
fields,
get_resolution,
get_unit_from_dtype,
iNaT,
ints_to_pydatetime,
is_date_array_normalized,
is_unitless,
Expand Down Expand Up @@ -72,9 +70,7 @@

from pandas.core.arrays import datetimelike as dtl
from pandas.core.arrays._ranges import generate_regular_range
from pandas.core.arrays.integer import IntegerArray
import pandas.core.common as com
from pandas.core.construction import extract_array

from pandas.tseries.frequencies import get_period_alias
from pandas.tseries.offsets import (
Expand Down Expand Up @@ -254,75 +250,14 @@ def _scalar_type(self) -> type[Timestamp]:

_dtype: np.dtype | DatetimeTZDtype
_freq = None
_default_dtype = DT64NS_DTYPE # used in TimeLikeOps.__init__

def __init__(
self, values, dtype=None, freq=lib.no_default, copy: bool = False
) -> None:
values = extract_array(values, extract_numpy=True)
if isinstance(values, IntegerArray):
values = values.to_numpy("int64", na_value=iNaT)

inferred_freq = getattr(values, "_freq", None)
explicit_none = freq is None
freq = freq if freq is not lib.no_default else None

if isinstance(values, type(self)):
if explicit_none:
# don't inherit from values
pass
elif freq is None:
freq = values.freq
elif freq and values.freq:
freq = to_offset(freq)
freq, _ = dtl.validate_inferred_freq(freq, values.freq, False)

if dtype is not None:
dtype = pandas_dtype(dtype)
if not is_dtype_equal(dtype, values.dtype):
raise TypeError(
f"dtype={dtype} does not match data dtype {values.dtype}"
)

dtype = values.dtype
values = values._ndarray

elif dtype is None:
dtype = DT64NS_DTYPE

if not isinstance(values, np.ndarray):
raise ValueError(
f"Unexpected type '{type(values).__name__}'. 'values' must be a "
f"{type(self).__name__}, ndarray, or Series or Index "
"containing one of those."
)
if values.ndim not in [1, 2]:
raise ValueError("Only 1-dimensional input arrays are supported.")

if values.dtype == "i8":
# for compat with datetime/timedelta/period shared methods,
# we can sometimes get here with int64 values. These represent
# nanosecond UTC (or tz-naive) unix timestamps
values = values.view(DT64NS_DTYPE)

@classmethod
def _validate_dtype(cls, values, dtype):
# used in TimeLikeOps.__init__
_validate_dt64_dtype(values.dtype)
dtype = _validate_dt64_dtype(dtype)

if freq == "infer":
raise ValueError(
f"Frequency inference not allowed in {type(self).__name__}.__init__. "
"Use 'pd.array()' instead."
)

if copy:
values = values.copy()
if freq:
freq = to_offset(freq)

NDArrayBacked.__init__(self, values=values, dtype=dtype)
self._freq = freq

if inferred_freq is None and freq is not None:
type(self)._validate_frequency(self, freq)
return dtype

# error: Signature of "_simple_new" incompatible with supertype "NDArrayBacked"
@classmethod
Expand Down
67 changes: 6 additions & 61 deletions pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
lib,
tslibs,
)
from pandas._libs.arrays import NDArrayBacked
from pandas._libs.tslibs import (
BaseOffset,
NaT,
Expand Down Expand Up @@ -54,13 +53,9 @@
from pandas.core.dtypes.missing import isna

from pandas.core import nanops
from pandas.core.arrays import (
IntegerArray,
datetimelike as dtl,
)
from pandas.core.arrays import datetimelike as dtl
from pandas.core.arrays._ranges import generate_regular_range
import pandas.core.common as com
from pandas.core.construction import extract_array
from pandas.core.ops.common import unpack_zerodim_and_defer

if TYPE_CHECKING:
Expand Down Expand Up @@ -171,64 +166,14 @@ def dtype(self) -> np.dtype: # type: ignore[override]
# Constructors

_freq = None
_default_dtype = TD64NS_DTYPE # used in TimeLikeOps.__init__

def __init__(
self, values, dtype=TD64NS_DTYPE, freq=lib.no_default, copy: bool = False
) -> None:
values = extract_array(values, extract_numpy=True)
if isinstance(values, IntegerArray):
values = values.to_numpy("int64", na_value=tslibs.iNaT)

inferred_freq = getattr(values, "_freq", None)
explicit_none = freq is None
freq = freq if freq is not lib.no_default else None

if isinstance(values, type(self)):
if explicit_none:
# don't inherit from values
pass
elif freq is None:
freq = values.freq
elif freq and values.freq:
freq = to_offset(freq)
freq, _ = dtl.validate_inferred_freq(freq, values.freq, False)

values = values._ndarray

if not isinstance(values, np.ndarray):
raise ValueError(
f"Unexpected type '{type(values).__name__}'. 'values' must be a "
f"{type(self).__name__}, ndarray, or Series or Index "
"containing one of those."
)
if values.ndim not in [1, 2]:
raise ValueError("Only 1-dimensional input arrays are supported.")

if values.dtype == "i8":
# for compat with datetime/timedelta/period shared methods,
# we can sometimes get here with int64 values. These represent
# nanosecond UTC (or tz-naive) unix timestamps
values = values.view(TD64NS_DTYPE)

@classmethod
def _validate_dtype(cls, values, dtype):
# used in TimeLikeOps.__init__
_validate_td64_dtype(values.dtype)
dtype = _validate_td64_dtype(dtype)

if freq == "infer":
raise ValueError(
f"Frequency inference not allowed in {type(self).__name__}.__init__. "
"Use 'pd.array()' instead."
)

if copy:
values = values.copy()
if freq:
freq = to_offset(freq)

NDArrayBacked.__init__(self, values=values, dtype=dtype)
self._freq = freq

if inferred_freq is None and freq is not None:
type(self)._validate_frequency(self, freq)
return dtype

# error: Signature of "_simple_new" incompatible with supertype "NDArrayBacked"
@classmethod
Expand Down