# Buggy code
def _inplace_binary_op(f):
    @functools.wraps(f)
    def func(self, other):
        if isinstance(other, groupby.GroupBy):
            raise TypeError(
                "in-place operations between a Dataset and "
                "a grouped object are not permitted"
            )
        other_coords = getattr(other, "coords", None)
        with self.coords._merge_inplace(other_coords):
            # make a defensive copy of variables to modify in-place so we
            # can rollback in case of an exception
            # note: when/if we support automatic alignment, only copy the
            # variables that will actually be included in the result
            dest_vars = dict((k, self._variables[k].copy()) for k in self.data_vars)
            _calculate_binary_op(f, dest_vars, other, dest_vars, inplace=True)
            self._variables.update(dest_vars)
        return self

    return func


# Traceback (AttributeError)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/Users/shoyer/miniconda/envs/rapid/lib/python2.7/site-packages/IPython/core/formatters.pyc in __call__(self, obj)
693                 type_pprinters=self.type_printers,
694                 deferred_pprinters=self.deferred_printers)
--> 695             printer.pretty(obj)
696             printer.flush()
697             return stream.getvalue()

/Users/shoyer/miniconda/envs/rapid/lib/python2.7/site-packages/IPython/lib/pretty.pyc in pretty(self, obj)
399                             if callable(meth):
400                                 return meth(obj, self, cycle)
--> 401             return _default_pprint(obj, self, cycle)
402         finally:
403             self.end_group()

/Users/shoyer/miniconda/envs/rapid/lib/python2.7/site-packages/IPython/lib/pretty.pyc in _default_pprint(obj, p, cycle)
519     if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs:
520         # A user-provided repr. Find newlines and replace them with p.break_()
--> 521         _repr_pprint(obj, p, cycle)
522         return
523     p.begin_group(1, '<')

/Users/shoyer/miniconda/envs/rapid/lib/python2.7/site-packages/IPython/lib/pretty.pyc in _repr_pprint(obj, p, cycle)
701     """A pprint that just redirects to the normal repr function."""
702     # Find newlines and replace them with p.break_()
--> 703     output = repr(obj)
704     for idx,output_line in enumerate(output.splitlines()):
705         if idx:

/Users/shoyer/dev/xray/xray/core/dataset.pyc in __repr__(self)
1043
1044     def __repr__(self):
-> 1045         return formatting.dataset_repr(self)
1046
1047     def isel(self, **indexers):

/Users/shoyer/dev/xray/xray/core/formatting.pyc in dataset_repr(ds)
231
232     summary.append(coords_repr(ds.coords, col_width=col_width))
--> 233     summary.append(vars_repr(ds.data_vars, col_width=col_width))
234     if ds.attrs:
235         summary.append(attrs_repr(ds.attrs))

/Users/shoyer/dev/xray/xray/core/formatting.pyc in _mapping_repr(mapping, title, summarizer, col_width)
170     summary = ['%s:' % title]
171     if mapping:
--> 172         summary += [summarizer(k, v, col_width) for k, v in mapping.items()]
173     else:
174         summary += [EMPTY_REPR]

/Users/shoyer/miniconda/envs/rapid/lib/python2.7/_abcoll.pyc in items(self)
412     def items(self):
413         "D.items() -> list of D's (key, value) pairs, as 2-tuples"
--> 414         return [(key, self[key]) for key in self]
415
416     def values(self):

/Users/shoyer/dev/xray/xray/core/dataset.pyc in __getitem__(self, key)
371     def __getitem__(self, key):
372         if key not in self._dataset._coord_names:
--> 373             return self._dataset[key]
374         else:
375             raise KeyError(key)

/Users/shoyer/dev/xray/xray/core/dataset.pyc in __getitem__(self, key)
751         key = np.asarray(key)
752         if key.ndim == 0:
--> 753             return DataArray._new_from_dataset(self, key.item())
754         else:
755             return self._copy_listed(key)

/Users/shoyer/dev/xray/xray/core/dataarray.pyc in _new_from_dataset(cls, dataset, name)
198         """
199         obj = object.__new__(cls)
--> 200         obj._dataset = dataset._copy_listed([name], keep_attrs=False)
201         if name not in obj._dataset:
202             # handle virtual variables

/Users/shoyer/dev/xray/xray/core/dataset.pyc in _copy_listed(self, names, keep_attrs)
680         needed_dims = set()
681         for v in variables.values():
--> 682             needed_dims.update(v._dims)
683         for k in self._coord_names:
684             if set(self._variables[k]._dims) <= needed_dims:

AttributeError: 'NotImplementedType' object has no attribute '_dims'

# Fixed code
def _inplace_binary_op(f):
    @functools.wraps(f)
    def func(self, other):
        if isinstance(other, groupby.GroupBy):
            raise TypeError(
                "in-place operations between a Dataset and "
                "a grouped object are not permitted"
            )
        if hasattr(other, "indexes"):
            other = other.reindex_like(self, copy=False)
        # we don't want to actually modify arrays in-place
        g = ops.inplace_to_noninplace_op(f)
        ds = self._calculate_binary_op(g, other, inplace=True)
        self._replace_vars_and_dims(
            ds._variables, ds._coord_names, ds._attrs, inplace=True
        )
        return self

    return func