From 4e1d77162a693c0b1d611e7284f0f73863ccce10 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Fri, 16 Dec 2022 21:38:51 +0000 Subject: [PATCH 1/6] CLN: clean IntervalArray._simple_new --- pandas/core/arrays/interval.py | 67 ++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 3c6686b5c0173..de79505cd20ba 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -232,9 +232,10 @@ def __new__( data = extract_array(data, extract_numpy=True) if isinstance(data, cls): - left = data._left - right = data._right + left: ArrayLike = data._left + right: ArrayLike = data._right closed = closed or data.closed + dtype = IntervalDtype(left.dtype, closed=closed) else: # don't allow scalars @@ -255,11 +256,13 @@ def __new__( right = lib.maybe_convert_objects(right) closed = closed or infer_closed + left, right, dtype = cls._ensure_simple_new_inputs( + left, right, closed=closed, copy=copy, dtype=dtype + ) + return cls._simple_new( left, right, - closed, - copy=copy, dtype=dtype, verify_integrity=verify_integrity, ) @@ -269,23 +272,39 @@ def _simple_new( cls: type[IntervalArrayT], left, right, - closed: IntervalClosedType | None = None, - copy: bool = False, - dtype: Dtype | None = None, + dtype: IntervalDtype, verify_integrity: bool = True, ) -> IntervalArrayT: result = IntervalMixin.__new__(cls) + result._left = left + result._right = right + result._dtype = dtype - if closed is None and isinstance(dtype, IntervalDtype): - closed = dtype.closed + if verify_integrity: + result._validate() - closed = closed or "right" + return result + @classmethod + def _ensure_simple_new_inputs( + cls, + left, + right, + closed: IntervalClosedType | None = None, + copy: bool = False, + dtype: Dtype | None = None, + ) -> tuple[ArrayLike, ArrayLike, IntervalDtype]: + """Ensure correctness of input parameters for cls._simple_new.""" from pandas.core.indexes.base import ensure_index left = ensure_index(left, copy=copy) right = ensure_index(right, copy=copy) + if closed is None and isinstance(dtype, IntervalDtype): + closed = dtype.closed + + closed = closed or "right" + if dtype is not None: # GH 19262: dtype must be an IntervalDtype to override inferred dtype = pandas_dtype(dtype) @@ -346,13 +365,8 @@ def _simple_new( right = right.copy() dtype = IntervalDtype(left.dtype, closed=closed) - result._dtype = dtype - result._left = left - result._right = right - if verify_integrity: - result._validate() - return result + return left, right, dtype @classmethod def _from_sequence( @@ -512,10 +526,12 @@ def from_arrays( left = _maybe_convert_platform_interval(left) right = _maybe_convert_platform_interval(right) - return cls._simple_new( - left, right, closed, copy=copy, dtype=dtype, verify_integrity=True + left, right, dtype = cls._ensure_simple_new_inputs( + left, right, closed=closed, copy=copy, dtype=dtype ) + return cls._simple_new(left, right, dtype=dtype, verify_integrity=True) + _interval_shared_docs["from_tuples"] = textwrap.dedent( """ Construct an %(klass)s from an array-like of tuples. @@ -639,7 +655,9 @@ def _shallow_copy(self: IntervalArrayT, left, right) -> IntervalArrayT: right : Index Values to be used for the right-side of the intervals. """ - return self._simple_new(left, right, closed=self.closed, verify_integrity=False) + dtype = IntervalDtype(left.dtype, closed=self.closed) + left, right, dtype = self._ensure_simple_new_inputs(left, right, dtype=dtype) + return self._simple_new(left, right, dtype=dtype, verify_integrity=False) # --------------------------------------------------------------------- # Descriptive @@ -986,7 +1004,10 @@ def _concat_same_type( left = np.concatenate([interval.left for interval in to_concat]) right = np.concatenate([interval.right for interval in to_concat]) - return cls._simple_new(left, right, closed=closed, copy=False) + + left, right, dtype = cls._ensure_simple_new_inputs(left, right, closed=closed) + + return cls._simple_new(left, right, dtype=dtype) def copy(self: IntervalArrayT) -> IntervalArrayT: """ @@ -1400,9 +1421,9 @@ def set_closed(self: IntervalArrayT, closed: IntervalClosedType) -> IntervalArra msg = f"invalid option for 'closed': {closed}" raise ValueError(msg) - return type(self)._simple_new( - left=self._left, right=self._right, closed=closed, verify_integrity=False - ) + left, right = self._left, self._right + dtype = IntervalDtype(left.dtype, closed=closed) + return self._simple_new(left, right, dtype=dtype, verify_integrity=False) _interval_shared_docs[ "is_non_overlapping_monotonic" From 9bc7316c39045aafd8886a9995d6522ec80cef60 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Tue, 20 Dec 2022 21:41:52 +0000 Subject: [PATCH 2/6] extract ._validate from ._simple_new --- pandas/core/arrays/interval.py | 51 ++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index de79505cd20ba..41adecb370382 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -257,14 +257,20 @@ def __new__( closed = closed or infer_closed left, right, dtype = cls._ensure_simple_new_inputs( - left, right, closed=closed, copy=copy, dtype=dtype + left, + right, + closed=closed, + copy=copy, + dtype=dtype, ) + if verify_integrity: + cls._validate(left, right, dtype=dtype) + return cls._simple_new( left, right, dtype=dtype, - verify_integrity=verify_integrity, ) @classmethod @@ -273,16 +279,12 @@ def _simple_new( left, right, dtype: IntervalDtype, - verify_integrity: bool = True, ) -> IntervalArrayT: result = IntervalMixin.__new__(cls) result._left = left result._right = right result._dtype = dtype - if verify_integrity: - result._validate() - return result @classmethod @@ -527,10 +529,15 @@ def from_arrays( right = _maybe_convert_platform_interval(right) left, right, dtype = cls._ensure_simple_new_inputs( - left, right, closed=closed, copy=copy, dtype=dtype + left, + right, + closed=closed, + copy=copy, + dtype=dtype, ) + cls._validate(left, right, dtype=dtype) - return cls._simple_new(left, right, dtype=dtype, verify_integrity=True) + return cls._simple_new(left, right, dtype=dtype) _interval_shared_docs["from_tuples"] = textwrap.dedent( """ @@ -615,32 +622,33 @@ def from_tuples( return cls.from_arrays(left, right, closed, copy=False, dtype=dtype) - def _validate(self): + @classmethod + def _validate(cls, left, right, dtype: IntervalDtype) -> None: """ Verify that the IntervalArray is valid. Checks that - * closed is valid + * dtype is correct * left and right match lengths * left and right have the same missing values * left is always below right """ - if self.closed not in VALID_CLOSED: - msg = f"invalid option for 'closed': {self.closed}" + if not isinstance(dtype, IntervalDtype): + msg = f"invalid dtype: {dtype}" raise ValueError(msg) - if len(self._left) != len(self._right): + if len(left) != len(right): msg = "left and right must have the same length" raise ValueError(msg) - left_mask = notna(self._left) - right_mask = notna(self._right) + left_mask = notna(left) + right_mask = notna(right) if not (left_mask == right_mask).all(): msg = ( "missing values must be missing in the same " "location both left and right sides" ) raise ValueError(msg) - if not (self._left[left_mask] <= self._right[left_mask]).all(): + if not (left[left_mask] <= right[left_mask]).all(): msg = "left side of interval must be <= right side" raise ValueError(msg) @@ -657,7 +665,9 @@ def _shallow_copy(self: IntervalArrayT, left, right) -> IntervalArrayT: """ dtype = IntervalDtype(left.dtype, closed=self.closed) left, right, dtype = self._ensure_simple_new_inputs(left, right, dtype=dtype) - return self._simple_new(left, right, dtype=dtype, verify_integrity=False) + self._validate(left, right, dtype=dtype) + + return self._simple_new(left, right, dtype=dtype) # --------------------------------------------------------------------- # Descriptive @@ -1019,9 +1029,8 @@ def copy(self: IntervalArrayT) -> IntervalArrayT: """ left = self._left.copy() right = self._right.copy() - closed = self.closed - # TODO: Could skip verify_integrity here. - return type(self).from_arrays(left, right, closed=closed) + dtype = self.dtype + return self._simple_new(left, right, dtype=dtype) def isna(self) -> np.ndarray: return isna(self._left) @@ -1423,7 +1432,7 @@ def set_closed(self: IntervalArrayT, closed: IntervalClosedType) -> IntervalArra left, right = self._left, self._right dtype = IntervalDtype(left.dtype, closed=closed) - return self._simple_new(left, right, dtype=dtype, verify_integrity=False) + return self._simple_new(left, right, dtype=dtype) _interval_shared_docs[ "is_non_overlapping_monotonic" From f625c189b33b69150b95a8e3f053ec6e769a096e Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Thu, 22 Dec 2022 18:36:36 +0000 Subject: [PATCH 3/6] add typing to IntervalArray._left/_right --- pandas/core/arrays/interval.py | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 41adecb370382..c86589cf00a2f 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -213,8 +213,8 @@ def ndim(self) -> Literal[1]: return 1 # To make mypy recognize the fields - _left: np.ndarray - _right: np.ndarray + _left: ArrayLike + _right: ArrayLike _dtype: IntervalDtype # --------------------------------------------------------------------- @@ -714,7 +714,7 @@ def __getitem__( if is_scalar(left) and isna(left): return self._fill_value return Interval(left, right, self.closed) - if np.ndim(left) > 1: + if np.ndim(left) > 1: # type: ignore[arg-type] # GH#30588 multi-dimensional indexer disallowed raise ValueError("multi-dimensional indexing not allowed") return self._shallow_copy(left, right) @@ -1456,15 +1456,15 @@ def is_non_overlapping_monotonic(self) -> bool: # at a point when both sides of intervals are included if self.closed == "both": return bool( - (self._right[:-1] < self._left[1:]).all() - or (self._left[:-1] > self._right[1:]).all() + (self._right[:-1] < self._left[1:]).all() # type: ignore[operator] + or (self._left[:-1] > self._right[1:]).all() # type: ignore[operator] ) # non-strict inequality when closed != 'both'; at least one side is # not included in the intervals, so equality does not imply overlapping return bool( - (self._right[:-1] <= self._left[1:]).all() - or (self._left[:-1] >= self._right[1:]).all() + (self._right[:-1] <= self._left[1:]).all() # type: ignore[operator] + or (self._left[:-1] >= self._right[1:]).all() # type: ignore[operator] ) # --------------------------------------------------------------------- @@ -1574,9 +1574,11 @@ def _putmask(self, mask: npt.NDArray[np.bool_], value) -> None: if isinstance(self._left, np.ndarray): np.putmask(self._left, mask, value_left) + assert isinstance(self._right, np.ndarray) np.putmask(self._right, mask, value_right) else: self._left._putmask(mask, value_left) + assert isinstance(self._right, ExtensionArray) self._right._putmask(mask, value_right) def insert(self: IntervalArrayT, loc: int, item: Interval) -> IntervalArrayT: @@ -1603,10 +1605,12 @@ def insert(self: IntervalArrayT, loc: int, item: Interval) -> IntervalArrayT: def delete(self: IntervalArrayT, loc) -> IntervalArrayT: if isinstance(self._left, np.ndarray): - new_left = np.delete(self._left, loc) - new_right = np.delete(self._right, loc) + new_left: ArrayLike = np.delete(self._left, loc) + assert isinstance(self._right, np.ndarray) + new_right: ArrayLike = np.delete(self._right, loc) else: new_left = self._left.delete(loc) + assert isinstance(self._right, ExtensionArray) new_right = self._right.delete(loc) return self._shallow_copy(left=new_left, right=new_right) @@ -1724,17 +1728,13 @@ def _from_combined(self, combined: np.ndarray) -> IntervalArray: dtype = self._left.dtype if needs_i8_conversion(dtype): - # error: "Type[ndarray[Any, Any]]" has no attribute "_from_sequence" - new_left = type(self._left)._from_sequence( # type: ignore[attr-defined] - nc[:, 0], dtype=dtype - ) - # error: "Type[ndarray[Any, Any]]" has no attribute "_from_sequence" - new_right = type(self._right)._from_sequence( # type: ignore[attr-defined] - nc[:, 1], dtype=dtype - ) + assert isinstance(self._left, ExtensionArray) + new_left = type(self._left)._from_sequence(nc[:, 0], dtype=dtype) + assert isinstance(self._right, ExtensionArray) + new_right = type(self._right)._from_sequence(nc[:, 1], dtype=dtype) else: - new_left = nc[:, 0].view(dtype) - new_right = nc[:, 1].view(dtype) + new_left = nc[:, 0].view(dtype) # type: ignore[arg-type] + new_right = nc[:, 1].view(dtype) # type: ignore[arg-type] return self._shallow_copy(left=new_left, right=new_right) def unique(self) -> IntervalArray: From 813b1c19e46338ea2fb347e0d195a6fdafba1cce Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Fri, 23 Dec 2022 17:44:02 +0000 Subject: [PATCH 4/6] Revert "add typing to IntervalArray._left/_right" This reverts commit c99c28fb520d2b736eeef085720ac6d2435c855c. --- pandas/core/arrays/interval.py | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index c86589cf00a2f..41adecb370382 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -213,8 +213,8 @@ def ndim(self) -> Literal[1]: return 1 # To make mypy recognize the fields - _left: ArrayLike - _right: ArrayLike + _left: np.ndarray + _right: np.ndarray _dtype: IntervalDtype # --------------------------------------------------------------------- @@ -714,7 +714,7 @@ def __getitem__( if is_scalar(left) and isna(left): return self._fill_value return Interval(left, right, self.closed) - if np.ndim(left) > 1: # type: ignore[arg-type] + if np.ndim(left) > 1: # GH#30588 multi-dimensional indexer disallowed raise ValueError("multi-dimensional indexing not allowed") return self._shallow_copy(left, right) @@ -1456,15 +1456,15 @@ def is_non_overlapping_monotonic(self) -> bool: # at a point when both sides of intervals are included if self.closed == "both": return bool( - (self._right[:-1] < self._left[1:]).all() # type: ignore[operator] - or (self._left[:-1] > self._right[1:]).all() # type: ignore[operator] + (self._right[:-1] < self._left[1:]).all() + or (self._left[:-1] > self._right[1:]).all() ) # non-strict inequality when closed != 'both'; at least one side is # not included in the intervals, so equality does not imply overlapping return bool( - (self._right[:-1] <= self._left[1:]).all() # type: ignore[operator] - or (self._left[:-1] >= self._right[1:]).all() # type: ignore[operator] + (self._right[:-1] <= self._left[1:]).all() + or (self._left[:-1] >= self._right[1:]).all() ) # --------------------------------------------------------------------- @@ -1574,11 +1574,9 @@ def _putmask(self, mask: npt.NDArray[np.bool_], value) -> None: if isinstance(self._left, np.ndarray): np.putmask(self._left, mask, value_left) - assert isinstance(self._right, np.ndarray) np.putmask(self._right, mask, value_right) else: self._left._putmask(mask, value_left) - assert isinstance(self._right, ExtensionArray) self._right._putmask(mask, value_right) def insert(self: IntervalArrayT, loc: int, item: Interval) -> IntervalArrayT: @@ -1605,12 +1603,10 @@ def insert(self: IntervalArrayT, loc: int, item: Interval) -> IntervalArrayT: def delete(self: IntervalArrayT, loc) -> IntervalArrayT: if isinstance(self._left, np.ndarray): - new_left: ArrayLike = np.delete(self._left, loc) - assert isinstance(self._right, np.ndarray) - new_right: ArrayLike = np.delete(self._right, loc) + new_left = np.delete(self._left, loc) + new_right = np.delete(self._right, loc) else: new_left = self._left.delete(loc) - assert isinstance(self._right, ExtensionArray) new_right = self._right.delete(loc) return self._shallow_copy(left=new_left, right=new_right) @@ -1728,13 +1724,17 @@ def _from_combined(self, combined: np.ndarray) -> IntervalArray: dtype = self._left.dtype if needs_i8_conversion(dtype): - assert isinstance(self._left, ExtensionArray) - new_left = type(self._left)._from_sequence(nc[:, 0], dtype=dtype) - assert isinstance(self._right, ExtensionArray) - new_right = type(self._right)._from_sequence(nc[:, 1], dtype=dtype) + # error: "Type[ndarray[Any, Any]]" has no attribute "_from_sequence" + new_left = type(self._left)._from_sequence( # type: ignore[attr-defined] + nc[:, 0], dtype=dtype + ) + # error: "Type[ndarray[Any, Any]]" has no attribute "_from_sequence" + new_right = type(self._right)._from_sequence( # type: ignore[attr-defined] + nc[:, 1], dtype=dtype + ) else: - new_left = nc[:, 0].view(dtype) # type: ignore[arg-type] - new_right = nc[:, 1].view(dtype) # type: ignore[arg-type] + new_left = nc[:, 0].view(dtype) + new_right = nc[:, 1].view(dtype) return self._shallow_copy(left=new_left, right=new_right) def unique(self) -> IntervalArray: From fa05be4ab26464bed5d57f9ae820b43357332a2c Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Mon, 26 Dec 2022 08:20:16 +0000 Subject: [PATCH 5/6] add typing to IntervalArray._left/_right, II --- pandas/_typing.py | 5 +++++ pandas/core/arrays/interval.py | 41 +++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/pandas/_typing.py b/pandas/_typing.py index 1ba5be8b5b0ed..8d3044a978291 100644 --- a/pandas/_typing.py +++ b/pandas/_typing.py @@ -44,6 +44,10 @@ from pandas.core.dtypes.dtypes import ExtensionDtype from pandas import Interval + from pandas.arrays import ( + DatetimeArray, + TimedeltaArray, + ) from pandas.core.arrays.base import ExtensionArray from pandas.core.frame import DataFrame from pandas.core.generic import NDFrame @@ -88,6 +92,7 @@ ArrayLike = Union["ExtensionArray", np.ndarray] AnyArrayLike = Union[ArrayLike, "Index", "Series"] +TimeArrayLike = Union["DatetimeArray", "TimedeltaArray"] # scalars diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 41adecb370382..9ead8f2cf0895 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -39,6 +39,7 @@ ScalarIndexer, SequenceIndexer, SortKind, + TimeArrayLike, npt, ) from pandas.compat.numpy import function as nv @@ -78,6 +79,8 @@ unique, value_counts, ) +from pandas.core.arrays.datetimes import DatetimeArray +from pandas.core.arrays.timedeltas import TimedeltaArray from pandas.core.arrays.base import ( ExtensionArray, _extension_array_shared_docs, @@ -102,6 +105,7 @@ IntervalArrayT = TypeVar("IntervalArrayT", bound="IntervalArray") +IntervalSideT = Union[TimeArrayLike, np.ndarray] IntervalOrNA = Union[Interval, float] _interval_shared_docs: dict[str, str] = {} @@ -123,8 +127,8 @@ Parameters ---------- data : array-like (1-dimensional) - Array-like containing Interval objects from which to build the - %(klass)s. + Array-like (ndarray, :class:`DateTimeArray`, :class:`TimeDeltaArray`) containing + Interval objects from which to build the %(klass)s. closed : {'left', 'right', 'both', 'neither'}, default 'right' Whether the intervals are closed on the left-side, right-side, both or neither. @@ -213,8 +217,8 @@ def ndim(self) -> Literal[1]: return 1 # To make mypy recognize the fields - _left: np.ndarray - _right: np.ndarray + _left: IntervalSideT + _right: IntervalSideT _dtype: IntervalDtype # --------------------------------------------------------------------- @@ -232,8 +236,8 @@ def __new__( data = extract_array(data, extract_numpy=True) if isinstance(data, cls): - left: ArrayLike = data._left - right: ArrayLike = data._right + left: IntervalSideT = data._left + right: IntervalSideT = data._right closed = closed or data.closed dtype = IntervalDtype(left.dtype, closed=closed) else: @@ -276,8 +280,8 @@ def __new__( @classmethod def _simple_new( cls: type[IntervalArrayT], - left, - right, + left: IntervalSideT, + right: IntervalSideT, dtype: IntervalDtype, ) -> IntervalArrayT: result = IntervalMixin.__new__(cls) @@ -295,7 +299,7 @@ def _ensure_simple_new_inputs( closed: IntervalClosedType | None = None, copy: bool = False, dtype: Dtype | None = None, - ) -> tuple[ArrayLike, ArrayLike, IntervalDtype]: + ) -> tuple[IntervalSideT, IntervalSideT, IntervalDtype]: """Ensure correctness of input parameters for cls._simple_new.""" from pandas.core.indexes.base import ensure_index @@ -1574,9 +1578,11 @@ def _putmask(self, mask: npt.NDArray[np.bool_], value) -> None: if isinstance(self._left, np.ndarray): np.putmask(self._left, mask, value_left) + assert isinstance(self._right, np.ndarray) np.putmask(self._right, mask, value_right) else: self._left._putmask(mask, value_left) + assert not isinstance(self._right, np.ndarray) self._right._putmask(mask, value_right) def insert(self: IntervalArrayT, loc: int, item: Interval) -> IntervalArrayT: @@ -1604,9 +1610,11 @@ def insert(self: IntervalArrayT, loc: int, item: Interval) -> IntervalArrayT: def delete(self: IntervalArrayT, loc) -> IntervalArrayT: if isinstance(self._left, np.ndarray): new_left = np.delete(self._left, loc) + assert isinstance(self._right, np.ndarray) new_right = np.delete(self._right, loc) else: new_left = self._left.delete(loc) + assert not isinstance(self._right, np.ndarray) new_right = self._right.delete(loc) return self._shallow_copy(left=new_left, right=new_right) @@ -1707,7 +1715,7 @@ def isin(self, values) -> npt.NDArray[np.bool_]: return isin(self.astype(object), values.astype(object)) @property - def _combined(self) -> ArrayLike: + def _combined(self) -> IntervalSideT: left = self.left._values.reshape(-1, 1) right = self.right._values.reshape(-1, 1) if needs_i8_conversion(left.dtype): @@ -1724,15 +1732,12 @@ def _from_combined(self, combined: np.ndarray) -> IntervalArray: dtype = self._left.dtype if needs_i8_conversion(dtype): - # error: "Type[ndarray[Any, Any]]" has no attribute "_from_sequence" - new_left = type(self._left)._from_sequence( # type: ignore[attr-defined] - nc[:, 0], dtype=dtype - ) - # error: "Type[ndarray[Any, Any]]" has no attribute "_from_sequence" - new_right = type(self._right)._from_sequence( # type: ignore[attr-defined] - nc[:, 1], dtype=dtype - ) + assert isinstance(self._left, (DatetimeArray, TimedeltaArray)) + new_left = type(self._left)._from_sequence(nc[:, 0], dtype=dtype) + assert isinstance(self._right, (DatetimeArray, TimedeltaArray)) + new_right = type(self._right)._from_sequence(nc[:, 1], dtype=dtype) else: + assert isinstance(dtype, np.dtype) new_left = nc[:, 0].view(dtype) new_right = nc[:, 1].view(dtype) return self._shallow_copy(left=new_left, right=new_right) From 746bf29b337f94b545785196402111fedfef2f74 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Mon, 26 Dec 2022 08:57:18 +0000 Subject: [PATCH 6/6] fix isort --- pandas/core/arrays/interval.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 9ead8f2cf0895..cc72e7a290f62 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -79,12 +79,12 @@ unique, value_counts, ) -from pandas.core.arrays.datetimes import DatetimeArray -from pandas.core.arrays.timedeltas import TimedeltaArray from pandas.core.arrays.base import ( ExtensionArray, _extension_array_shared_docs, ) +from pandas.core.arrays.datetimes import DatetimeArray +from pandas.core.arrays.timedeltas import TimedeltaArray import pandas.core.common as com from pandas.core.construction import ( array as pd_array,