# Buggy code
def save(self, labels):
    """Save.

    Args:
        labels - (SemanticSegmentationLabels) labels to be saved
    """
    local_path = get_local_path(self.uri, self.tmp_dir)
    make_dir(local_path, use_dirname=True)

    transform = self.crs_transformer.get_affine_transform()
    crs = self.crs_transformer.get_image_crs()

    band_count = 1
    dtype = np.uint8
    if self.class_trans:
        band_count = 3

    if self.vector_output:
        # We need to store the whole output mask to run feature extraction.
        # If the raster is large, this will result in running out of memory, so
        # more work will be needed to get this to work in a scalable way. But this
        # is complicated because of the need to merge features that are split
        # across windows.
        mask = np.zeros((self.extent.ymax, self.extent.xmax), dtype=np.uint8)
    else:
        mask = None

    # https://github.com/mapbox/rasterio/blob/master/docs/quickstart.rst
    # https://rasterio.readthedocs.io/en/latest/topics/windowed-rw.html
    with rasterio.open(
        local_path,
        "w",
        driver="GTiff",
        height=self.extent.ymax,
        width=self.extent.xmax,
        count=band_count,
        dtype=dtype,
        transform=transform,
        crs=crs,
    ) as dataset:
        for window in labels.get_windows():
            class_labels = labels.get_label_arr(window, clip_extent=self.extent)
            clipped_window = (
                (window.ymin, window.ymin + class_labels.shape[0]),
                (window.xmin, window.xmin + class_labels.shape[1]),
            )
            if mask is not None:
                mask[
                    clipped_window[0][0] : clipped_window[0][1],
                    clipped_window[1][0] : clipped_window[1][1],
                ] = class_labels
            if self.class_trans:
                rgb_labels = self.class_trans.class_to_rgb(class_labels)
                for chan in range(3):
                    dataset.write_band(
                        chan + 1, rgb_labels[:, :, chan], window=clipped_window
                    )
            else:
                img = class_labels.astype(dtype)
                dataset.write_band(1, img, window=clipped_window)

    upload_or_copy(local_path, self.uri)

    if self.vector_output:
        import mask_to_polygons.vectorification as vectorification
        import mask_to_polygons.processing.denoise as denoise

        for vo in self.vector_output:
            denoise_radius = vo["denoise"]
            uri = vo["uri"]
            mode = vo["mode"]
            class_id = vo["class_id"]
            class_mask = np.array(mask == class_id, dtype=np.uint8)
            local_geojson_path = get_local_path(uri, self.tmp_dir)

            def transform(x, y):
                return self.crs_transformer.pixel_to_map((x, y))

            if denoise_radius > 0:
                class_mask = denoise.denoise(class_mask, denoise_radius)

            if uri and mode == "buildings":
                options = vo["building_options"]
                geojson = vectorification.geojson_from_mask(
                    mask=class_mask,
                    transform=transform,
                    mode=mode,
                    min_aspect_ratio=options["min_aspect_ratio"],
                    min_area=options["min_area"],
                    width_factor=options["element_width_factor"],
                    thickness=options["element_thickness"],
                )
            elif uri and mode == "polygons":
                geojson = vectorification.geojson_from_mask(
                    mask=class_mask, transform=transform, mode=mode
                )

            if local_geojson_path:
                with open(local_geojson_path, "w") as file_out:
                    file_out.write(geojson)
                    upload_or_copy(local_geojson_path, uri)


# Traceback (json.decoder.JSONDecodeError)

17:55:54
2019-10-01 17:55:54:rastervision.utils.files: INFO - Downloading s3://raster-vision-lf-dev/examples/test-output/21/spacenet-vegas-buildings-semantic-segmentation-pytorch/predict/buildings-semantic_segmentation/5058.tif to /opt/data/temp/tmp5903c076/tmpk2r7cdga/s3/raster-vision-lf-dev/examples/test-output/21/spacenet-vegas-buildings-semantic-segmentation-pytorch/predict/buildings-semantic_segmentat
2019-10-01 17:55:54:rastervision.utils.files: INFO - Downloading s3://raster-vision-lf-dev/examples/test-output/21/spacenet-vegas-buildings-semantic-segmentation-pytorch/predict/buildings-semantic_segmentation/5058.tif to /opt/data/temp/tmp5903c076/tmpk2r7cdga/s3/raster-vision-lf-dev/examples/test-output/21/spacenet-vegas-buildings-semantic-segmentation-pytorch/predict/buildings-semantic_segmentation/5058.tif

17:55:56
Traceback (most recent call last):

17:55:56
File "/opt/conda/lib/python3.6/runpy.py", line 193, in _run_module_as_main

17:55:56
"__main__", mod_spec)

17:55:56
File "/opt/conda/lib/python3.6/runpy.py", line 85, in _run_code

17:55:56
exec(code, run_globals)

17:55:56
File "/opt/src/rastervision/__main__.py", line 17, in <module>

17:55:56
rv.main()

17:55:56
File "/opt/conda/lib/python3.6/site-packages/click/core.py", line 722, in __call__

17:55:56
return self.main(*args, **kwargs)

17:55:56
File "/opt/conda/lib/python3.6/site-packages/click/core.py", line 697, in main

17:55:56
rv = self.invoke(ctx)

17:55:56
File "/opt/conda/lib/python3.6/site-packages/click/core.py", line 1066, in invoke

17:55:56
return _process_result(sub_ctx.command.invoke(sub_ctx))

17:55:56
File "/opt/conda/lib/python3.6/site-packages/click/core.py", line 895, in invoke

17:55:56
return ctx.invoke(self.callback, **ctx.params)

17:55:56
File "/opt/conda/lib/python3.6/site-packages/click/core.py", line 535, in invoke

17:55:56
return callback(*args, **kwargs)

17:55:56
File "/opt/src/rastervision/cli/main.py", line 294, in run_command

17:55:56
rv.runner.CommandRunner.run(command_config_uri)

17:55:56
File "/opt/src/rastervision/runner/command_runner.py", line 11, in run

17:55:56
CommandRunner.run_from_proto(msg)

17:55:56
File "/opt/src/rastervision/runner/command_runner.py", line 17, in run_from_proto

17:55:56
command.run()

17:55:56
File "/opt/src/rastervision/command/eval_command.py", line 24, in run

17:55:56
evaluator.process(scenes, tmp_dir)

17:55:56
File "/opt/src/rastervision/evaluation/semantic_segmentation_evaluator.py", line 75, in process

17:55:56
pred_geojson = pred_geojson_source.get_geojson()

17:55:56
File "/opt/src/rastervision/data/vector_source/vector_source.py", line 153, in get_geojson

17:55:56
self.geojson = self._get_geojson()

17:55:56
File "/opt/src/rastervision/data/vector_source/geojson_vector_source.py", line 25, in _get_geojson

17:55:56
geojson = json.loads(file_to_str(self.uri))

17:55:56
File "/opt/conda/lib/python3.6/json/__init__.py", line 354, in loads

17:55:56
return _default_decoder.decode(s)

17:55:56
File "/opt/conda/lib/python3.6/json/decoder.py", line 339, in decode

17:55:56
obj, end = self.raw_decode(s, idx=_w(s, 0).end())

17:55:56
File "/opt/conda/lib/python3.6/json/decoder.py", line 357, in raw_decode

17:55:56
raise JSONDecodeError("Expecting value", s, err.value) from None

17:55:56
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

# Fixed code
def save(self, labels):
    """Save.

    Args:
        labels - (SemanticSegmentationLabels) labels to be saved
    """
    local_path = get_local_path(self.uri, self.tmp_dir)
    make_dir(local_path, use_dirname=True)

    transform = self.crs_transformer.get_affine_transform()
    crs = self.crs_transformer.get_image_crs()

    band_count = 1
    dtype = np.uint8
    if self.class_trans:
        band_count = 3

    if self.vector_output:
        # We need to store the whole output mask to run feature extraction.
        # If the raster is large, this will result in running out of memory, so
        # more work will be needed to get this to work in a scalable way. But this
        # is complicated because of the need to merge features that are split
        # across windows.
        mask = np.zeros((self.extent.ymax, self.extent.xmax), dtype=np.uint8)
    else:
        mask = None

    # https://github.com/mapbox/rasterio/blob/master/docs/quickstart.rst
    # https://rasterio.readthedocs.io/en/latest/topics/windowed-rw.html
    with rasterio.open(
        local_path,
        "w",
        driver="GTiff",
        height=self.extent.ymax,
        width=self.extent.xmax,
        count=band_count,
        dtype=dtype,
        transform=transform,
        crs=crs,
    ) as dataset:
        for window in labels.get_windows():
            class_labels = labels.get_label_arr(window, clip_extent=self.extent)
            clipped_window = (
                (window.ymin, window.ymin + class_labels.shape[0]),
                (window.xmin, window.xmin + class_labels.shape[1]),
            )
            if mask is not None:
                mask[
                    clipped_window[0][0] : clipped_window[0][1],
                    clipped_window[1][0] : clipped_window[1][1],
                ] = class_labels
            if self.class_trans:
                rgb_labels = self.class_trans.class_to_rgb(class_labels)
                for chan in range(3):
                    dataset.write_band(
                        chan + 1, rgb_labels[:, :, chan], window=clipped_window
                    )
            else:
                img = class_labels.astype(dtype)
                dataset.write_band(1, img, window=clipped_window)

    upload_or_copy(local_path, self.uri)

    if self.vector_output:
        import mask_to_polygons.vectorification as vectorification
        import mask_to_polygons.processing.denoise as denoise

        for vo in self.vector_output:
            denoise_radius = vo["denoise"]
            uri = vo["uri"]
            mode = vo["mode"]
            class_id = vo["class_id"]
            class_mask = np.array(mask == class_id, dtype=np.uint8)

            def transform(x, y):
                return self.crs_transformer.pixel_to_map((x, y))

            if denoise_radius > 0:
                class_mask = denoise.denoise(class_mask, denoise_radius)

            if uri and mode == "buildings":
                options = vo["building_options"]
                geojson = vectorification.geojson_from_mask(
                    mask=class_mask,
                    transform=transform,
                    mode=mode,
                    min_aspect_ratio=options["min_aspect_ratio"],
                    min_area=options["min_area"],
                    width_factor=options["element_width_factor"],
                    thickness=options["element_thickness"],
                )
            elif uri and mode == "polygons":
                geojson = vectorification.geojson_from_mask(
                    mask=class_mask, transform=transform, mode=mode
                )

            str_to_file(geojson, uri)