Skip to content

Commit 05e238d

Browse files
committed
use attrs
1 parent 930aa9d commit 05e238d

File tree

6 files changed

+50
-37
lines changed

6 files changed

+50
-37
lines changed

pandas/core/frame.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5316,8 +5316,9 @@ def _arith_op(left, right):
53165316
with np.errstate(all="ignore"):
53175317
res_values = _arith_op(this.values, other.values)
53185318
new_data = dispatch_fill_zeros(func, this.values, other.values, res_values)
5319-
# XXX: pass them here.
5320-
return this._construct_result(new_data)
5319+
return this._construct_result(new_data).__finalize__(
5320+
(self, other), method="combine_frame"
5321+
)
53215322

53225323
def _combine_match_index(self, other, func):
53235324
# at this point we have `self.index.equals(other.index)`

pandas/core/generic.py

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class NDFrame(PandasObject, SelectionMixin):
187187
"ix",
188188
]
189189
) # type: FrozenSet[str]
190-
_metadata = ["allows_duplicate_labels"] # type: List[str]
190+
_metadata = [] # type: List[str]
191191
_is_copy = None
192192
_data = None # type: BlockManager
193193

@@ -224,12 +224,16 @@ def __init__(
224224
object.__setattr__(self, "_is_copy", None)
225225
object.__setattr__(self, "_data", data)
226226
object.__setattr__(self, "_item_cache", {})
227-
object.__setattr__(self, "allows_duplicate_labels", allow_duplicate_labels)
228227
if attrs is None:
229228
attrs = {}
230229
else:
231230
attrs = dict(attrs)
231+
# need to add it to the dict here, since NDFrame.__setattr__
232+
# also calls NDFrame.__getattr__...
233+
# attrs['allows_duplicate_labels'] = allow_duplicate_labels
232234
object.__setattr__(self, "_attrs", attrs)
235+
object.__setattr__(self, "allows_duplicate_labels", allow_duplicate_labels)
236+
# self.allows_duplicate_labels = allow_duplicate_labels
233237

234238
def _init_mgr(self, mgr, axes=None, dtype=None, copy=False):
235239
""" passed a manager and a axes dict """
@@ -251,21 +255,6 @@ def _init_mgr(self, mgr, axes=None, dtype=None, copy=False):
251255
# ----------------------------------------------------------------------
252256

253257
@property
254-
def allows_duplicate_labels(self):
255-
"""
256-
Whether this object allows duplicate labels.
257-
"""
258-
return self._allows_duplicate_labels
259-
260-
@allows_duplicate_labels.setter
261-
def allows_duplicate_labels(self, value: bool):
262-
value = bool(value)
263-
if not value:
264-
for ax in self.axes:
265-
ax._maybe_check_unique()
266-
267-
self._allows_duplicate_labels = value
268-
269258
def attrs(self) -> Dict[Hashable, Any]:
270259
"""
271260
Dictionary of global attributes on this object.
@@ -278,6 +267,22 @@ def attrs(self) -> Dict[Hashable, Any]:
278267
def attrs(self, value: Mapping[Hashable, Any]) -> None:
279268
self._attrs = dict(value)
280269

270+
@property
271+
def allows_duplicate_labels(self) -> bool:
272+
"""
273+
Whether this object allows duplicate labels.
274+
"""
275+
return self.attrs["allows_duplicate_labels"]
276+
277+
@allows_duplicate_labels.setter
278+
def allows_duplicate_labels(self, value: bool):
279+
value = bool(value)
280+
if not value:
281+
for ax in self.axes:
282+
ax._maybe_check_unique()
283+
284+
self.attrs["allows_duplicate_labels"] = value
285+
281286
@property
282287
def is_copy(self):
283288
"""
@@ -5249,6 +5254,7 @@ def pipe(self, func, *args, **kwargs):
52495254
>>> s = pd.Series(range(3))
52505255
>>> s
52515256
0 0
5257+
52525258
1 1
52535259
2 2
52545260
dtype: int64
@@ -5287,18 +5293,18 @@ def finalize_name(objs):
52875293

52885294
duplicate_labels = "allows_duplicate_labels"
52895295

5290-
# import pdb; pdb.set_trace()
52915296
if isinstance(other, NDFrame):
5292-
for name in other.attrs:
5293-
self.attrs[name] = other.attrs[name]
5297+
for name, value in other.attrs.items():
5298+
# Need to think about this...
5299+
if name == "allows_duplicate_labels":
5300+
self.allows_duplicate_labels = value
5301+
elif name in self.attrs:
5302+
self.attrs[name] = other.attrs[name]
5303+
52945304
# For subclasses using _metadata.
52955305
for name in self._metadata:
5296-
if name == "name" and getattr(other, "ndim", None) == 1:
5297-
# Calling hasattr(other, 'name') is bad for DataFrames with
5298-
# a name column.
5299-
object.__setattr__(self, name, getattr(other, name, None))
5300-
elif name != "name":
5301-
object.__setattr__(self, name, getattr(other, name, None))
5306+
object.__setattr__(self, name, getattr(other, name, None))
5307+
53025308
elif method == "concat":
53035309
assert isinstance(other, _Concatenator)
53045310
self.allows_duplicate_labels = merge_all(other.objs, duplicate_labels)
@@ -5307,7 +5313,7 @@ def finalize_name(objs):
53075313
self.allows_duplicate_labels = merge_all(
53085314
(other.left, other.right), duplicate_labels
53095315
)
5310-
elif method in {"combine_const", "combine_frame"}:
5316+
elif method in {"combine_const", "combine_frame", "combine_series_frame"}:
53115317
assert isinstance(other, tuple)
53125318
self.allows_duplicate_labels = merge_all(other, duplicate_labels)
53135319
elif method == "align_series":

pandas/core/groupby/generic.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ def aggregate(self, func=None, *args, **kwargs):
243243

244244
if isinstance(func, str):
245245
return getattr(self, func)(*args, **kwargs).__finalize__(
246-
method="groupby-aggregate"
246+
self, method="groupby-aggregate"
247247
)
248248

249249
if isinstance(func, abc.Iterable):
@@ -275,12 +275,16 @@ def aggregate(self, func=None, *args, **kwargs):
275275
print("Warning, ignoring as_index=True")
276276

277277
# _level handled at higher
278-
if not _level and isinstance(ret, dict):
278+
if not _level and isinstance(ret, (dict, OrderedDict)):
279279
from pandas import concat
280280

281281
ret = concat(ret, axis=1)
282282

283-
return ret.__finalize__(self, method="groupby-aggregate")
283+
if isinstance(ret, NDFrame):
284+
# TODO: when is this *not* an NDFrame?
285+
# pandas/tests/resample/test_resample_api.py::test_agg_nested_dicts
286+
ret = ret.__finalize__(self, method="groupby-aggregate")
287+
return ret
284288

285289
agg = aggregate
286290

@@ -876,7 +880,7 @@ def aggregate(self, func=None, *args, **kwargs):
876880

877881
result, how = self._aggregate(func, _level=_level, *args, **kwargs)
878882
if how is None:
879-
return result
883+
return result.__finalize__(self, method="groupby-aggregate")
880884

881885
if result is None:
882886

pandas/core/ops/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,9 @@ def _combine_series_frame(self, other, func, fill_value=None, axis=None, level=N
624624
else:
625625
new_data = dispatch_to_series(left, right, func, axis="columns")
626626

627-
return left._construct_result(new_data)
627+
return left._construct_result(new_data).__finalize__(
628+
(self, other), method="combine_series_frame"
629+
)
628630

629631

630632
def _align_method_FRAME(left, right, axis):
@@ -724,7 +726,7 @@ def f(self, other, axis=default_axis, level=None, fill_value=None):
724726
self = self.fillna(fill_value)
725727

726728
new_data = dispatch_to_series(self, other, op)
727-
return self._construct_result(new_data)
729+
return self._construct_result(new_data).__finalize__(self)
728730

729731
f.__name__ = op_name
730732

pandas/tests/test_duplicate_labels.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ class TestRaises:
249249
)
250250
def test_construction_with_duplicates(self, cls, axes):
251251
result = cls(**axes)
252-
assert result._allows_duplicate_labels is True
252+
assert result.allows_duplicate_labels is True
253253

254254
with pytest.raises(pandas.errors.DuplicateLabelError):
255255
cls(**axes, allow_duplicate_labels=False)

pandas/util/testing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2800,7 +2800,7 @@ def inner(*args, **kwargs):
28002800

28012801

28022802
class SubclassedSeries(Series):
2803-
_metadata = ["testattr", "name"]
2803+
_metadata = Series._metadata + ["testattr"]
28042804

28052805
@property
28062806
def _constructor(self):

0 commit comments

Comments
 (0)