@@ -47,8 +47,7 @@ def _single_replace(self, to_replace, method, inplace, limit):
47
47
if values .dtype == orig_dtype and inplace :
48
48
return
49
49
50
- result = pd .Series (values , index = self .index , name = self .name ,
51
- dtype = self .dtype )
50
+ result = pd .Series (values , index = self .index , dtype = self .dtype ).__finalize__ (self )
52
51
53
52
if inplace :
54
53
self ._data = result ._data
@@ -72,7 +71,7 @@ class NDFrame(PandasObject):
72
71
_internal_names = [
73
72
'_data' , 'name' , '_cacher' , '_subtyp' , '_index' , '_default_kind' , '_default_fill_value' ]
74
73
_internal_names_set = set (_internal_names )
75
- _prop_attributes = []
74
+ _metadata = []
76
75
77
76
def __init__ (self , data , axes = None , copy = False , dtype = None , fastpath = False ):
78
77
@@ -413,7 +412,7 @@ def transpose(self, *args, **kwargs):
413
412
new_values = self .values .transpose (axes_numbers )
414
413
if kwargs .get ('copy' ) or (len (args ) and args [- 1 ]):
415
414
new_values = new_values .copy ()
416
- return self ._constructor (new_values , ** new_axes )
415
+ return self ._constructor (new_values , ** new_axes ). __finalize__ ( self )
417
416
418
417
def swapaxes (self , axis1 , axis2 , copy = True ):
419
418
"""
@@ -439,7 +438,7 @@ def swapaxes(self, axis1, axis2, copy=True):
439
438
if copy :
440
439
new_values = new_values .copy ()
441
440
442
- return self ._constructor (new_values , * new_axes )
441
+ return self ._constructor (new_values , * new_axes ). __finalize__ ( self )
443
442
444
443
def pop (self , item ):
445
444
"""
@@ -543,7 +542,7 @@ def f(x):
543
542
self ._clear_item_cache ()
544
543
545
544
else :
546
- return result ._propogate_attributes (self )
545
+ return result .__finalize__ (self )
547
546
548
547
rename .__doc__ = _shared_docs ['rename' ]
549
548
@@ -655,14 +654,14 @@ def __abs__(self):
655
654
656
655
def _wrap_array (self , arr , axes , copy = False ):
657
656
d = self ._construct_axes_dict_from (self , axes , copy = copy )
658
- return self ._constructor (arr , ** d )
657
+ return self ._constructor (arr , ** d ). __finalize__ ( self )
659
658
660
659
def __array__ (self , dtype = None ):
661
660
return _values_from_object (self )
662
661
663
662
def __array_wrap__ (self , result ):
664
663
d = self ._construct_axes_dict (self ._AXIS_ORDERS , copy = False )
665
- return self ._constructor (result , ** d )
664
+ return self ._constructor (result , ** d ). __finalize__ ( self )
666
665
667
666
def to_dense (self ):
668
667
# compat
@@ -1024,7 +1023,7 @@ def take(self, indices, axis=0, convert=True):
1024
1023
new_data = self ._data .reindex_axis (new_items , indexer = indices , axis = 0 )
1025
1024
else :
1026
1025
new_data = self ._data .take (indices , axis = baxis )
1027
- return self ._constructor (new_data )
1026
+ return self ._constructor (new_data ). __finalize__ ( self )
1028
1027
1029
1028
# TODO: Check if this was clearer in 0.12
1030
1029
def select (self , crit , axis = 0 ):
@@ -1135,7 +1134,7 @@ def add_prefix(self, prefix):
1135
1134
with_prefix : type of caller
1136
1135
"""
1137
1136
new_data = self ._data .add_prefix (prefix )
1138
- return self ._constructor (new_data )
1137
+ return self ._constructor (new_data ). __finalize__ ( self )
1139
1138
1140
1139
def add_suffix (self , suffix ):
1141
1140
"""
@@ -1150,7 +1149,7 @@ def add_suffix(self, suffix):
1150
1149
with_suffix : type of caller
1151
1150
"""
1152
1151
new_data = self ._data .add_suffix (suffix )
1153
- return self ._constructor (new_data )
1152
+ return self ._constructor (new_data ). __finalize__ ( self )
1154
1153
1155
1154
def sort_index (self , axis = 0 , ascending = True ):
1156
1155
"""
@@ -1244,7 +1243,8 @@ def reindex(self, *args, **kwargs):
1244
1243
return self
1245
1244
1246
1245
# perform the reindex on the axes
1247
- return self ._reindex_axes (axes , level , limit , method , fill_value , copy , takeable = takeable )._propogate_attributes (self )
1246
+ return self ._reindex_axes (axes , level , limit ,
1247
+ method , fill_value , copy , takeable = takeable ).__finalize__ (self )
1248
1248
1249
1249
def _reindex_axes (self , axes , level , limit , method , fill_value , copy , takeable = False ):
1250
1250
""" perform the reinxed for all the axes """
@@ -1332,7 +1332,7 @@ def reindex_axis(self, labels, axis=0, method=None, level=None, copy=True,
1332
1332
new_index , indexer = axis_values .reindex (labels , method , level ,
1333
1333
limit = limit , copy_if_needed = True )
1334
1334
return self ._reindex_with_indexers ({axis : [new_index , indexer ]}, method = method , fill_value = fill_value ,
1335
- limit = limit , copy = copy )._propogate_attributes (self )
1335
+ limit = limit , copy = copy ).__finalize__ (self )
1336
1336
1337
1337
def _reindex_with_indexers (self , reindexers , method = None , fill_value = np .nan , limit = None , copy = False , allow_dups = False ):
1338
1338
""" allow_dups indicates an internal call here """
@@ -1370,7 +1370,7 @@ def _reindex_with_indexers(self, reindexers, method=None, fill_value=np.nan, lim
1370
1370
if copy and new_data is self ._data :
1371
1371
new_data = new_data .copy ()
1372
1372
1373
- return self ._constructor (new_data )
1373
+ return self ._constructor (new_data ). __finalize__ ( self )
1374
1374
1375
1375
def _reindex_axis (self , new_index , fill_method , axis , copy ):
1376
1376
new_data = self ._data .reindex_axis (new_index , axis = axis ,
@@ -1379,7 +1379,7 @@ def _reindex_axis(self, new_index, fill_method, axis, copy):
1379
1379
if new_data is self ._data and not copy :
1380
1380
return self
1381
1381
else :
1382
- return self ._constructor (new_data )
1382
+ return self ._constructor (new_data ). __finalize__ ( self )
1383
1383
1384
1384
def filter (self , items = None , like = None , regex = None , axis = None ):
1385
1385
"""
@@ -1421,9 +1421,18 @@ def filter(self, items=None, like=None, regex=None, axis=None):
1421
1421
#----------------------------------------------------------------------
1422
1422
# Attribute access
1423
1423
1424
- def _propogate_attributes (self , other ):
1425
- """ propogate attributes from other to self"""
1426
- for name in self ._prop_attributes :
1424
+ def __finalize__ (self , other , method = None , ** kwargs ):
1425
+ """
1426
+ propagate metadata from other to self
1427
+
1428
+ Parameters
1429
+ ----------
1430
+ other : the object from which to get the attributes that we are going to propagate
1431
+ method : optional, a passed method name ; possibily to take different types
1432
+ of propagation actions based on this
1433
+
1434
+ """
1435
+ for name in self ._metadata :
1427
1436
object .__setattr__ (self , name , getattr (other , name , None ))
1428
1437
return self
1429
1438
@@ -1484,7 +1493,7 @@ def consolidate(self, inplace=False):
1484
1493
cons_data = self ._protect_consolidate (f )
1485
1494
if cons_data is self ._data :
1486
1495
cons_data = cons_data .copy ()
1487
- return self ._constructor (cons_data )
1496
+ return self ._constructor (cons_data ). __finalize__ ( self )
1488
1497
1489
1498
@property
1490
1499
def _is_mixed_type (self ):
@@ -1504,10 +1513,10 @@ def _protect_consolidate(self, f):
1504
1513
return result
1505
1514
1506
1515
def _get_numeric_data (self ):
1507
- return self ._constructor (self ._data .get_numeric_data ())
1516
+ return self ._constructor (self ._data .get_numeric_data ()). __finalize__ ( self )
1508
1517
1509
1518
def _get_bool_data (self ):
1510
- return self ._constructor (self ._data .get_bool_data ())
1519
+ return self ._constructor (self ._data .get_bool_data ()). __finalize__ ( self )
1511
1520
1512
1521
#----------------------------------------------------------------------
1513
1522
# Internal Interface Methods
@@ -1584,7 +1593,7 @@ def as_blocks(self, columns=None):
1584
1593
for b in self ._data .blocks :
1585
1594
b = b .reindex_items_from (columns or b .items )
1586
1595
bd [str (b .dtype )] = self ._constructor (
1587
- BlockManager ([b ], [b .items , self .index ]))
1596
+ BlockManager ([b ], [b .items , self .index ])). __finalize__ ( self )
1588
1597
return bd
1589
1598
1590
1599
@property
@@ -1608,7 +1617,7 @@ def astype(self, dtype, copy=True, raise_on_error=True):
1608
1617
1609
1618
mgr = self ._data .astype (
1610
1619
dtype , copy = copy , raise_on_error = raise_on_error )
1611
- return self ._constructor (mgr )._propogate_attributes (self )
1620
+ return self ._constructor (mgr ).__finalize__ (self )
1612
1621
1613
1622
def copy (self , deep = True ):
1614
1623
"""
@@ -1626,7 +1635,7 @@ def copy(self, deep=True):
1626
1635
data = self ._data
1627
1636
if deep :
1628
1637
data = data .copy ()
1629
- return self ._constructor (data )._propogate_attributes (self )
1638
+ return self ._constructor (data ).__finalize__ (self )
1630
1639
1631
1640
def convert_objects (self , convert_dates = True , convert_numeric = False , copy = True ):
1632
1641
"""
@@ -1642,7 +1651,9 @@ def convert_objects(self, convert_dates=True, convert_numeric=False, copy=True):
1642
1651
-------
1643
1652
converted : asm as input object
1644
1653
"""
1645
- return self ._constructor (self ._data .convert (convert_dates = convert_dates , convert_numeric = convert_numeric , copy = copy ))
1654
+ return self ._constructor (self ._data .convert (convert_dates = convert_dates ,
1655
+ convert_numeric = convert_numeric ,
1656
+ copy = copy )).__finalize__ (self )
1646
1657
1647
1658
#----------------------------------------------------------------------
1648
1659
# Filling NA's
@@ -1713,7 +1724,7 @@ def fillna(self, value=None, method=None, axis=0, inplace=False,
1713
1724
1714
1725
# fill in 2d chunks
1715
1726
result = dict ([ (col ,s .fillna (method = method , value = value )) for col , s in compat .iteritems (self ) ])
1716
- return self ._constructor .from_dict (result )
1727
+ return self ._constructor .from_dict (result ). __finalize__ ( self )
1717
1728
1718
1729
# 2d or less
1719
1730
method = com ._clean_fill_method (method )
@@ -1750,7 +1761,7 @@ def fillna(self, value=None, method=None, axis=0, inplace=False,
1750
1761
if inplace :
1751
1762
self ._data = new_data
1752
1763
else :
1753
- return self ._constructor (new_data )
1764
+ return self ._constructor (new_data ). __finalize__ ( self )
1754
1765
1755
1766
def ffill (self , axis = 0 , inplace = False , limit = None , downcast = None ):
1756
1767
return self .fillna (method = 'ffill' , axis = axis , inplace = inplace ,
@@ -1991,7 +2002,7 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
1991
2002
if inplace :
1992
2003
self ._data = new_data
1993
2004
else :
1994
- return self ._constructor (new_data )
2005
+ return self ._constructor (new_data ). __finalize__ ( self )
1995
2006
1996
2007
def interpolate (self , method = 'linear' , axis = 0 , limit = None , inplace = False ,
1997
2008
downcast = 'infer' , ** kwargs ):
@@ -2101,7 +2112,7 @@ def interpolate(self, method='linear', axis=0, limit=None, inplace=False,
2101
2112
else :
2102
2113
self ._data = new_data
2103
2114
else :
2104
- res = self ._constructor (new_data , index = self . index )
2115
+ res = self ._constructor (new_data ). __finalize__ ( self )
2105
2116
if axis == 1 :
2106
2117
res = res .T
2107
2118
return res
@@ -2113,13 +2124,13 @@ def isnull(self):
2113
2124
"""
2114
2125
Return a boolean same-sized object indicating if the values are null
2115
2126
"""
2116
- return self .__class__ (isnull (self ),** self ._construct_axes_dict ())._propogate_attributes (self )
2127
+ return self .__class__ (isnull (self ),** self ._construct_axes_dict ()).__finalize__ (self )
2117
2128
2118
2129
def notnull (self ):
2119
2130
"""
2120
2131
Return a boolean same-sized object indicating if the values are not null
2121
2132
"""
2122
- return self .__class__ (notnull (self ),** self ._construct_axes_dict ())._propogate_attributes (self )
2133
+ return self .__class__ (notnull (self ),** self ._construct_axes_dict ()).__finalize__ (self )
2123
2134
2124
2135
def clip (self , lower = None , upper = None , out = None ):
2125
2136
"""
@@ -2484,7 +2495,7 @@ def _align_frame(self, other, join='outer', axis=None, level=None,
2484
2495
left = left .fillna (axis = fill_axis , method = method , limit = limit )
2485
2496
right = right .fillna (axis = fill_axis , method = method , limit = limit )
2486
2497
2487
- return left , right
2498
+ return left . __finalize__ ( self ) , right . __finalize__ ( other )
2488
2499
2489
2500
def _align_series (self , other , join = 'outer' , axis = None , level = None ,
2490
2501
copy = True , fill_value = None , method = None , limit = None ,
@@ -2543,7 +2554,7 @@ def _align_series(self, other, join='outer', axis=None, level=None,
2543
2554
right_result .fillna (fill_value , method = method ,
2544
2555
limit = limit ))
2545
2556
else :
2546
- return left_result , right_result
2557
+ return left_result . __finalize__ ( self ) , right_result . __finalize__ ( other )
2547
2558
2548
2559
def where (self , cond , other = np .nan , inplace = False , axis = None , level = None ,
2549
2560
try_cast = False , raise_on_error = True ):
@@ -2680,7 +2691,7 @@ def where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
2680
2691
new_data = self ._data .where (
2681
2692
other , cond , align = axis is None , raise_on_error = raise_on_error , try_cast = try_cast )
2682
2693
2683
- return self ._constructor (new_data )
2694
+ return self ._constructor (new_data ). __finalize__ ( self )
2684
2695
2685
2696
def mask (self , cond ):
2686
2697
"""
@@ -2728,7 +2739,7 @@ def shift(self, periods=1, freq=None, axis=0, **kwds):
2728
2739
else :
2729
2740
return self .tshift (periods , freq , ** kwds )
2730
2741
2731
- return self ._constructor (new_data )
2742
+ return self ._constructor (new_data ). __finalize__ ( self )
2732
2743
2733
2744
def tshift (self , periods = 1 , freq = None , axis = 0 , ** kwds ):
2734
2745
"""
@@ -2789,7 +2800,7 @@ def tshift(self, periods=1, freq=None, axis=0, **kwds):
2789
2800
new_data = self ._data .copy ()
2790
2801
new_data .axes [block_axis ] = index .shift (periods , offset )
2791
2802
2792
- return self ._constructor (new_data )
2803
+ return self ._constructor (new_data ). __finalize__ ( self )
2793
2804
2794
2805
def truncate (self , before = None , after = None , copy = True ):
2795
2806
"""Truncates a sorted NDFrame before and/or after some particular
@@ -2864,7 +2875,7 @@ def tz_convert(self, tz, axis=0, copy=True):
2864
2875
new_obj ._set_axis (0 , new_ax )
2865
2876
self ._clear_item_cache ()
2866
2877
2867
- return new_obj
2878
+ return new_obj . __finalize__ ( self )
2868
2879
2869
2880
def tz_localize (self , tz , axis = 0 , copy = True , infer_dst = False ):
2870
2881
"""
@@ -2902,7 +2913,7 @@ def tz_localize(self, tz, axis=0, copy=True, infer_dst=False):
2902
2913
new_obj ._set_axis (0 , new_ax )
2903
2914
self ._clear_item_cache ()
2904
2915
2905
- return new_obj
2916
+ return new_obj . __finalize__ ( self )
2906
2917
2907
2918
#----------------------------------------------------------------------
2908
2919
# Numeric Methods
@@ -3128,7 +3139,7 @@ def func(self, axis=None, dtype=None, out=None, skipna=True, **kwargs):
3128
3139
3129
3140
d = self ._construct_axes_dict ()
3130
3141
d ['copy' ] = False
3131
- return self ._constructor (result , ** d )._propogate_attributes (self )
3142
+ return self ._constructor (result , ** d ).__finalize__ (self )
3132
3143
3133
3144
func .__name__ = name
3134
3145
return func
0 commit comments