@@ -252,6 +252,8 @@ class Grouper:
252
252
axis : int
253
253
sort : bool
254
254
dropna : bool
255
+ _gpr_index : Index | None
256
+ _grouper : Index | None
255
257
256
258
_attributes : tuple [str , ...] = ("key" , "level" , "freq" , "axis" , "sort" )
257
259
@@ -279,6 +281,7 @@ def __init__(
279
281
self .sort = sort
280
282
281
283
self .grouper = None
284
+ self ._gpr_index = None
282
285
self .obj = None
283
286
self .indexer = None
284
287
self .binner = None
@@ -288,8 +291,11 @@ def __init__(
288
291
289
292
@final
290
293
@property
291
- def ax (self ):
292
- return self .grouper
294
+ def ax (self ) -> Index :
295
+ index = self ._gpr_index
296
+ if index is None :
297
+ raise ValueError ("_set_grouper must be called before ax is accessed" )
298
+ return index
293
299
294
300
def _get_grouper (self , obj : FrameOrSeries , validate : bool = True ):
295
301
"""
@@ -317,6 +323,7 @@ def _get_grouper(self, obj: FrameOrSeries, validate: bool = True):
317
323
validate = validate ,
318
324
dropna = self .dropna ,
319
325
)
326
+
320
327
return self .binner , self .grouper , self .obj
321
328
322
329
@final
@@ -338,14 +345,17 @@ def _set_grouper(self, obj: FrameOrSeries, sort: bool = False):
338
345
339
346
# Keep self.grouper value before overriding
340
347
if self ._grouper is None :
341
- self ._grouper = self .grouper
348
+ # TODO: What are we assuming about subsequent calls?
349
+ self ._grouper = self ._gpr_index
342
350
self ._indexer = self .indexer
343
351
344
352
# the key must be a valid info item
345
353
if self .key is not None :
346
354
key = self .key
347
355
# The 'on' is already defined
348
- if getattr (self .grouper , "name" , None ) == key and isinstance (obj , Series ):
356
+ if getattr (self ._gpr_index , "name" , None ) == key and isinstance (
357
+ obj , Series
358
+ ):
349
359
# Sometimes self._grouper will have been resorted while
350
360
# obj has not. In this case there is a mismatch when we
351
361
# call self._grouper.take(obj.index) so we need to undo the sorting
@@ -390,10 +400,8 @@ def _set_grouper(self, obj: FrameOrSeries, sort: bool = False):
390
400
# error: Incompatible types in assignment (expression has type
391
401
# "FrameOrSeries", variable has type "None")
392
402
self .obj = obj # type: ignore[assignment]
393
- # error: Incompatible types in assignment (expression has type "Index",
394
- # variable has type "None")
395
- self .grouper = ax # type: ignore[assignment]
396
- return self .grouper
403
+ self ._gpr_index = ax
404
+ return self ._gpr_index
397
405
398
406
@final
399
407
@property
0 commit comments