Skip to content

Commit a9e08d8

Browse files
committed
Merge remote-tracking branch 'upstream/main' into ref/index_equiv
2 parents 8cbcbe4 + 308b773 commit a9e08d8

File tree

3 files changed

+104
-54
lines changed

3 files changed

+104
-54
lines changed

doc/source/user_guide/groupby.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,12 @@ You can also include the grouping columns if you want to operate on them.
416416
417417
grouped[["A", "B"]].sum()
418418
419+
.. note::
420+
421+
The ``groupby`` operation in Pandas drops the ``name`` field of the columns Index object
422+
after the operation. This change ensures consistency in syntax between different
423+
column selection methods within groupby operations.
424+
419425
.. _groupby.iterating-label:
420426

421427
Iterating through groups

pandas/core/accessor.py

Lines changed: 94 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def __get__(self, obj, cls):
231231
return accessor_obj
232232

233233

234-
@doc(klass="", others="")
234+
@doc(klass="", examples="", others="")
235235
def _register_accessor(name: str, cls):
236236
"""
237237
Register a custom accessor on {klass} objects.
@@ -255,51 +255,26 @@ def _register_accessor(name: str, cls):
255255
256256
Notes
257257
-----
258-
When accessed, your accessor will be initialized with the pandas object
259-
the user is interacting with. So the signature must be
258+
This function allows you to register a custom-defined accessor class for {klass}.
259+
The requirements for the accessor class are as follows:
260260
261-
.. code-block:: python
261+
* Must contain an init method that:
262262
263-
def __init__(self, pandas_object): # noqa: E999
264-
...
263+
* accepts a single {klass} object
265264
266-
For consistency with pandas methods, you should raise an ``AttributeError``
267-
if the data passed to your accessor has an incorrect dtype.
265+
* raises an AttributeError if the {klass} object does not have correctly
266+
matching inputs for the accessor
268267
269-
>>> pd.Series(["a", "b"]).dt
270-
Traceback (most recent call last):
271-
...
272-
AttributeError: Can only use .dt accessor with datetimelike values
268+
* Must contain a method for each access pattern.
273269
274-
Examples
275-
--------
276-
In your library code::
277-
278-
@pd.api.extensions.register_dataframe_accessor("geo")
279-
class GeoAccessor:
280-
def __init__(self, pandas_obj):
281-
self._obj = pandas_obj
282-
283-
@property
284-
def center(self):
285-
# return the geographic center point of this DataFrame
286-
lat = self._obj.latitude
287-
lon = self._obj.longitude
288-
return (float(lon.mean()), float(lat.mean()))
270+
* The methods should be able to take any argument signature.
289271
290-
def plot(self):
291-
# plot this array's data on a map, e.g., using Cartopy
292-
pass
272+
* Accessible using the @property decorator if no additional arguments are
273+
needed.
293274
294-
Back in an interactive IPython session:
295-
296-
.. code-block:: ipython
297-
298-
In [1]: ds = pd.DataFrame({{"longitude": np.linspace(0, 10),
299-
...: "latitude": np.linspace(0, 20)}})
300-
In [2]: ds.geo.center
301-
Out[2]: (5.0, 10.0)
302-
In [3]: ds.geo.plot() # plots data on a map
275+
Examples
276+
--------
277+
{examples}
303278
"""
304279

305280
def decorator(accessor):
@@ -318,21 +293,98 @@ def decorator(accessor):
318293
return decorator
319294

320295

321-
@doc(_register_accessor, klass="DataFrame")
296+
_register_df_examples = """
297+
An accessor that only accepts integers could
298+
have a class defined like this:
299+
300+
>>> @pd.api.extensions.register_dataframe_accessor("int_accessor")
301+
... class IntAccessor:
302+
... def __init__(self, pandas_obj):
303+
... if not all(pandas_obj[col].dtype == 'int64' for col in pandas_obj.columns):
304+
... raise AttributeError("All columns must contain integer values only")
305+
... self._obj = pandas_obj
306+
...
307+
... def sum(self):
308+
... return self._obj.sum()
309+
...
310+
>>> df = pd.DataFrame([[1, 2], ['x', 'y']])
311+
>>> df.int_accessor
312+
Traceback (most recent call last):
313+
...
314+
AttributeError: All columns must contain integer values only.
315+
>>> df = pd.DataFrame([[1, 2], [3, 4]])
316+
>>> df.int_accessor.sum()
317+
0 4
318+
1 6
319+
dtype: int64"""
320+
321+
322+
@doc(_register_accessor, klass="DataFrame", examples=_register_df_examples)
322323
def register_dataframe_accessor(name: str):
323324
from pandas import DataFrame
324325

325326
return _register_accessor(name, DataFrame)
326327

327328

328-
@doc(_register_accessor, klass="Series")
329+
_register_series_examples = """
330+
An accessor that only accepts integers could
331+
have a class defined like this:
332+
333+
>>> @pd.api.extensions.register_series_accessor("int_accessor")
334+
... class IntAccessor:
335+
... def __init__(self, pandas_obj):
336+
... if not pandas_obj.dtype == 'int64':
337+
... raise AttributeError("The series must contain integer data only")
338+
... self._obj = pandas_obj
339+
...
340+
... def sum(self):
341+
... return self._obj.sum()
342+
...
343+
>>> df = pd.Series([1, 2, 'x'])
344+
>>> df.int_accessor
345+
Traceback (most recent call last):
346+
...
347+
AttributeError: The series must contain integer data only.
348+
>>> df = pd.Series([1, 2, 3])
349+
>>> df.int_accessor.sum()
350+
6"""
351+
352+
353+
@doc(_register_accessor, klass="Series", examples=_register_series_examples)
329354
def register_series_accessor(name: str):
330355
from pandas import Series
331356

332357
return _register_accessor(name, Series)
333358

334359

335-
@doc(_register_accessor, klass="Index")
360+
_register_index_examples = """
361+
An accessor that only accepts integers could
362+
have a class defined like this:
363+
364+
>>> @pd.api.extensions.register_index_accessor("int_accessor")
365+
... class IntAccessor:
366+
... def __init__(self, pandas_obj):
367+
... if not all(isinstance(x, int) for x in pandas_obj):
368+
... raise AttributeError("The index must only be an integer value")
369+
... self._obj = pandas_obj
370+
...
371+
... def even(self):
372+
... return [x for x in self._obj if x % 2 == 0]
373+
>>> df = pd.DataFrame.from_dict(
374+
... {"row1": {"1": 1, "2": "a"}, "row2": {"1": 2, "2": "b"}}, orient="index"
375+
... )
376+
>>> df.index.int_accessor
377+
Traceback (most recent call last):
378+
...
379+
AttributeError: The index must only be an integer value.
380+
>>> df = pd.DataFrame(
381+
... {"col1": [1, 2, 3, 4], "col2": ["a", "b", "c", "d"]}, index=[1, 2, 5, 8]
382+
... )
383+
>>> df.index.int_accessor.even()
384+
[2, 8]"""
385+
386+
387+
@doc(_register_accessor, klass="Index", examples=_register_index_examples)
336388
def register_index_accessor(name: str):
337389
from pandas import Index
338390

pyproject.toml

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ requires = [
66
"meson==1.2.1",
77
"wheel",
88
"Cython~=3.0.5", # Note: sync with setup.py, environment.yml and asv.conf.json
9-
# Any NumPy version should be fine for compiling. Users are unlikely
10-
# to get a NumPy<1.25 so the result will be compatible with all relevant
11-
# NumPy versions (if not it is presumably compatible with their version).
12-
# Pin <2.0 for releases until tested against an RC. But explicitly allow
13-
# testing the `.dev0` nightlies (which require the extra index).
14-
"numpy>1.22.4,<=2.0.0.dev0",
9+
# Force numpy higher than 2.0rc1, so that built wheels are compatible
10+
# with both numpy 1 and 2
11+
"numpy>=2.0.0rc1",
1512
"versioneer[toml]"
1613
]
1714

@@ -152,9 +149,6 @@ setup = ['--vsenv'] # For Windows
152149
skip = "cp36-* cp37-* cp38-* pp* *_i686 *_ppc64le *_s390x"
153150
build-verbosity = "3"
154151
environment = {LDFLAGS="-Wl,--strip-all"}
155-
# TODO: remove this once numpy 2.0 proper releases
156-
# and specify numpy 2.0 as a dependency in [build-system] requires in pyproject.toml
157-
before-build = "pip install numpy==2.0.0rc1"
158152
test-requires = "hypothesis>=6.46.1 pytest>=7.3.2 pytest-xdist>=2.2.0"
159153
test-command = """
160154
PANDAS_CI='1' python -c 'import pandas as pd; \
@@ -163,9 +157,7 @@ test-command = """
163157
"""
164158

165159
[tool.cibuildwheel.windows]
166-
# TODO: remove this once numpy 2.0 proper releases
167-
# and specify numpy 2.0 as a dependency in [build-system] requires in pyproject.toml
168-
before-build = "pip install delvewheel numpy==2.0.0rc1"
160+
before-build = "pip install delvewheel"
169161
repair-wheel-command = "delvewheel repair -w {dest_dir} {wheel}"
170162

171163
[[tool.cibuildwheel.overrides]]

0 commit comments

Comments
 (0)