class_docstr: Holds the grouping information for a single key
  
  Parameters
  ----------
  index : Index
  grouper :
  obj :
  name :
  level :
  observed : boolean, default False
      If we are a Categorical, use the observed values
  in_axis : if the Grouping is a column in self.obj and hence among
      Groupby.exclusions list
  
  Returns
  -------
  **Attributes**:
    * indices : dict of {group -> index_list}
    * labels : ndarray, group labels
    * ids : mapping of label -> group
    * counts : array of group counts
    * group_index : unique groups
    * groups : dict of {group -> label_list}
code: def __init__(
      self,
      index,
      grouper=None,
      obj=None,
      name=None,
      level=None,
      sort=True,
      observed=False,
      in_axis=False,
  ):
      self.name = name
      self.level = level
      self.grouper = _convert_grouper(index, grouper)
      self.all_grouper = None
      self.index = index
      self.sort = sort
      self.obj = obj
      self.observed = observed
      self.in_axis = in_axis
  
      # right place for this?
      if isinstance(grouper, (Series, Index)) and name is None:
          self.name = grouper.name
  
      if isinstance(grouper, MultiIndex):
          self.grouper = grouper.values
  
      # we have a single grouper which may be a myriad of things,
      # some of which are dependent on the passing in level
  
      if level is not None:
          if not isinstance(level, int):
              if level not in index.names:
                  raise AssertionError(
                      "Level {} not in index".format(level)
                  )
              level = index.names.index(level)
  
          if self.name is None:
              self.name = index.names[level]
  
          (
              self.grouper,
              self._labels,
              self._group_index,
          ) = index._get_grouper_for_level(self.grouper, level)
  
      # a passed Grouper like, directly get the grouper in the same way
      # as single grouper groupby, use the group_info to get labels
      elif isinstance(self.grouper, Grouper):
          # get the new grouper; we already have disambiguated
          # what key/level refer to exactly, don't need to
          # check again as we have by this point converted these
          # to an actual value (rather than a pd.Grouper)
          _, grouper, _ = self.grouper._get_grouper(
              self.obj, validate=False
          )
          if self.name is None:
              self.name = grouper.result_index.name
          self.obj = self.grouper.obj
          self.grouper = grouper
  
      else:
          if self.grouper is None and self.name is not None:
              self.grouper = self.obj[self.name]
  
          elif isinstance(self.grouper, (list, tuple)):
              self.grouper = com.asarray_tuplesafe(self.grouper)
  
          # a passed Categorical
          elif is_categorical_dtype(self.grouper):
              from pandas.core.groupby.categorical import (
                  recode_for_groupby,
              )
  
              self.grouper, self.all_grouper = recode_for_groupby(
                  self.grouper, self.sort, observed
              )
              categories = self.grouper.categories
  
              # we make a CategoricalIndex out of the cat grouper
              # preserving the categories / ordered attributes
              self._labels = self.grouper.codes
              if observed:
                  codes = algorithms.unique1d(self.grouper.codes)
                  codes = codes[codes != -1]
              else:
                  codes = np.arange(len(categories))
  
              self._group_index = CategoricalIndex(
                  Categorical.from_codes(
                      codes=codes,
                      categories=categories,
                      ordered=self.grouper.ordered,
                  )
              )
  
          # we are done
          if isinstance(self.grouper, Grouping):
              self.grouper = self.grouper.grouper
  
          # no level passed
          elif not isinstance(
              self.grouper, (Series, Index, ExtensionArray, np.ndarray)
          ):
              if getattr(self.grouper, "ndim", 1) != 1:
                  t = self.name or str(type(self.grouper))
                  raise ValueError(
                      "Grouper for '{}' not 1-dimensional".format(t)
                  )
              self.grouper = self.index.map(self.grouper)
              if not (
                  hasattr(self.grouper, "__len__")
                  and len(self.grouper) == len(self.index)
              ):
                  errmsg = (
                      "Grouper result violates len(labels) == "
                      "len(data)\nresult: %s"
                      % pprint_thing(self.grouper)
                  )
                  self.grouper = None  # Try for sanity
                  raise AssertionError(errmsg)
  
      # if we have a date/time-like grouper, make sure that we have
      # Timestamps like
      if getattr(self.grouper, "dtype", None) is not None:
          if is_datetime64_dtype(self.grouper):
              from pandas import to_datetime
  
              self.grouper = to_datetime(self.grouper)
          elif is_timedelta64_dtype(self.grouper):
              from pandas import to_timedelta
  
              self.grouper = to_timedelta(self.grouper)
  
imports: import warnings
  import numpy
  import pandas.compat
  from pandas.compat import callable, zip
  from pandas.util._decorators import cache_readonly
  from pandas.core.dtypes.common import ensure_categorical, is_categorical_dtype, is_datetime64_dtype, is_hashable, is_list_like, is_scalar, is_timedelta64_dtype
  from pandas.core.dtypes.generic import ABCSeries
  import pandas.core.algorithms
  from pandas.core.arrays import Categorical, ExtensionArray
  import pandas.core.common
  from pandas.core.frame import DataFrame
  from pandas.core.groupby.ops import BaseGrouper
  from pandas.core.index import CategoricalIndex, Index, MultiIndex
  from pandas.core.series import Series
  from pandas.io.formats.printing import pprint_thing
label_desc: Use image node_id 1 to create a new Grouping object from inherited base classes: object with example: obj = Grouping(index, grouper, obj, name, level, sort, observed, in_axis)