3
3
import itertools
4
4
import operator
5
5
import re
6
- from typing import Dict , List , Optional , Sequence , Tuple , Union
6
+ from typing import Dict , List , Optional , Sequence , Tuple , TypeVar , Union
7
7
8
8
import numpy as np
9
9
10
10
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
12
12
from pandas .util ._validators import validate_bool_kwarg
13
13
14
14
from pandas .core .dtypes .cast import (
58
58
59
59
# TODO: flexible with index=None and/or items=None
60
60
61
+ T = TypeVar ("T" , bound = "BlockManager" )
62
+
61
63
62
64
class BlockManager (PandasObject ):
63
65
"""
@@ -149,6 +151,13 @@ def __init__(
149
151
self ._blknos = None
150
152
self ._blklocs = None
151
153
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
+
152
161
@property
153
162
def blknos (self ):
154
163
"""
@@ -176,18 +185,19 @@ def blklocs(self):
176
185
177
186
return self ._blklocs
178
187
179
- def make_empty (self , axes = None ) -> "BlockManager" :
188
+ def make_empty (self : T , axes = None ) -> T :
180
189
""" return an empty BlockManager with the items axis of len 0 """
181
190
if axes is None :
182
191
axes = [Index ([])] + self .axes [1 :]
183
192
184
193
# preserve dtype if possible
185
194
if self .ndim == 1 :
186
195
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 )]
188
198
else :
189
199
blocks = []
190
- return type (self )(blocks , axes )
200
+ return type (self ). from_blocks (blocks , axes )
191
201
192
202
def __nonzero__ (self ) -> bool :
193
203
return True
@@ -380,7 +390,7 @@ def reduce(self, func, *args, **kwargs):
380
390
381
391
return res
382
392
383
- def apply (self , f , filter = None , ** kwargs ) -> "BlockManager" :
393
+ def apply (self : T , f , filter = None , ** kwargs ) -> T :
384
394
"""
385
395
Iterate over the blocks, collect and create a new BlockManager.
386
396
@@ -458,8 +468,8 @@ def apply(self, f, filter=None, **kwargs) -> "BlockManager":
458
468
459
469
if len (result_blocks ) == 0 :
460
470
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 )
463
473
464
474
def quantile (
465
475
self ,
@@ -658,7 +668,7 @@ def comp(s, regex=False):
658
668
rb = new_rb
659
669
result_blocks .extend (rb )
660
670
661
- bm = type (self )(result_blocks , self .axes )
671
+ bm = type (self ). from_blocks (result_blocks , self .axes )
662
672
bm ._consolidate_inplace ()
663
673
return bm
664
674
@@ -747,7 +757,7 @@ def combine(self, blocks: List[Block], copy: bool = True) -> "BlockManager":
747
757
axes = list (self .axes )
748
758
axes [0 ] = self .items .take (indexer )
749
759
750
- return type (self )(new_blocks , axes , do_integrity_check = False )
760
+ return type (self ). from_blocks (new_blocks , axes )
751
761
752
762
def get_slice (self , slobj : slice , axis : int = 0 ) -> "BlockManager" :
753
763
@@ -774,7 +784,7 @@ def __contains__(self, item) -> bool:
774
784
def nblocks (self ) -> int :
775
785
return len (self .blocks )
776
786
777
- def copy (self , deep = True ) -> "BlockManager" :
787
+ def copy (self : T , deep = True ) -> T :
778
788
"""
779
789
Make deep or shallow copy of BlockManager
780
790
@@ -1244,14 +1254,14 @@ def reindex_axis(
1244
1254
)
1245
1255
1246
1256
def reindex_indexer (
1247
- self ,
1257
+ self : T ,
1248
1258
new_axis ,
1249
1259
indexer ,
1250
1260
axis : int ,
1251
1261
fill_value = None ,
1252
- allow_dups = False ,
1262
+ allow_dups : bool = False ,
1253
1263
copy : bool = True ,
1254
- ):
1264
+ ) -> T :
1255
1265
"""
1256
1266
Parameters
1257
1267
----------
@@ -1299,7 +1309,8 @@ def reindex_indexer(
1299
1309
1300
1310
new_axes = list (self .axes )
1301
1311
new_axes [axis ] = new_axis
1302
- return type (self )(new_blocks , new_axes )
1312
+
1313
+ return type (self ).from_blocks (new_blocks , new_axes )
1303
1314
1304
1315
def _slice_take_blocks_ax0 (self , slice_or_indexer , fill_tuple = None ):
1305
1316
"""
@@ -1500,6 +1511,8 @@ def __init__(
1500
1511
do_integrity_check : bool = False ,
1501
1512
fastpath : bool = False ,
1502
1513
):
1514
+ assert isinstance (block , Block ), type (block )
1515
+
1503
1516
if isinstance (axis , list ):
1504
1517
if len (axis ) != 1 :
1505
1518
raise ValueError (
@@ -1510,38 +1523,29 @@ def __init__(
1510
1523
# passed from constructor, single block, single axis
1511
1524
if fastpath :
1512
1525
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 ]
1523
1526
else :
1524
1527
self .axes = [ensure_index (axis )]
1525
1528
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 ])
1540
1530
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 )
1543
1541
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 )
1545
1549
1546
1550
def _post_setstate (self ):
1547
1551
pass
@@ -1568,7 +1572,10 @@ def get_slice(self, slobj: slice, axis: int = 0) -> "SingleBlockManager":
1568
1572
if axis >= self .ndim :
1569
1573
raise IndexError ("Requested axis not found in manager" )
1570
1574
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 )
1572
1579
1573
1580
@property
1574
1581
def index (self ) -> Index :
@@ -1626,7 +1633,7 @@ def fast_xs(self, loc):
1626
1633
"""
1627
1634
raise NotImplementedError ("Use series._values[loc] instead" )
1628
1635
1629
- def concat (self , to_concat , new_axis ) -> "SingleBlockManager" :
1636
+ def concat (self , to_concat , new_axis : Index ) -> "SingleBlockManager" :
1630
1637
"""
1631
1638
Concatenate a list of SingleBlockManagers into a single
1632
1639
SingleBlockManager.
0 commit comments