Skip to content

Commit 0a3dbf7

Browse files
committed
Merge pull request #5205 from jreback/meta
API: rename _prop_attributes to __finalize__ (in NDFrame)
2 parents 247af41 + 7fe3d02 commit 0a3dbf7

File tree

8 files changed

+233
-120
lines changed

8 files changed

+233
-120
lines changed

pandas/core/common.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -2554,7 +2554,8 @@ def save(obj, path): # TODO remove in 0.13
25542554

25552555

25562556
def _maybe_match_name(a, b):
2557-
name = None
2558-
if a.name == b.name:
2559-
name = a.name
2560-
return name
2557+
a_name = getattr(a,'name',None)
2558+
b_name = getattr(b,'name',None)
2559+
if a_name == b_name:
2560+
return a_name
2561+
return None

pandas/core/generic.py

+50-39
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ def _single_replace(self, to_replace, method, inplace, limit):
4747
if values.dtype == orig_dtype and inplace:
4848
return
4949

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)
5251

5352
if inplace:
5453
self._data = result._data
@@ -72,7 +71,7 @@ class NDFrame(PandasObject):
7271
_internal_names = [
7372
'_data', 'name', '_cacher', '_subtyp', '_index', '_default_kind', '_default_fill_value']
7473
_internal_names_set = set(_internal_names)
75-
_prop_attributes = []
74+
_metadata = []
7675

7776
def __init__(self, data, axes=None, copy=False, dtype=None, fastpath=False):
7877

@@ -413,7 +412,7 @@ def transpose(self, *args, **kwargs):
413412
new_values = self.values.transpose(axes_numbers)
414413
if kwargs.get('copy') or (len(args) and args[-1]):
415414
new_values = new_values.copy()
416-
return self._constructor(new_values, **new_axes)
415+
return self._constructor(new_values, **new_axes).__finalize__(self)
417416

418417
def swapaxes(self, axis1, axis2, copy=True):
419418
"""
@@ -439,7 +438,7 @@ def swapaxes(self, axis1, axis2, copy=True):
439438
if copy:
440439
new_values = new_values.copy()
441440

442-
return self._constructor(new_values, *new_axes)
441+
return self._constructor(new_values, *new_axes).__finalize__(self)
443442

444443
def pop(self, item):
445444
"""
@@ -543,7 +542,7 @@ def f(x):
543542
self._clear_item_cache()
544543

545544
else:
546-
return result._propogate_attributes(self)
545+
return result.__finalize__(self)
547546

548547
rename.__doc__ = _shared_docs['rename']
549548

@@ -655,14 +654,14 @@ def __abs__(self):
655654

656655
def _wrap_array(self, arr, axes, copy=False):
657656
d = self._construct_axes_dict_from(self, axes, copy=copy)
658-
return self._constructor(arr, **d)
657+
return self._constructor(arr, **d).__finalize__(self)
659658

660659
def __array__(self, dtype=None):
661660
return _values_from_object(self)
662661

663662
def __array_wrap__(self, result):
664663
d = self._construct_axes_dict(self._AXIS_ORDERS, copy=False)
665-
return self._constructor(result, **d)
664+
return self._constructor(result, **d).__finalize__(self)
666665

667666
def to_dense(self):
668667
# compat
@@ -1024,7 +1023,7 @@ def take(self, indices, axis=0, convert=True):
10241023
new_data = self._data.reindex_axis(new_items, indexer=indices, axis=0)
10251024
else:
10261025
new_data = self._data.take(indices, axis=baxis)
1027-
return self._constructor(new_data)
1026+
return self._constructor(new_data).__finalize__(self)
10281027

10291028
# TODO: Check if this was clearer in 0.12
10301029
def select(self, crit, axis=0):
@@ -1135,7 +1134,7 @@ def add_prefix(self, prefix):
11351134
with_prefix : type of caller
11361135
"""
11371136
new_data = self._data.add_prefix(prefix)
1138-
return self._constructor(new_data)
1137+
return self._constructor(new_data).__finalize__(self)
11391138

11401139
def add_suffix(self, suffix):
11411140
"""
@@ -1150,7 +1149,7 @@ def add_suffix(self, suffix):
11501149
with_suffix : type of caller
11511150
"""
11521151
new_data = self._data.add_suffix(suffix)
1153-
return self._constructor(new_data)
1152+
return self._constructor(new_data).__finalize__(self)
11541153

11551154
def sort_index(self, axis=0, ascending=True):
11561155
"""
@@ -1244,7 +1243,8 @@ def reindex(self, *args, **kwargs):
12441243
return self
12451244

12461245
# 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)
12481248

12491249
def _reindex_axes(self, axes, level, limit, method, fill_value, copy, takeable=False):
12501250
""" perform the reinxed for all the axes """
@@ -1332,7 +1332,7 @@ def reindex_axis(self, labels, axis=0, method=None, level=None, copy=True,
13321332
new_index, indexer = axis_values.reindex(labels, method, level,
13331333
limit=limit, copy_if_needed=True)
13341334
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)
13361336

13371337
def _reindex_with_indexers(self, reindexers, method=None, fill_value=np.nan, limit=None, copy=False, allow_dups=False):
13381338
""" allow_dups indicates an internal call here """
@@ -1370,7 +1370,7 @@ def _reindex_with_indexers(self, reindexers, method=None, fill_value=np.nan, lim
13701370
if copy and new_data is self._data:
13711371
new_data = new_data.copy()
13721372

1373-
return self._constructor(new_data)
1373+
return self._constructor(new_data).__finalize__(self)
13741374

13751375
def _reindex_axis(self, new_index, fill_method, axis, copy):
13761376
new_data = self._data.reindex_axis(new_index, axis=axis,
@@ -1379,7 +1379,7 @@ def _reindex_axis(self, new_index, fill_method, axis, copy):
13791379
if new_data is self._data and not copy:
13801380
return self
13811381
else:
1382-
return self._constructor(new_data)
1382+
return self._constructor(new_data).__finalize__(self)
13831383

13841384
def filter(self, items=None, like=None, regex=None, axis=None):
13851385
"""
@@ -1421,9 +1421,18 @@ def filter(self, items=None, like=None, regex=None, axis=None):
14211421
#----------------------------------------------------------------------
14221422
# Attribute access
14231423

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:
14271436
object.__setattr__(self, name, getattr(other, name, None))
14281437
return self
14291438

@@ -1484,7 +1493,7 @@ def consolidate(self, inplace=False):
14841493
cons_data = self._protect_consolidate(f)
14851494
if cons_data is self._data:
14861495
cons_data = cons_data.copy()
1487-
return self._constructor(cons_data)
1496+
return self._constructor(cons_data).__finalize__(self)
14881497

14891498
@property
14901499
def _is_mixed_type(self):
@@ -1504,10 +1513,10 @@ def _protect_consolidate(self, f):
15041513
return result
15051514

15061515
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)
15081517

15091518
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)
15111520

15121521
#----------------------------------------------------------------------
15131522
# Internal Interface Methods
@@ -1584,7 +1593,7 @@ def as_blocks(self, columns=None):
15841593
for b in self._data.blocks:
15851594
b = b.reindex_items_from(columns or b.items)
15861595
bd[str(b.dtype)] = self._constructor(
1587-
BlockManager([b], [b.items, self.index]))
1596+
BlockManager([b], [b.items, self.index])).__finalize__(self)
15881597
return bd
15891598

15901599
@property
@@ -1608,7 +1617,7 @@ def astype(self, dtype, copy=True, raise_on_error=True):
16081617

16091618
mgr = self._data.astype(
16101619
dtype, copy=copy, raise_on_error=raise_on_error)
1611-
return self._constructor(mgr)._propogate_attributes(self)
1620+
return self._constructor(mgr).__finalize__(self)
16121621

16131622
def copy(self, deep=True):
16141623
"""
@@ -1626,7 +1635,7 @@ def copy(self, deep=True):
16261635
data = self._data
16271636
if deep:
16281637
data = data.copy()
1629-
return self._constructor(data)._propogate_attributes(self)
1638+
return self._constructor(data).__finalize__(self)
16301639

16311640
def convert_objects(self, convert_dates=True, convert_numeric=False, copy=True):
16321641
"""
@@ -1642,7 +1651,9 @@ def convert_objects(self, convert_dates=True, convert_numeric=False, copy=True):
16421651
-------
16431652
converted : asm as input object
16441653
"""
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)
16461657

16471658
#----------------------------------------------------------------------
16481659
# Filling NA's
@@ -1713,7 +1724,7 @@ def fillna(self, value=None, method=None, axis=0, inplace=False,
17131724

17141725
# fill in 2d chunks
17151726
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)
17171728

17181729
# 2d or less
17191730
method = com._clean_fill_method(method)
@@ -1750,7 +1761,7 @@ def fillna(self, value=None, method=None, axis=0, inplace=False,
17501761
if inplace:
17511762
self._data = new_data
17521763
else:
1753-
return self._constructor(new_data)
1764+
return self._constructor(new_data).__finalize__(self)
17541765

17551766
def ffill(self, axis=0, inplace=False, limit=None, downcast=None):
17561767
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,
19912002
if inplace:
19922003
self._data = new_data
19932004
else:
1994-
return self._constructor(new_data)
2005+
return self._constructor(new_data).__finalize__(self)
19952006

19962007
def interpolate(self, method='linear', axis=0, limit=None, inplace=False,
19972008
downcast='infer', **kwargs):
@@ -2101,7 +2112,7 @@ def interpolate(self, method='linear', axis=0, limit=None, inplace=False,
21012112
else:
21022113
self._data = new_data
21032114
else:
2104-
res = self._constructor(new_data, index=self.index)
2115+
res = self._constructor(new_data).__finalize__(self)
21052116
if axis == 1:
21062117
res = res.T
21072118
return res
@@ -2113,13 +2124,13 @@ def isnull(self):
21132124
"""
21142125
Return a boolean same-sized object indicating if the values are null
21152126
"""
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)
21172128

21182129
def notnull(self):
21192130
"""
21202131
Return a boolean same-sized object indicating if the values are not null
21212132
"""
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)
21232134

21242135
def clip(self, lower=None, upper=None, out=None):
21252136
"""
@@ -2484,7 +2495,7 @@ def _align_frame(self, other, join='outer', axis=None, level=None,
24842495
left = left.fillna(axis=fill_axis, method=method, limit=limit)
24852496
right = right.fillna(axis=fill_axis, method=method, limit=limit)
24862497

2487-
return left, right
2498+
return left.__finalize__(self), right.__finalize__(other)
24882499

24892500
def _align_series(self, other, join='outer', axis=None, level=None,
24902501
copy=True, fill_value=None, method=None, limit=None,
@@ -2543,7 +2554,7 @@ def _align_series(self, other, join='outer', axis=None, level=None,
25432554
right_result.fillna(fill_value, method=method,
25442555
limit=limit))
25452556
else:
2546-
return left_result, right_result
2557+
return left_result.__finalize__(self), right_result.__finalize__(other)
25472558

25482559
def where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
25492560
try_cast=False, raise_on_error=True):
@@ -2680,7 +2691,7 @@ def where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
26802691
new_data = self._data.where(
26812692
other, cond, align=axis is None, raise_on_error=raise_on_error, try_cast=try_cast)
26822693

2683-
return self._constructor(new_data)
2694+
return self._constructor(new_data).__finalize__(self)
26842695

26852696
def mask(self, cond):
26862697
"""
@@ -2728,7 +2739,7 @@ def shift(self, periods=1, freq=None, axis=0, **kwds):
27282739
else:
27292740
return self.tshift(periods, freq, **kwds)
27302741

2731-
return self._constructor(new_data)
2742+
return self._constructor(new_data).__finalize__(self)
27322743

27332744
def tshift(self, periods=1, freq=None, axis=0, **kwds):
27342745
"""
@@ -2789,7 +2800,7 @@ def tshift(self, periods=1, freq=None, axis=0, **kwds):
27892800
new_data = self._data.copy()
27902801
new_data.axes[block_axis] = index.shift(periods, offset)
27912802

2792-
return self._constructor(new_data)
2803+
return self._constructor(new_data).__finalize__(self)
27932804

27942805
def truncate(self, before=None, after=None, copy=True):
27952806
"""Truncates a sorted NDFrame before and/or after some particular
@@ -2864,7 +2875,7 @@ def tz_convert(self, tz, axis=0, copy=True):
28642875
new_obj._set_axis(0, new_ax)
28652876
self._clear_item_cache()
28662877

2867-
return new_obj
2878+
return new_obj.__finalize__(self)
28682879

28692880
def tz_localize(self, tz, axis=0, copy=True, infer_dst=False):
28702881
"""
@@ -2902,7 +2913,7 @@ def tz_localize(self, tz, axis=0, copy=True, infer_dst=False):
29022913
new_obj._set_axis(0, new_ax)
29032914
self._clear_item_cache()
29042915

2905-
return new_obj
2916+
return new_obj.__finalize__(self)
29062917

29072918
#----------------------------------------------------------------------
29082919
# Numeric Methods
@@ -3128,7 +3139,7 @@ def func(self, axis=None, dtype=None, out=None, skipna=True, **kwargs):
31283139

31293140
d = self._construct_axes_dict()
31303141
d['copy'] = False
3131-
return self._constructor(result, **d)._propogate_attributes(self)
3142+
return self._constructor(result, **d).__finalize__(self)
31323143

31333144
func.__name__ = name
31343145
return func

pandas/core/ops.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ def wrapper(self, other):
515515
if len(self) != len(other):
516516
raise ValueError('Lengths must match to compare')
517517
return self._constructor(na_op(self.values, np.asarray(other)),
518-
index=self.index, name=self.name)
518+
index=self.index).__finalize__(self)
519519
else:
520520

521521
mask = isnull(self)
@@ -590,7 +590,7 @@ def wrapper(self, other):
590590
else:
591591
# scalars
592592
return self._constructor(na_op(self.values, other),
593-
index=self.index, name=self.name).fillna(False).astype(bool)
593+
index=self.index).fillna(False).astype(bool).__finalize__(self)
594594
return wrapper
595595

596596

@@ -643,8 +643,8 @@ def f(self, other, level=None, fill_value=None):
643643
return self._binop(self._constructor(other, self.index), op,
644644
level=level, fill_value=fill_value)
645645
else:
646-
return self._constructor(op(self.values, other), self.index,
647-
name=self.name)
646+
return self._constructor(op(self.values, other),
647+
self.index).__finalize__(self)
648648

649649
f.__name__ = name
650650
return f

0 commit comments

Comments
 (0)