Skip to content

Commit d771b80

Browse files
committed
use attrs
1 parent f039118 commit d771b80

File tree

9 files changed

+69
-60
lines changed

9 files changed

+69
-60
lines changed

pandas/core/frame.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""""
1+
"""
22
DataFrame
33
---------
44
An efficient 2D container for potentially mixed-type time series or other
@@ -2791,7 +2791,8 @@ def _ixs(self, i: int, axis: int = 0):
27912791
index=self.columns,
27922792
name=self.index[i],
27932793
dtype=new_values.dtype,
2794-
).__finalize__(self, method="ixs")
2794+
)
2795+
result.__finalize__(self, method="ixs")
27952796
result._set_is_copy(self, copy=copy)
27962797
return result
27972798

@@ -5314,8 +5315,9 @@ def _arith_op(left, right):
53145315
with np.errstate(all="ignore"):
53155316
res_values = _arith_op(this.values, other.values)
53165317
new_data = dispatch_fill_zeros(func, this.values, other.values, res_values)
5317-
# XXX: pass them here.
5318-
return this._construct_result(new_data)
5318+
result = this._construct_result(new_data)
5319+
result.__finalize__((self, other), method="combine_frame")
5320+
return result
53195321

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

pandas/core/generic.py

+40-33
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
"""
@@ -3655,7 +3660,8 @@ class animal locomotion
36553660
index=self.columns,
36563661
name=self.index[loc],
36573662
dtype=new_values.dtype,
3658-
).__finalize__(self, method="xs")
3663+
)
3664+
result.__finalize__(self, method="xs")
36593665

36603666
else:
36613667
result = self.iloc[loc]
@@ -5276,18 +5282,18 @@ def finalize_name(objs):
52765282

52775283
duplicate_labels = "allows_duplicate_labels"
52785284

5279-
# import pdb; pdb.set_trace()
52805285
if isinstance(other, NDFrame):
5281-
for name in other.attrs:
5282-
self.attrs[name] = other.attrs[name]
5286+
for name, value in other.attrs.items():
5287+
# Need to think about this...
5288+
if name == "allows_duplicate_labels":
5289+
self.allows_duplicate_labels = value
5290+
elif name in self.attrs:
5291+
self.attrs[name] = other.attrs[name]
5292+
52835293
# For subclasses using _metadata.
52845294
for name in self._metadata:
5285-
if name == "name" and getattr(other, "ndim", None) == 1:
5286-
# Calling hasattr(other, 'name') is bad for DataFrames with
5287-
# a name column.
5288-
object.__setattr__(self, name, getattr(other, name, None))
5289-
elif name != "name":
5290-
object.__setattr__(self, name, getattr(other, name, None))
5295+
object.__setattr__(self, name, getattr(other, name, None))
5296+
52915297
elif method == "concat":
52925298
assert isinstance(other, _Concatenator)
52935299
self.allows_duplicate_labels = merge_all(other.objs, duplicate_labels)
@@ -5296,7 +5302,7 @@ def finalize_name(objs):
52965302
self.allows_duplicate_labels = merge_all(
52975303
(other.left, other.right), duplicate_labels
52985304
)
5299-
elif method in {"combine_const", "combine_frame"}:
5305+
elif method in {"combine_const", "combine_frame", "combine_series_frame"}:
53005306
assert isinstance(other, tuple)
53015307
self.allows_duplicate_labels = merge_all(other, duplicate_labels)
53025308
elif method == "align_series":
@@ -9078,10 +9084,9 @@ def _align_series(
90789084
right.index = join_index
90799085

90809086
# TODO: Determine the expected behavior here. Should these affect eachother?
9081-
return (
9082-
left.__finalize__((self, other), method="align_series"),
9083-
right.__finalize__((other, self), method="align_series"),
9084-
)
9087+
left.__finalize__((self, other), method="align_series")
9088+
right.__finalize__((other, self), method="align_series")
9089+
return left, right
90859090

90869091
def _where(
90879092
self,
@@ -10032,7 +10037,9 @@ def abs(self):
1003210037
2 6 30 -30
1003310038
3 7 40 -50
1003410039
"""
10035-
return np.abs(self).__finalize__(self)
10040+
result = np.abs(self)
10041+
result.__finalize__(self)
10042+
return result
1003610043

1003710044
def describe(self, percentiles=None, include=None, exclude=None):
1003810045
"""

pandas/core/groupby/generic.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ def aggregate(self, func=None, *args, **kwargs):
242242
raise TypeError(no_arg_message)
243243

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

249249
if isinstance(func, abc.Iterable):
250250
# Catch instances of lists / tuples
@@ -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,6 +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:
883+
result.__finalize__(self, method="groupby-aggregate")
879884
return result
880885

881886
if result is None:

pandas/core/ops/__init__.py

+6-2
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+
result = left._construct_result(new_data)
628+
result.__finalize__((self, other), method="combine_series_frame")
629+
return result
628630

629631

630632
def _align_method_FRAME(left, right, axis):
@@ -724,7 +726,9 @@ 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+
result = self._construct_result(new_data)
730+
result.__finalize__(self)
731+
return result
728732

729733
f.__name__ = op_name
730734

pandas/core/series.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1795,7 +1795,8 @@ def to_frame(self, name=None):
17951795
else:
17961796
df = self._constructor_expanddim({name: self})
17971797

1798-
return df.__finalize__(self)
1798+
df.__finalize__(self)
1799+
return df
17991800

18001801
def _set_name(self, name, inplace=False):
18011802
"""

pandas/core/window/rolling.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,9 @@ def _wrap_results(self, results, blocks, obj, exclude=None) -> FrameOrSeries:
330330

331331
if not len(final):
332332
return obj.astype("float64")
333-
return (
334-
concat(final, axis=1)
335-
.reindex(columns=columns, copy=False)
336-
.__finalize__(self, method="window")
337-
)
333+
result = concat(final, axis=1).reindex(columns=columns, copy=False)
334+
result.__finalize__(self, method="window")
335+
return result
338336

339337
def _center_window(self, result, window) -> np.ndarray:
340338
"""

pandas/errors/__init__.py

-8
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,6 @@ class DuplicateLabelError(ValueError):
169169
"""
170170

171171

172-
class NullFrequencyError(ValueError):
173-
"""
174-
Error raised when a null `freq` attribute is used in an operation
175-
that needs a non-null frequency, particularly `DatetimeIndex.shift`,
176-
`TimedeltaIndex.shift`, `PeriodIndex.shift`.
177-
"""
178-
179-
180172
class AccessorRegistrationWarning(Warning):
181173
"""Warning for attribute conflicts in accessor registration."""
182174

pandas/tests/test_duplicate_labels.py

+1-1
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

+1-1
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)