Skip to content

Commit b8ee1e1

Browse files
authored
TYP: enforce annotation on SingleBlockManager.__init__ (#32421)
1 parent 8c38283 commit b8ee1e1

File tree

3 files changed

+56
-48
lines changed

3 files changed

+56
-48
lines changed

pandas/core/internals/managers.py

+51-44
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import itertools
44
import operator
55
import re
6-
from typing import Dict, List, Optional, Sequence, Tuple, Union
6+
from typing import Dict, List, Optional, Sequence, Tuple, TypeVar, Union
77

88
import numpy as np
99

1010
from pandas._libs import Timedelta, Timestamp, internals as libinternals, lib
11-
from pandas._typing import DtypeObj, Label
11+
from pandas._typing import ArrayLike, DtypeObj, Label
1212
from pandas.util._validators import validate_bool_kwarg
1313

1414
from pandas.core.dtypes.cast import (
@@ -58,6 +58,8 @@
5858

5959
# TODO: flexible with index=None and/or items=None
6060

61+
T = TypeVar("T", bound="BlockManager")
62+
6163

6264
class BlockManager(PandasObject):
6365
"""
@@ -149,6 +151,13 @@ def __init__(
149151
self._blknos = None
150152
self._blklocs = None
151153

154+
@classmethod
155+
def from_blocks(cls, blocks: List[Block], axes: List[Index]):
156+
"""
157+
Constructor for BlockManager and SingleBlockManager with same signature.
158+
"""
159+
return cls(blocks, axes, do_integrity_check=False)
160+
152161
@property
153162
def blknos(self):
154163
"""
@@ -176,18 +185,19 @@ def blklocs(self):
176185

177186
return self._blklocs
178187

179-
def make_empty(self, axes=None) -> "BlockManager":
188+
def make_empty(self: T, axes=None) -> T:
180189
""" return an empty BlockManager with the items axis of len 0 """
181190
if axes is None:
182191
axes = [Index([])] + self.axes[1:]
183192

184193
# preserve dtype if possible
185194
if self.ndim == 1:
186195
assert isinstance(self, SingleBlockManager) # for mypy
187-
blocks = np.array([], dtype=self.array_dtype)
196+
arr = np.array([], dtype=self.array_dtype)
197+
blocks = [make_block(arr, placement=slice(0, 0), ndim=1)]
188198
else:
189199
blocks = []
190-
return type(self)(blocks, axes)
200+
return type(self).from_blocks(blocks, axes)
191201

192202
def __nonzero__(self) -> bool:
193203
return True
@@ -380,7 +390,7 @@ def reduce(self, func, *args, **kwargs):
380390

381391
return res
382392

383-
def apply(self, f, filter=None, **kwargs) -> "BlockManager":
393+
def apply(self: T, f, filter=None, **kwargs) -> T:
384394
"""
385395
Iterate over the blocks, collect and create a new BlockManager.
386396
@@ -458,8 +468,8 @@ def apply(self, f, filter=None, **kwargs) -> "BlockManager":
458468

459469
if len(result_blocks) == 0:
460470
return self.make_empty(self.axes)
461-
bm = type(self)(result_blocks, self.axes, do_integrity_check=False)
462-
return bm
471+
472+
return type(self).from_blocks(result_blocks, self.axes)
463473

464474
def quantile(
465475
self,
@@ -658,7 +668,7 @@ def comp(s, regex=False):
658668
rb = new_rb
659669
result_blocks.extend(rb)
660670

661-
bm = type(self)(result_blocks, self.axes)
671+
bm = type(self).from_blocks(result_blocks, self.axes)
662672
bm._consolidate_inplace()
663673
return bm
664674

@@ -747,7 +757,7 @@ def combine(self, blocks: List[Block], copy: bool = True) -> "BlockManager":
747757
axes = list(self.axes)
748758
axes[0] = self.items.take(indexer)
749759

750-
return type(self)(new_blocks, axes, do_integrity_check=False)
760+
return type(self).from_blocks(new_blocks, axes)
751761

752762
def get_slice(self, slobj: slice, axis: int = 0) -> "BlockManager":
753763

@@ -774,7 +784,7 @@ def __contains__(self, item) -> bool:
774784
def nblocks(self) -> int:
775785
return len(self.blocks)
776786

777-
def copy(self, deep=True) -> "BlockManager":
787+
def copy(self: T, deep=True) -> T:
778788
"""
779789
Make deep or shallow copy of BlockManager
780790
@@ -1244,14 +1254,14 @@ def reindex_axis(
12441254
)
12451255

12461256
def reindex_indexer(
1247-
self,
1257+
self: T,
12481258
new_axis,
12491259
indexer,
12501260
axis: int,
12511261
fill_value=None,
1252-
allow_dups=False,
1262+
allow_dups: bool = False,
12531263
copy: bool = True,
1254-
):
1264+
) -> T:
12551265
"""
12561266
Parameters
12571267
----------
@@ -1299,7 +1309,8 @@ def reindex_indexer(
12991309

13001310
new_axes = list(self.axes)
13011311
new_axes[axis] = new_axis
1302-
return type(self)(new_blocks, new_axes)
1312+
1313+
return type(self).from_blocks(new_blocks, new_axes)
13031314

13041315
def _slice_take_blocks_ax0(self, slice_or_indexer, fill_tuple=None):
13051316
"""
@@ -1500,6 +1511,8 @@ def __init__(
15001511
do_integrity_check: bool = False,
15011512
fastpath: bool = False,
15021513
):
1514+
assert isinstance(block, Block), type(block)
1515+
15031516
if isinstance(axis, list):
15041517
if len(axis) != 1:
15051518
raise ValueError(
@@ -1510,38 +1523,29 @@ def __init__(
15101523
# passed from constructor, single block, single axis
15111524
if fastpath:
15121525
self.axes = [axis]
1513-
if isinstance(block, list):
1514-
1515-
# empty block
1516-
if len(block) == 0:
1517-
block = [np.array([])]
1518-
elif len(block) != 1:
1519-
raise ValueError(
1520-
"Cannot create SingleBlockManager with more than 1 block"
1521-
)
1522-
block = block[0]
15231526
else:
15241527
self.axes = [ensure_index(axis)]
15251528

1526-
# create the block here
1527-
if isinstance(block, list):
1528-
1529-
# provide consolidation to the interleaved_dtype
1530-
if len(block) > 1:
1531-
dtype = _interleaved_dtype(block)
1532-
block = [b.astype(dtype) for b in block]
1533-
block = _consolidate(block)
1534-
1535-
if len(block) != 1:
1536-
raise ValueError(
1537-
"Cannot create SingleBlockManager with more than 1 block"
1538-
)
1539-
block = block[0]
1529+
self.blocks = tuple([block])
15401530

1541-
if not isinstance(block, Block):
1542-
block = make_block(block, placement=slice(0, len(axis)), ndim=1)
1531+
@classmethod
1532+
def from_blocks(
1533+
cls, blocks: List[Block], axes: List[Index]
1534+
) -> "SingleBlockManager":
1535+
"""
1536+
Constructor for BlockManager and SingleBlockManager with same signature.
1537+
"""
1538+
assert len(blocks) == 1
1539+
assert len(axes) == 1
1540+
return cls(blocks[0], axes[0], do_integrity_check=False, fastpath=True)
15431541

1544-
self.blocks = tuple([block])
1542+
@classmethod
1543+
def from_array(cls, array: ArrayLike, index: Index) -> "SingleBlockManager":
1544+
"""
1545+
Constructor for if we have an array that is not yet a Block.
1546+
"""
1547+
block = make_block(array, placement=slice(0, len(index)), ndim=1)
1548+
return cls(block, index, fastpath=True)
15451549

15461550
def _post_setstate(self):
15471551
pass
@@ -1568,7 +1572,10 @@ def get_slice(self, slobj: slice, axis: int = 0) -> "SingleBlockManager":
15681572
if axis >= self.ndim:
15691573
raise IndexError("Requested axis not found in manager")
15701574

1571-
return type(self)(self._block._slice(slobj), self.index[slobj], fastpath=True)
1575+
blk = self._block
1576+
array = blk._slice(slobj)
1577+
block = blk.make_block_same_class(array, placement=range(len(array)))
1578+
return type(self)(block, self.index[slobj], fastpath=True)
15721579

15731580
@property
15741581
def index(self) -> Index:
@@ -1626,7 +1633,7 @@ def fast_xs(self, loc):
16261633
"""
16271634
raise NotImplementedError("Use series._values[loc] instead")
16281635

1629-
def concat(self, to_concat, new_axis) -> "SingleBlockManager":
1636+
def concat(self, to_concat, new_axis: Index) -> "SingleBlockManager":
16301637
"""
16311638
Concatenate a list of SingleBlockManagers into a single
16321639
SingleBlockManager.

pandas/core/series.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def __init__(
205205

206206
# data is an ndarray, index is defined
207207
if not isinstance(data, SingleBlockManager):
208-
data = SingleBlockManager(data, index, fastpath=True)
208+
data = SingleBlockManager.from_array(data, index)
209209
if copy:
210210
data = data.copy()
211211
if index is None:
@@ -317,7 +317,7 @@ def __init__(
317317
else:
318318
data = sanitize_array(data, index, dtype, copy, raise_cast_failure=True)
319319

320-
data = SingleBlockManager(data, index, fastpath=True)
320+
data = SingleBlockManager.from_array(data, index)
321321

322322
generic.NDFrame.__init__(self, data)
323323
self.name = name

pandas/tests/extension/test_external_block.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pytest
33

44
import pandas as pd
5-
from pandas.core.internals import BlockManager
5+
from pandas.core.internals import BlockManager, SingleBlockManager
66
from pandas.core.internals.blocks import Block, NonConsolidatableMixIn
77

88

@@ -36,7 +36,8 @@ def test_concat_series():
3636
# GH17728
3737
values = np.arange(3, dtype="int64")
3838
block = CustomBlock(values, placement=slice(0, 3))
39-
s = pd.Series(block, pd.RangeIndex(3), fastpath=True)
39+
mgr = SingleBlockManager(block, pd.RangeIndex(3))
40+
s = pd.Series(mgr, pd.RangeIndex(3), fastpath=True)
4041

4142
res = pd.concat([s, s])
4243
assert isinstance(res._data.blocks[0], CustomBlock)

0 commit comments

Comments
 (0)