# Buggy code
def _binary_op(f, reflexive=False, join="inner", drop_missing_vars=True):
    @functools.wraps(f)
    def func(self, other):
        if isinstance(other, groupby.GroupBy):
            return NotImplemented
        if hasattr(other, "indexes"):
            self, other = align(self, other, join=join, copy=False)
            empty_indexes = [d for d, s in self.dims.items() if s == 0]
            if empty_indexes:
                raise ValueError(
                    "no overlapping labels for some dimensions: %s" % empty_indexes
                )
        other_coords = getattr(other, "coords", None)
        ds = self.coords.merge(other_coords)
        g = f if not reflexive else lambda x, y: f(y, x)
        _calculate_binary_op(
            g, self, other, ds._variables, drop_missing_vars=drop_missing_vars
        )
        return ds

    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 _binary_op(f, reflexive=False, join="inner", drop_na_vars=True):
    @functools.wraps(f)
    def func(self, other):
        if isinstance(other, groupby.GroupBy):
            return NotImplemented
        if hasattr(other, "indexes"):
            self, other = align(self, other, join=join, copy=False)
            empty_indexes = [d for d, s in self.dims.items() if s == 0]
            if empty_indexes:
                raise ValueError(
                    "no overlapping labels for some dimensions: %s" % empty_indexes
                )
        g = f if not reflexive else lambda x, y: f(y, x)
        ds = self._calculate_binary_op(g, other, drop_na_vars=drop_na_vars)
        return ds

    return func