Skip to content

Commit 529adea

Browse files
[ArrayManager] Add SingleArrayManager to back a Series (#40152)
1 parent 5dcaf49 commit 529adea

File tree

14 files changed

+265
-56
lines changed

14 files changed

+265
-56
lines changed

.github/workflows/ci.yml

+3
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ jobs:
165165
pytest pandas/tests/resample/
166166
pytest pandas/tests/reshape/merge
167167
168+
pytest pandas/tests/series/methods
169+
pytest pandas/tests/series/test_*
170+
168171
# indexing subset (temporary since other tests don't pass yet)
169172
pytest pandas/tests/frame/indexing/test_indexing.py::TestDataFrameIndexing::test_setitem_boolean
170173
pytest pandas/tests/frame/indexing/test_where.py

pandas/_typing.py

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
from pandas.core.internals import (
5959
ArrayManager,
6060
BlockManager,
61+
SingleArrayManager,
62+
SingleBlockManager,
6163
)
6264
from pandas.core.resample import Resampler
6365
from pandas.core.series import Series
@@ -184,3 +186,4 @@
184186

185187
# internals
186188
Manager = Union["ArrayManager", "BlockManager"]
189+
SingleManager = Union["SingleArrayManager", "SingleBlockManager"]

pandas/core/construction.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,6 @@ def sanitize_array(
481481
DataFrame constructor, as the dtype keyword there may be interpreted as only
482482
applying to a subset of columns, see GH#24435.
483483
"""
484-
485484
if isinstance(data, ma.MaskedArray):
486485
data = sanitize_masked_array(data)
487486

@@ -555,6 +554,7 @@ def sanitize_array(
555554
inferred = lib.infer_dtype(subarr, skipna=False)
556555
if inferred in {"interval", "period"}:
557556
subarr = array(subarr)
557+
subarr = extract_array(subarr, extract_numpy=True)
558558

559559
return subarr
560560

pandas/core/generic.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
from pandas.core.internals import (
139139
ArrayManager,
140140
BlockManager,
141+
SingleArrayManager,
141142
)
142143
from pandas.core.internals.construction import mgr_to_mgr
143144
from pandas.core.missing import find_valid_index
@@ -5563,7 +5564,7 @@ def _protect_consolidate(self, f):
55635564
Consolidate _mgr -- if the blocks have changed, then clear the
55645565
cache
55655566
"""
5566-
if isinstance(self._mgr, ArrayManager):
5567+
if isinstance(self._mgr, (ArrayManager, SingleArrayManager)):
55675568
return f()
55685569
blocks_before = len(self._mgr.blocks)
55695570
result = f()

pandas/core/groupby/generic.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,7 @@
108108
all_indexes_same,
109109
)
110110
import pandas.core.indexes.base as ibase
111-
from pandas.core.internals import (
112-
ArrayManager,
113-
BlockManager,
114-
)
111+
from pandas.core.internals import ArrayManager
115112
from pandas.core.series import Series
116113
from pandas.core.util.numba_ import maybe_use_numba
117114

@@ -1151,18 +1148,18 @@ def py_fallback(values: ArrayLike) -> ArrayLike:
11511148
# in the operation. We un-split here.
11521149
result = result._consolidate()
11531150
assert isinstance(result, (Series, DataFrame)) # for mypy
1151+
# unwrap DataFrame/Series to get array
11541152
mgr = result._mgr
1155-
assert isinstance(mgr, BlockManager)
1156-
1157-
# unwrap DataFrame to get array
1158-
if len(mgr.blocks) != 1:
1153+
arrays = mgr.arrays
1154+
if len(arrays) != 1:
11591155
# We've split an object block! Everything we've assumed
11601156
# about a single block input returning a single block output
11611157
# is a lie. See eg GH-39329
11621158
return mgr.as_array()
11631159
else:
1164-
result = mgr.blocks[0].values
1165-
return result
1160+
# We are a single block from a BlockManager
1161+
# or one array from SingleArrayManager
1162+
return arrays[0]
11661163

11671164
def array_func(values: ArrayLike) -> ArrayLike:
11681165

pandas/core/indexing.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,11 @@ def _setitem_with_indexer(self, indexer, value, name="iloc"):
15901590

15911591
# if there is only one block/type, still have to take split path
15921592
# unless the block is one-dimensional or it can hold the value
1593-
if not take_split_path and self.obj._mgr.blocks and self.ndim > 1:
1593+
if (
1594+
not take_split_path
1595+
and getattr(self.obj._mgr, "blocks", False)
1596+
and self.ndim > 1
1597+
):
15941598
# in case of dict, keys are indices
15951599
val = list(value.values()) if isinstance(value, dict) else value
15961600
blk = self.obj._mgr.blocks[0]

pandas/core/internals/__init__.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
from pandas.core.internals.array_manager import ArrayManager
2-
from pandas.core.internals.base import DataManager
1+
from pandas.core.internals.array_manager import (
2+
ArrayManager,
3+
SingleArrayManager,
4+
)
5+
from pandas.core.internals.base import (
6+
DataManager,
7+
SingleDataManager,
8+
)
39
from pandas.core.internals.blocks import ( # io.pytables, io.packers
410
Block,
511
CategoricalBlock,
@@ -34,7 +40,9 @@
3440
"DataManager",
3541
"ArrayManager",
3642
"BlockManager",
43+
"SingleDataManager",
3744
"SingleBlockManager",
45+
"SingleArrayManager",
3846
"concatenate_managers",
3947
# those two are preserved here for downstream compatibility (GH-33892)
4048
"create_block_manager_from_arrays",

0 commit comments

Comments
 (0)