Skip to content

BUG: raise on RangeIndex.array #40022

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 27 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3b265b0
BUG: raise on RangeIndex.array
jbrockmendel Feb 24, 2021
72ada03
Merge branch 'master' into util-extract_array
jbrockmendel Feb 24, 2021
be2d7fd
Merge branch 'master' into util-extract_array
jbrockmendel Feb 24, 2021
bd50f18
make RangeIndex check part of extract_array
jbrockmendel Feb 24, 2021
947231d
Merge branch 'master' into util-extract_array
jbrockmendel Feb 25, 2021
7037a46
Merge branch 'master' into util-extract_array
jbrockmendel Feb 26, 2021
92ccdfe
merge master
jbrockmendel Mar 3, 2021
9cc1225
Merge branch 'master' into util-extract_array
jbrockmendel Mar 4, 2021
31dc8fc
Merge branch 'master' into util-extract_array
jbrockmendel Mar 5, 2021
3dfbc08
Merge branch 'master' into util-extract_array
jbrockmendel Mar 8, 2021
6bf4a8f
restore RangeIndex.array
jbrockmendel Mar 8, 2021
c4882ac
Merge branch 'master' into util-extract_array
jbrockmendel Mar 8, 2021
bc7c628
troubleshoot ci
jbrockmendel Mar 8, 2021
c5977d6
Update pandas/core/construction.py
jbrockmendel Mar 8, 2021
ce578f6
Merge branch 'master' into util-extract_array
jbrockmendel Mar 8, 2021
217dd68
no longer need to skip array manager test
jbrockmendel Mar 8, 2021
5c24b75
flake8 fixup
jbrockmendel Mar 8, 2021
ae87afa
Merge branch 'master' into util-extract_array
jbrockmendel Mar 18, 2021
20bb6fc
mypy fixup
jbrockmendel Mar 18, 2021
9dcf5f4
revert xfail
jbrockmendel Mar 18, 2021
13c7c70
Merge branch 'master' into util-extract_array
jbrockmendel Mar 30, 2021
2caa121
Merge branch 'master' into util-extract_array
jbrockmendel Mar 31, 2021
7e05c61
Merge branch 'master' into util-extract_array
jbrockmendel Apr 1, 2021
190efa6
Merge branch 'master' into util-extract_array
jbrockmendel Apr 2, 2021
0eace12
Merge branch 'master' into util-extract_array
jbrockmendel Apr 2, 2021
b7d1e3d
Merge branch 'master' into util-extract_array
jbrockmendel Apr 3, 2021
e88503e
Merge branch 'master' into util-extract_array
jbrockmendel Apr 7, 2021
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
7 changes: 6 additions & 1 deletion pandas/_testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
)
from pandas.core.arrays import (
DatetimeArray,
PandasArray,
PeriodArray,
TimedeltaArray,
period_array,
Expand Down Expand Up @@ -204,7 +205,11 @@ def box_expected(expected, box_cls, transpose=True):
subclass of box_cls
"""
if box_cls is pd.array:
expected = pd.array(expected)
if isinstance(expected, RangeIndex):
# pd.array would return an IntegerArray
expected = PandasArray(np.asarray(expected._values))
else:
expected = pd.array(expected)
elif box_cls is Index:
expected = Index(expected)
elif box_cls is Series:
Expand Down
14 changes: 13 additions & 1 deletion pandas/core/construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
ABCExtensionArray,
ABCIndex,
ABCPandasArray,
ABCRangeIndex,
ABCSeries,
)
from pandas.core.dtypes.missing import isna
Expand Down Expand Up @@ -367,7 +368,9 @@ def array(
return PandasArray._from_sequence(data, dtype=dtype, copy=copy)


def extract_array(obj: object, extract_numpy: bool = False) -> Any | ArrayLike:
def extract_array(
obj: object, extract_numpy: bool = False, extract_range: bool = False
) -> Any | ArrayLike:
"""
Extract the ndarray or ExtensionArray from a Series or Index.

Expand All @@ -382,6 +385,10 @@ def extract_array(obj: object, extract_numpy: bool = False) -> Any | ArrayLike:
extract_numpy : bool, default False
Whether to extract the ndarray from a PandasArray

extract_range : bool, default False
If we have a RangeIndex, return range._values if True
(which is a materialized integer ndarray), otherwise return unchanged.

Returns
-------
arr : object
Expand Down Expand Up @@ -410,6 +417,11 @@ def extract_array(obj: object, extract_numpy: bool = False) -> Any | ArrayLike:
array([1, 2, 3])
"""
if isinstance(obj, (ABCIndex, ABCSeries)):
if isinstance(obj, ABCRangeIndex):
if extract_range:
return obj._values
return obj

obj = obj.array

if extract_numpy and isinstance(obj, ABCPandasArray):
Expand Down
12 changes: 9 additions & 3 deletions pandas/core/indexes/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,12 +528,17 @@ def argsort(self, *args, **kwargs) -> np.ndarray:
--------
numpy.ndarray.argsort
"""
ascending = kwargs.pop("ascending", True) # EA compat
nv.validate_argsort(args, kwargs)

if self._range.step > 0:
return np.arange(len(self))
result = np.arange(len(self))
else:
return np.arange(len(self) - 1, -1, -1)
result = np.arange(len(self) - 1, -1, -1)

if not ascending:
result = result[::-1]
return result

def factorize(
self, sort: bool = False, na_sentinel: int | None = -1
Expand Down Expand Up @@ -920,7 +925,8 @@ def _arith_method(self, other, op):
if op in [operator.mul, ops.rmul, operator.truediv, ops.rtruediv]:
step = op

other = extract_array(other, extract_numpy=True)
# TODO: if other is a RangeIndex we may have more efficient options
other = extract_array(other, extract_numpy=True, extract_range=True)
attrs = self._get_attributes_dict()

left, right = self, other
Expand Down
5 changes: 3 additions & 2 deletions pandas/core/reshape/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -2080,8 +2080,9 @@ def _factorize_keys(
(array([0, 1, 2]), array([0, 1]), 3)
"""
# Some pre-processing for non-ndarray lk / rk
lk = extract_array(lk, extract_numpy=True)
rk = extract_array(rk, extract_numpy=True)
lk = extract_array(lk, extract_numpy=True, extract_range=True)
rk = extract_array(rk, extract_numpy=True, extract_range=True)
# TODO: if either is a RangeIndex, we can likely factorize more efficiently?

if is_datetime64tz_dtype(lk.dtype) and is_datetime64tz_dtype(rk.dtype):
# Extract the ndarray (UTC-localized) values
Expand Down
7 changes: 4 additions & 3 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -5078,7 +5078,7 @@ def _cmp_method(self, other, op):
raise ValueError("Can only compare identically-labeled Series objects")

lvalues = self._values
rvalues = extract_array(other, extract_numpy=True)
rvalues = extract_array(other, extract_numpy=True, extract_range=True)

with np.errstate(all="ignore"):
res_values = ops.comparison_op(lvalues, rvalues, op)
Expand All @@ -5090,7 +5090,7 @@ def _logical_method(self, other, op):
self, other = ops.align_method_SERIES(self, other, align_asobject=True)

lvalues = self._values
rvalues = extract_array(other, extract_numpy=True)
rvalues = extract_array(other, extract_numpy=True, extract_range=True)

res_values = ops.logical_op(lvalues, rvalues, op)
return self._construct_result(res_values, name=res_name)
Expand All @@ -5100,7 +5100,8 @@ def _arith_method(self, other, op):
self, other = ops.align_method_SERIES(self, other)

lvalues = self._values
rvalues = extract_array(other, extract_numpy=True)
rvalues = extract_array(other, extract_numpy=True, extract_range=True)

with np.errstate(all="ignore"):
result = ops.arithmetic_op(lvalues, rvalues, op)

Expand Down
12 changes: 9 additions & 3 deletions pandas/core/sorting.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
ensure_platform_int,
is_extension_array_dtype,
)
from pandas.core.dtypes.generic import ABCMultiIndex
from pandas.core.dtypes.generic import (
ABCMultiIndex,
ABCRangeIndex,
)
from pandas.core.dtypes.missing import isna

from pandas.core.construction import extract_array
Expand Down Expand Up @@ -362,9 +365,12 @@ def nargsort(
mask=mask,
)

items = extract_array(items)
if isinstance(items, ABCRangeIndex):
return items.argsort(ascending=ascending) # TODO: test coverage with key?
Copy link
Contributor

Choose a reason for hiding this comment

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

hmm if you use extract_range on L376 i think you can just fall thru no? (or I guess need L380 to change), anyhow for the future

elif not isinstance(items, ABCMultiIndex):
items = extract_array(items)
if mask is None:
mask = np.asarray(isna(items))
mask = np.asarray(isna(items)) # TODO: does this exclude MultiIndex too?

if is_extension_array_dtype(items):
return items.argsort(ascending=ascending, kind=kind, na_position=na_position)
Expand Down
1 change: 1 addition & 0 deletions pandas/tests/arithmetic/test_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ def test_add_sub_datetimelike_invalid(self, numeric_idx, other, box_with_array):
"Concatenation operation is not implemented for NumPy arrays",
# pd.array vs np.datetime64 case
r"operand type\(s\) all returned NotImplemented from __array_ufunc__",
"can only perform ops with numeric values",
]
)
with pytest.raises(TypeError, match=msg):
Expand Down
Empty file.
18 changes: 18 additions & 0 deletions pandas/tests/construction/test_extract_array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from pandas import Index
import pandas._testing as tm
from pandas.core.construction import extract_array


def test_extract_array_rangeindex():
ri = Index(range(5))

expected = ri._values
res = extract_array(ri, extract_numpy=True, extract_range=True)
tm.assert_numpy_array_equal(res, expected)
res = extract_array(ri, extract_numpy=False, extract_range=True)
tm.assert_numpy_array_equal(res, expected)

res = extract_array(ri, extract_numpy=True, extract_range=False)
tm.assert_index_equal(res, ri)
res = extract_array(ri, extract_numpy=False, extract_range=False)
tm.assert_index_equal(res, ri)