Skip to content

Commit 49f09cc

Browse files
TomAugspurgerjorisvandenbossche
authored andcommitted
API: Added ExtensionArray constructor from scalars (pandas-dev#19913)
1 parent d30d165 commit 49f09cc

File tree

5 files changed

+41
-2
lines changed

5 files changed

+41
-2
lines changed

pandas/core/arrays/base.py

+20
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class ExtensionArray(object):
1818
The interface includes the following abstract methods that must be
1919
implemented by subclasses:
2020
21+
* _constructor_from_sequence
2122
* __getitem__
2223
* __len__
2324
* dtype
@@ -56,6 +57,25 @@ class ExtensionArray(object):
5657
# '_typ' is for pandas.core.dtypes.generic.ABCExtensionArray.
5758
# Don't override this.
5859
_typ = 'extension'
60+
61+
# ------------------------------------------------------------------------
62+
# Constructors
63+
# ------------------------------------------------------------------------
64+
@classmethod
65+
def _constructor_from_sequence(cls, scalars):
66+
"""Construct a new ExtensionArray from a sequence of scalars.
67+
68+
Parameters
69+
----------
70+
scalars : Sequence
71+
Each element will be an instance of the scalar type for this
72+
array, ``cls.dtype.type``.
73+
Returns
74+
-------
75+
ExtensionArray
76+
"""
77+
raise AbstractMethodError(cls)
78+
5979
# ------------------------------------------------------------------------
6080
# Must be a Sequence
6181
# ------------------------------------------------------------------------

pandas/core/arrays/categorical.py

+4
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ def __init__(self, values, categories=None, ordered=None, dtype=None,
364364
self._dtype = self._dtype.update_dtype(dtype)
365365
self._codes = coerce_indexer_dtype(codes, dtype.categories)
366366

367+
@classmethod
368+
def _constructor_from_sequence(cls, scalars):
369+
return cls(scalars)
370+
367371
@property
368372
def categories(self):
369373
"""The categories of this categorical.

pandas/tests/extension/base/constructors.py

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99

1010
class BaseConstructorsTests(BaseExtensionTests):
1111

12+
def test_array_from_scalars(self, data):
13+
scalars = [data[0], data[1], data[2]]
14+
result = data._constructor_from_sequence(scalars)
15+
assert isinstance(result, type(data))
16+
1217
def test_series_constructor(self, data):
1318
result = pd.Series(data)
1419
assert result.dtype == data.dtype

pandas/tests/extension/decimal/array.py

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ def __init__(self, values):
3232

3333
self.values = values
3434

35+
@classmethod
36+
def _constructor_from_sequence(cls, scalars):
37+
return cls(scalars)
38+
3539
def __getitem__(self, item):
3640
if isinstance(item, numbers.Integral):
3741
return self.values[item]

pandas/tests/extension/json/array.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,17 @@ def __init__(self, values):
3333
raise TypeError
3434
self.data = values
3535

36+
@classmethod
37+
def _constructor_from_sequence(cls, scalars):
38+
return cls(scalars)
39+
3640
def __getitem__(self, item):
3741
if isinstance(item, numbers.Integral):
3842
return self.data[item]
3943
elif isinstance(item, np.ndarray) and item.dtype == 'bool':
40-
return type(self)([x for x, m in zip(self, item) if m])
44+
return self._constructor_from_sequence([
45+
x for x, m in zip(self, item) if m
46+
])
4147
else:
4248
return type(self)(self.data[item])
4349

@@ -77,7 +83,7 @@ def isna(self):
7783
def take(self, indexer, allow_fill=True, fill_value=None):
7884
output = [self.data[loc] if loc != -1 else self._na_value
7985
for loc in indexer]
80-
return type(self)(output)
86+
return self._constructor_from_sequence(output)
8187

8288
def copy(self, deep=False):
8389
return type(self)(self.data[:])

0 commit comments

Comments
 (0)