# Buggy code
def __call__(self, datasets, optional_datasets=None, **info):
    if len(datasets) != 3:
        raise ValueError("Expected 3 datasets, got %d" % (len(datasets),))

    area = None
    n = {}
    p1, p2, p3 = datasets
    if optional_datasets:
        high_res = optional_datasets[0]
        low_res = datasets[["red", "green", "blue"].index(self.high_resolution_band)]
        if high_res.info["area"] != low_res.info["area"]:
            if np.mod(high_res.shape[0], low_res.shape[0]) or np.mod(
                high_res.shape[1], low_res.shape[1]
            ):
                raise IncompatibleAreas(
                    "High resolution band is not mapped the same area as the low resolution bands"
                )
            else:
                f0 = high_res.shape[0] / low_res.shape[0]
                f1 = high_res.shape[1] / low_res.shape[1]
                if p1.shape != high_res.shape:
                    p1 = np.ma.repeat(np.ma.repeat(p1, f0, axis=0), f1, axis=1)
                    p1.info["area"] = high_res.info["area"]
                if p2.shape != high_res.shape:
                    p2 = np.ma.repeat(np.ma.repeat(p2, f0, axis=0), f1, axis=1)
                    p2.info["area"] = high_res.info["area"]
                if p3.shape != high_res.shape:
                    p3 = np.ma.repeat(np.ma.repeat(p3, f0, axis=0), f1, axis=1)
                    p3.info["area"] = high_res.info["area"]
                area = high_res.info["area"]
        if "rows_per_scan" in high_res.info:
            n.setdefault("rows_per_scan", high_res.info["rows_per_scan"])
        n.setdefault("resolution", high_res.info["resolution"])
        if self.high_resolution_band == "red":
            LOG.debug("Sharpening image with high resolution red band")
            ratio = high_res.data / p1.data
            r = high_res.data
            g = p2.data * ratio
            b = p3.data * ratio
        elif self.high_resolution_band == "green":
            LOG.debug("Sharpening image with high resolution green band")
            ratio = high_res.data / p2.data
            r = p1.data * ratio
            g = high_res.data
            b = p3.data * ratio
        elif self.high_resolution_band == "blue":
            LOG.debug("Sharpening image with high resolution blue band")
            ratio = high_res.data / p3.data
            r = p1.data * ratio
            g = p2.data * ratio
            b = high_res.data
        else:
            # no sharpening
            r = p1.data
            g = p2.data
            b = p3.data
        mask = p1.mask | p2.mask | p3.mask | high_res.mask
    else:
        r, g, b = p1.data, p2.data, p3.data
        mask = p1.mask | p2.mask | p3.mask

    # Collect information that is the same between the projectables
    info = combine_info(*datasets)
    info.update(n)
    # Update that information with configured information (including name)
    info.update(self.info)
    # Force certain pieces of metadata that we *know* to be true
    info["wavelength"] = None
    info.setdefault("standard_name", "true_color")
    info["mode"] = self.info.get("mode", "RGB")
    if area is not None:
        info["area"] = area
    return Dataset(
        data=np.concatenate(([r], [g], [b]), axis=0),
        mask=np.array([[mask, mask, mask]]),
        **info,
    )


# Traceback (AttributeError)
[INFO: 2017-12-12 08:14:04 : satpy.writers.cf_writer] Saving datasets to NetCDF4/CF.
[INFO: 2017-12-12 08:14:04 : satpy.writers.cf_writer] No longitude and latitude data to save.
[INFO: 2017-12-12 08:14:04 : satpy.writers.cf_writer] No grid mapping to save.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-24-58ece08c15f3> in <module>()
----> 1 lcl.save_datasets(writer='cf', filename='/tmp/foo.nc')

/home/lahtinep/Software/pytroll/packages/satpy/satpy/scene.pyc in save_datasets(self, writer, datasets, **kwargs)
632             datasets = self.datasets.values()
633         writer = self.get_writer(writer, **kwargs)
--> 634         writer.save_datasets(datasets, **kwargs)
635
636     def get_writer(self, writer="geotiff", **kwargs):

/home/lahtinep/Software/pytroll/packages/satpy/satpy/writers/cf_writer.pyc in save_datasets(self, datasets, filename, **kwargs)
176                     coords = [line_coord, pixel_coord]
177
--> 178                 domain = cf.Domain(dim=coords,
179                                    aux=aux,
180                                    ref=grid_mapping)

AttributeError: 'module' object has no attribute 'Domain'

# Fixed code
def __call__(self, datasets, optional_datasets=None, **info):
    if len(datasets) != 3:
        raise ValueError("Expected 3 datasets, got %d" % (len(datasets),))

    area = None
    n = {}
    p1, p2, p3 = datasets
    if optional_datasets:
        high_res = optional_datasets[0]
        low_res = datasets[["red", "green", "blue"].index(self.high_resolution_band)]
        if high_res.info["area"] != low_res.info["area"]:
            if np.mod(high_res.shape[0], low_res.shape[0]) or np.mod(
                high_res.shape[1], low_res.shape[1]
            ):
                raise IncompatibleAreas(
                    "High resolution band is not mapped the same area as the low resolution bands"
                )
            else:
                f0 = high_res.shape[0] / low_res.shape[0]
                f1 = high_res.shape[1] / low_res.shape[1]
                if p1.shape != high_res.shape:
                    p1 = np.ma.repeat(np.ma.repeat(p1, f0, axis=0), f1, axis=1)
                    p1.info["area"] = high_res.info["area"]
                if p2.shape != high_res.shape:
                    p2 = np.ma.repeat(np.ma.repeat(p2, f0, axis=0), f1, axis=1)
                    p2.info["area"] = high_res.info["area"]
                if p3.shape != high_res.shape:
                    p3 = np.ma.repeat(np.ma.repeat(p3, f0, axis=0), f1, axis=1)
                    p3.info["area"] = high_res.info["area"]
                area = high_res.info["area"]
        if "rows_per_scan" in high_res.info:
            n.setdefault("rows_per_scan", high_res.info["rows_per_scan"])
        n.setdefault("resolution", high_res.info["resolution"])
        if self.high_resolution_band == "red":
            LOG.debug("Sharpening image with high resolution red band")
            ratio = high_res.data / p1.data
            r = high_res.data
            g = p2.data * ratio
            b = p3.data * ratio
        elif self.high_resolution_band == "green":
            LOG.debug("Sharpening image with high resolution green band")
            ratio = high_res.data / p2.data
            r = p1.data * ratio
            g = high_res.data
            b = p3.data * ratio
        elif self.high_resolution_band == "blue":
            LOG.debug("Sharpening image with high resolution blue band")
            ratio = high_res.data / p3.data
            r = p1.data * ratio
            g = p2.data * ratio
            b = high_res.data
        else:
            # no sharpening
            r = p1.data
            g = p2.data
            b = p3.data
        mask = p1.mask | p2.mask | p3.mask | high_res.mask
    else:
        r, g, b = p1.data, p2.data, p3.data
        mask = p1.mask | p2.mask | p3.mask

    # Collect information that is the same between the projectables
    info = combine_metadata(*datasets)
    info.update(n)
    # Update that information with configured information (including name)
    info.update(self.attrs)
    # Force certain pieces of metadata that we *know* to be true
    info["wavelength"] = None
    info.setdefault("standard_name", "true_color")
    info["mode"] = self.attrs.get("mode", "RGB")
    if area is not None:
        info["area"] = area
    return Dataset(
        data=np.concatenate(([r], [g], [b]), axis=0),
        mask=np.array([[mask, mask, mask]]),
        **info,
    )