diff --git a/setup.py b/setup.py index 06afd52..215617f 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setuptools.setup( name="slicedimage", - version="3.2.0", + version="4.0.0", description="Library to access sliced imaging data", author="Tony Tung", author_email="ttung@chanzuckerberg.com", diff --git a/slicedimage/__init__.py b/slicedimage/__init__.py index 1bf5742..d26a506 100644 --- a/slicedimage/__init__.py +++ b/slicedimage/__init__.py @@ -2,4 +2,4 @@ from ._collection import Collection from ._tile import Tile from ._tileset import TileSet -from .io import Reader, Writer, v0_0_0, v0_1_0, VERSIONS +from .io import Reader, v0_0_0, v0_1_0, Writer, WriterContract, VERSIONS diff --git a/slicedimage/backends/_disk.py b/slicedimage/backends/_disk.py index b31edd7..20c4bba 100644 --- a/slicedimage/backends/_disk.py +++ b/slicedimage/backends/_disk.py @@ -10,7 +10,7 @@ def __init__(self, basedir): def read_contextmanager(self, name, checksum_sha256=None): return _FileLikeContextManager(os.path.join(self._basedir, name), checksum_sha256) - def write_file_handle(self, name=None): + def write_file_handle(self, name): return open(os.path.join(self._basedir, name), "wb") diff --git a/slicedimage/io/__init__.py b/slicedimage/io/__init__.py index fca94a6..458adb9 100644 --- a/slicedimage/io/__init__.py +++ b/slicedimage/io/__init__.py @@ -1,6 +1,6 @@ # this import is here for compatibility reasons from slicedimage.url.resolve import resolve_path_or_url, resolve_url -from ._base import Reader, VERSIONS, Writer +from ._base import Reader, VERSIONS, Writer, WriterContract from ._v0_0_0 import v0_0_0 from ._v0_1_0 import v0_1_0 diff --git a/slicedimage/io/_base.py b/slicedimage/io/_base.py index 95cb890..0c22e3d 100644 --- a/slicedimage/io/_base.py +++ b/slicedimage/io/_base.py @@ -1,14 +1,31 @@ import codecs import json -import pathlib -import tempfile +import hashlib +import urllib.parse import warnings from abc import abstractmethod -from typing import MutableSequence, Sequence +from io import BytesIO +from pathlib import Path, PurePath, PurePosixPath +from typing import ( + BinaryIO, + Callable, + cast, + Mapping, + MutableSequence, + Optional, + Sequence, + TextIO, + Union, +) from packaging import version from slicedimage.url.resolve import resolve_url +from slicedimage._collection import Collection +from slicedimage._compat import fspath +from slicedimage._formats import ImageFormat +from slicedimage._tile import Tile +from slicedimage._tileset import TileSet from ._keys import CommonPartitionKeys @@ -55,44 +72,254 @@ def parse(self, json_doc, baseurl, backend_config): class Writer: @staticmethod - def write_to_path(partition, path, pretty=False, version_class=None, *args, **kwargs): + def write_to_path( + partition: Union[Collection, TileSet], + path: Path, + pretty: bool = False, + version_class=None, + *args, **kwargs): if isinstance(path, str): warnings.warn("Paths should be passed in as pathlib.Path objects", DeprecationWarning) - path = pathlib.Path(path) + path = Path(path) if version_class is None: version_class = VERSIONS[-1] - document = version_class.Writer().generate_partition_document( - partition, path, pretty, *args, **kwargs) - indent = 4 if pretty else None - with open(str(path), "w") as fh: - json.dump(document, fh, indent=indent, sort_keys=pretty) - @staticmethod - def default_partition_path_generator(parent_partition_path, partition_name): - parent_partition_stem = parent_partition_path.stem - partition_file = tempfile.NamedTemporaryFile( - suffix=".json", - prefix="{}-".format(parent_partition_stem), - dir=str(parent_partition_path.parent), - delete=False, - ) - return pathlib.Path(partition_file.name) + partition_path_generator = None # type: Optional[Callable[[PurePath, str], Path]] + if len(args) > 0: + partition_path_generator = args[0] + args = args[1:] + elif 'partition_path_generator' in kwargs: + partition_path_generator = kwargs.pop('partition_path_generator') + if partition_path_generator is not None: + warnings.warn( + "`partition_path_generator` is deprecated. Please use `WriterContract` to control " + "the behavior of image writing", + DeprecationWarning + ) + + tile_opener = None # type: Optional[Callable[[PurePath, Tile, str], BinaryIO]] + if len(args) > 0: + tile_opener = args[0] + args = args[1:] + elif 'tile_opener' in kwargs: + tile_opener = kwargs.pop('tile_opener') + if tile_opener is not None: + warnings.warn( + "`tile_opener` is deprecated. Please use `WriterContract` to control the behavior " + "of image writing", + DeprecationWarning + ) + + writer_contract = None # type: Optional[WriterContract] + if len(args) > 0: + writer_contract = args[0] + args = args[1:] + elif 'writer_contract' in kwargs: + writer_contract = kwargs.pop('writer_contract') + + if partition_path_generator is not None or tile_opener is not None: + if writer_contract is not None: + raise ValueError( + "Cannot specify both `writer_contract` and `partition_path_generator` or " + "`tile_opener`") + kwargs['writer_contract'] = CompatibilityWriterContract( + partition_path_generator, tile_opener) + elif writer_contract is not None: + kwargs['writer_contract'] = writer_contract + else: + kwargs['writer_contract'] = WriterContract() + + url = urllib.parse.urlunparse(("file", "", fspath(path), "", "", "")) + + return Writer.write_to_url(partition, url, pretty, version_class, *args, **kwargs) @staticmethod - def default_tile_opener(tileset_path, tile, ext): - tileset_stem = tileset_path.stem - return tempfile.NamedTemporaryFile( - suffix=".{}".format(ext), - prefix="{}-".format(tileset_stem), - dir=str(tileset_path.parent), - delete=False, - ) + def write_to_url( + partition: Union[Collection, TileSet], + url: str, + pretty: bool = False, + version_class=None, + *args, **kwargs): + if version_class is None: + version_class = VERSIONS[-1] + + document = version_class.Writer().generate_partition_document( + partition, url, pretty, *args, **kwargs) + indent = 4 if pretty else None + + backend, name, _ = resolve_url(url) + with backend.write_file_handle(name) as fh: + writer = cast(TextIO, codecs.getwriter("utf-8")(fh)) + json.dump(document, writer, indent=indent, sort_keys=pretty, ensure_ascii=False) @abstractmethod - def generate_partition_document(self, partition, path, pretty=False, *args, **kwargs): + def generate_partition_document( + self, + partition: Union[Collection, TileSet], + url: str, + pretty: bool = False, + *args, **kwargs): raise NotImplementedError() +class WriterContract(object): + def partition_url_generator(self, parent_partition_url: str, partition_name: str) -> str: + """Given the url of the parent partition and the name of a partition to be added to the + parent partition, return the url of the resulting of the resulting partition. + + Parameters + ---------- + parent_partition_url : str + The URL of the parent partition. + partition_name : str + The name of the partition we're adding to the parent partition. + + Returns + ------- + str : + The URL of the partition being added. + """ + parent_parsed_url = urllib.parse.urlparse(parent_partition_url) + parent_path = PurePosixPath(parent_parsed_url.path) + parent_stem = parent_path.stem + partition_path = parent_path.parent / "{}-{}.json".format(parent_stem, partition_name) + partition_parsed_url = parent_parsed_url._replace(path=str(partition_path)) + return urllib.parse.urlunparse(partition_parsed_url) + + def tile_url_generator(self, tileset_url: str, tile: Tile, ext: str) -> str: + """Given the url of a tileset and a tile to be added to the tileset, return the url where + the tile data is written to. + + Parameters + ---------- + tileset_url : str + The URL of the tileset + tile : Tile + The tile to be added to the tileset. + ext : str + The extension to be used for writing the tile data. + + Returns + ------- + str : + The URL of the tile being added. + """ + tileset_parsed_url = urllib.parse.urlparse(tileset_url) + tileset_path = PurePosixPath(tileset_parsed_url.path) + tileset_stem = tileset_path.stem + indices_sorted_str = "-".join([ + "{}{}".format(index_name, tile.indices[index_name]) + for index_name in sorted(tile.indices.keys()) + ]) + tile_path = tileset_path.parent / "{}-{}.{}".format(tileset_stem, indices_sorted_str, ext) + tile_parsed_url = tileset_parsed_url._replace(path=str(tile_path)) + return urllib.parse.urlunparse(tile_parsed_url) + + def write_tile( + self, + tile_url: str, + tile: Tile, + tile_format: ImageFormat, + backend_config: Optional[Mapping] = None, + ) -> str: + """Write the data for a tile to a given URL. + + Parameters + ---------- + tile_url : str + The URL of the tile. + tile : Tile + The tile to be written. + tile_format : ImageFormat + The format to write the tile in. + backend_config : Optional[Mapping] + Mapping from the backend names to the config + + Returns + ------- + str : + The sha256 of the tile being added. + """ + backend, name, _ = resolve_url(tile_url, backend_config=backend_config) + buffer_fh = BytesIO() + tile.write(buffer_fh, tile_format) + + buffer_fh.seek(0) + sha256 = hashlib.sha256(buffer_fh.getvalue()).hexdigest() + + buffer_fh.seek(0) + with backend.write_file_handle(name) as fh: + fh.write(buffer_fh.read()) + + return sha256 + + +class CompatibilityWriterContract(WriterContract): + """This provides a WriterContract to support the previous API of partition_path_generator and + tile_opener. This compatibility layer only works with URLs with the scheme ``file``.""" + def __init__( + self, + partition_path_generator: Optional[Callable[[PurePath, str], Path]] = None, + tile_opener: Optional[Callable[[PurePath, Tile, str], BinaryIO]] = None, + ): + self.partition_path_generator = partition_path_generator + self.tile_opener = tile_opener + + def partition_url_generator(self, parent_partition_url: str, partition_name: str) -> str: + """Given the url of the parent partition and the name of a partition to be added to the + parent partition, return the url of the resulting of the resulting partition. + + Parameters + ---------- + parent_partition_url : str + The URL of the parent partition. + partition_name : str + The name of the partition we're adding to the parent partition. + + Returns + ------- + str : + The URL of the partition being added. + """ + if self.partition_path_generator is None: + return super().partition_url_generator(parent_partition_url, partition_name) + parent_parsed_url = urllib.parse.urlparse(parent_partition_url) + assert parent_parsed_url.scheme == "file" + parent_path = PurePosixPath(parent_parsed_url.path) + partition_path = self.partition_path_generator(parent_path, partition_name) + partition_parsed_url = parent_parsed_url._replace(path=str(partition_path)) + return urllib.parse.urlunparse(partition_parsed_url) + + def tile_url_generator(self, tileset_url: str, tile: Tile, ext: str) -> str: + """Given the url of a tileset and a tile to be added to the tileset, return the url where + the tile data is written to. + + Parameters + ---------- + tileset_url : str + The URL of the tileset + tile : Tile + The tile to be added to the tileset. + ext : str + The extension to be used for writing the tile data. + + Returns + ------- + str : + The URL of the tile being added. + """ + if self.tile_opener is None: + return super().tile_url_generator(tileset_url, tile, ext) + tileset_parsed_url = urllib.parse.urlparse(tileset_url) + assert tileset_parsed_url.scheme == "file" + tileset_path = PurePosixPath(tileset_parsed_url.path) + with self.tile_opener(tileset_path, tile, ext) as open_fh: + tile_path = open_fh.name + + tile_parsed_url = tileset_parsed_url._replace(path=str(tile_path)) + return urllib.parse.urlunparse(tile_parsed_url) + + def _parse_collection(parse_method, baseurl, backend_config): """Return a method that binds a parse method, a baseurl, and a backend config to a method that accepts name and path of a partition belonging to a collection. The method should then return diff --git a/slicedimage/io/_v0_0_0.py b/slicedimage/io/_v0_0_0.py index df1f158..db19a75 100644 --- a/slicedimage/io/_v0_0_0.py +++ b/slicedimage/io/_v0_0_0.py @@ -1,16 +1,14 @@ -import hashlib import os -import warnings -from io import BytesIO from multiprocessing.pool import ThreadPool +from typing import Optional, Union -import pathlib from packaging import version from slicedimage._collection import Collection from slicedimage._formats import ImageFormat from slicedimage._tile import Tile from slicedimage._tileset import TileSet +from slicedimage.url.path import calculate_relative_url from slicedimage.url.resolve import resolve_url from . import _base from ._keys import ( @@ -110,18 +108,15 @@ def _actual_future(): class Writer(_base.Writer): def generate_partition_document( self, - partition, - path, - pretty=False, - partition_path_generator=_base.Writer.default_partition_path_generator, - tile_opener=_base.Writer.default_tile_opener, + partition: Union[Collection, TileSet], + url: str, + pretty: bool = False, + writer_contract: Optional[_base.WriterContract] = None, tile_format=ImageFormat.NUMPY, + *args, **kwargs ): - if isinstance(path, str): - warnings.warn("Paths should be passed in as pathlib.Path objects", - DeprecationWarning) - path = pathlib.Path(path) - + if writer_contract is None: + writer_contract = _base.WriterContract() json_doc = { CommonPartitionKeys.VERSION: v0_0_0.VERSION, CommonPartitionKeys.EXTRAS: partition.extras, @@ -129,16 +124,15 @@ def generate_partition_document( if isinstance(partition, Collection): json_doc[CollectionKeys.CONTENTS] = dict() for partition_name, partition in partition._partitions.items(): - partition_path = partition_path_generator(path, partition_name) - _base.Writer.write_to_path( - partition, partition_path, pretty, + partition_url = writer_contract.partition_url_generator(url, partition_name) + _base.Writer.write_to_url( + partition, partition_url, pretty, version_class=v0_0_0, - partition_path_generator=partition_path_generator, - tile_opener=tile_opener, + writer_contract=writer_contract, tile_format=tile_format, ) - json_doc[CollectionKeys.CONTENTS][partition_name] = str( - partition_path.relative_to(path.parent)) + json_doc[CollectionKeys.CONTENTS][partition_name] = calculate_relative_url( + url, partition_url) return json_doc elif isinstance(partition, TileSet): json_doc[TileSetKeys.DIMENSIONS] = tuple(partition.dimensions) @@ -159,22 +153,14 @@ def generate_partition_document( TileKeys.INDICES: tile.indices, } - with tile_opener(path, tile, tile_format.file_ext) as tile_fh: - buffer_fh = BytesIO() - tile.write(buffer_fh, tile_format) - - buffer_fh.seek(0) - tile.sha256 = hashlib.sha256(buffer_fh.getvalue()).hexdigest() - - buffer_fh.seek(0) - tile_fh.write(buffer_fh.read()) - tiledoc[TileKeys.FILE] = str( - pathlib.Path(tile_fh.name).relative_to(path.parent)) + tile_url = writer_contract.tile_url_generator(url, tile, tile_format.file_ext) + tiledoc[TileKeys.SHA256] = writer_contract.write_tile( + tile_url, tile, tile_format) + tiledoc[TileKeys.FILE] = calculate_relative_url(url, tile_url) if tile.tile_shape is not None: - tiledoc[TileKeys.TILE_SHAPE] = \ - Tile.format_dict_shape_to_tuple_shape(tile.tile_shape) - tiledoc[TileKeys.SHA256] = tile.sha256 + tiledoc[TileKeys.TILE_SHAPE] = Tile.format_dict_shape_to_tuple_shape( + tile.tile_shape) if tile_format is not None: tiledoc[TileKeys.TILE_FORMAT] = tile_format.name if len(tile.extras) != 0: diff --git a/slicedimage/io/_v0_1_0.py b/slicedimage/io/_v0_1_0.py index b6e787a..27aedf2 100644 --- a/slicedimage/io/_v0_1_0.py +++ b/slicedimage/io/_v0_1_0.py @@ -1,10 +1,7 @@ -import hashlib import os -import warnings -from io import BytesIO from multiprocessing.pool import ThreadPool +from typing import Optional, Union -import pathlib from packaging import version from slicedimage._collection import Collection @@ -12,6 +9,7 @@ from slicedimage._tile import Tile from slicedimage._tileset import TileSet from slicedimage._typeformatting import format_enum_keyed_dicts +from slicedimage.url.path import calculate_relative_url from slicedimage.url.resolve import resolve_url from . import _base from ._keys import ( @@ -109,18 +107,15 @@ def _actual_future(): class Writer(_base.Writer): def generate_partition_document( self, - partition, - path, - pretty=False, - partition_path_generator=_base.Writer.default_partition_path_generator, - tile_opener=_base.Writer.default_tile_opener, + partition: Union[Collection, TileSet], + url: str, + pretty: bool = False, + writer_contract: Optional[_base.WriterContract] = None, tile_format=ImageFormat.NUMPY, + *args, **kwargs ): - if isinstance(path, str): - warnings.warn("Paths should be passed in as pathlib.Path objects", - DeprecationWarning) - path = pathlib.Path(path) - + if writer_contract is None: + writer_contract = _base.WriterContract() json_doc = { CommonPartitionKeys.VERSION: v0_1_0.VERSION, CommonPartitionKeys.EXTRAS: partition.extras, @@ -128,15 +123,14 @@ def generate_partition_document( if isinstance(partition, Collection): json_doc[CollectionKeys.CONTENTS] = dict() for partition_name, partition in partition._partitions.items(): - partition_path = partition_path_generator(path, partition_name) - _base.Writer.write_to_path( - partition, partition_path, pretty, - partition_path_generator=partition_path_generator, - tile_opener=tile_opener, + partition_url = writer_contract.partition_url_generator(url, partition_name) + _base.Writer.write_to_url( + partition, partition_url, pretty, + writer_contract=writer_contract, tile_format=tile_format, ) - json_doc[CollectionKeys.CONTENTS][partition_name] = str( - partition_path.relative_to(path.parent)) + json_doc[CollectionKeys.CONTENTS][partition_name] = calculate_relative_url( + url, partition_url) return json_doc elif isinstance(partition, TileSet): json_doc[TileSetKeys.DIMENSIONS] = tuple(partition.dimensions) @@ -156,21 +150,13 @@ def generate_partition_document( TileKeys.INDICES: tile.indices, } - with tile_opener(path, tile, tile_format.file_ext) as tile_fh: - buffer_fh = BytesIO() - tile.write(buffer_fh, tile_format) - - buffer_fh.seek(0) - tile.sha256 = hashlib.sha256(buffer_fh.getvalue()).hexdigest() - - buffer_fh.seek(0) - tile_fh.write(buffer_fh.read()) - tiledoc[TileKeys.FILE] = str( - pathlib.Path(tile_fh.name).relative_to(path.parent)) + tile_url = writer_contract.tile_url_generator(url, tile, tile_format.file_ext) + tiledoc[TileKeys.SHA256] = writer_contract.write_tile( + tile_url, tile, tile_format) + tiledoc[TileKeys.FILE] = calculate_relative_url(url, tile_url) if tile.tile_shape is not None: tiledoc[TileKeys.TILE_SHAPE] = format_enum_keyed_dicts(tile.tile_shape) - tiledoc[TileKeys.SHA256] = tile.sha256 if tile_format is not None: tiledoc[TileKeys.TILE_FORMAT] = tile_format.name if len(tile.extras) != 0: diff --git a/tests/io_/v0_0_0/test_missing_shape.py b/tests/io_/v0_0_0/test_missing_shape.py index fb7dc54..46d8188 100644 --- a/tests/io_/v0_0_0/test_missing_shape.py +++ b/tests/io_/v0_0_0/test_missing_shape.py @@ -40,7 +40,7 @@ def test_tileset_without_shapes(self): with tempfile.TemporaryDirectory() as tempdir, \ tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name) + image, "file://{}".format(partition_file.name)) # remove the shape information from the tiles. for tile in partition_doc[TileSetKeys.TILES]: diff --git a/tests/io_/v0_0_0/test_reader.py b/tests/io_/v0_0_0/test_reader.py index d90b803..6a3ee69 100644 --- a/tests/io_/v0_0_0/test_reader.py +++ b/tests/io_/v0_0_0/test_reader.py @@ -123,7 +123,7 @@ def test_numpy(self): with tempfile.TemporaryDirectory() as tempdir: partition_path = os.path.join(tempdir, "tileset.json") partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_path) + image, "file://{}".format(partition_path)) with open(partition_path, "w") as fh: json.dump(partition_doc, fh) diff --git a/tests/io_/v0_0_0/test_write.py b/tests/io_/v0_0_0/test_write.py index 280c199..cd31809 100644 --- a/tests/io_/v0_0_0/test_write.py +++ b/tests/io_/v0_0_0/test_write.py @@ -43,7 +43,7 @@ def test_write_tileset(self): with tempfile.TemporaryDirectory() as tempdir, \ tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name) + image, "file://{}".format(partition_file.name)) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) partition_file.flush() @@ -97,7 +97,7 @@ def test_write_collection(self): with tempfile.TemporaryDirectory() as tempdir, \ tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - collection, partition_file.name) + collection, "file://{}".format(partition_file.name)) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) partition_file.flush() @@ -172,7 +172,7 @@ def test_checksum_on_write(self): tempfile.NamedTemporaryFile( suffix=".json", dir=output_tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name) + image, "file://{}".format(partition_file.name)) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) @@ -212,7 +212,7 @@ def test_write_tiff(self): tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: # create the tileset and save it. partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name, tile_format=ImageFormat.TIFF) + image, "file://{}".format(partition_file.name), tile_format=ImageFormat.TIFF) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) partition_file.flush() diff --git a/tests/io_/v0_1_0/test_missing_shape.py b/tests/io_/v0_1_0/test_missing_shape.py index fb7dc54..46d8188 100644 --- a/tests/io_/v0_1_0/test_missing_shape.py +++ b/tests/io_/v0_1_0/test_missing_shape.py @@ -40,7 +40,7 @@ def test_tileset_without_shapes(self): with tempfile.TemporaryDirectory() as tempdir, \ tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name) + image, "file://{}".format(partition_file.name)) # remove the shape information from the tiles. for tile in partition_doc[TileSetKeys.TILES]: diff --git a/tests/io_/v0_1_0/test_reader.py b/tests/io_/v0_1_0/test_reader.py index d90b803..6a3ee69 100644 --- a/tests/io_/v0_1_0/test_reader.py +++ b/tests/io_/v0_1_0/test_reader.py @@ -123,7 +123,7 @@ def test_numpy(self): with tempfile.TemporaryDirectory() as tempdir: partition_path = os.path.join(tempdir, "tileset.json") partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_path) + image, "file://{}".format(partition_path)) with open(partition_path, "w") as fh: json.dump(partition_doc, fh) diff --git a/tests/io_/v0_1_0/test_write.py b/tests/io_/v0_1_0/test_write.py index c29b810..420728d 100644 --- a/tests/io_/v0_1_0/test_write.py +++ b/tests/io_/v0_1_0/test_write.py @@ -43,7 +43,7 @@ def test_write_tileset(self): with tempfile.TemporaryDirectory() as tempdir, \ tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name) + image, "file://{}".format(partition_file.name)) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) partition_file.flush() @@ -97,7 +97,7 @@ def test_write_collection(self): with tempfile.TemporaryDirectory() as tempdir, \ tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - collection, partition_file.name) + collection, "file://{}".format(partition_file.name)) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) partition_file.flush() @@ -172,7 +172,7 @@ def test_checksum_on_write(self): tempfile.NamedTemporaryFile( suffix=".json", dir=output_tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name) + image, "file://{}".format(partition_file.name)) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) @@ -212,7 +212,7 @@ def test_write_tiff(self): tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: # create the tileset and save it. partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - image, partition_file.name, tile_format=ImageFormat.TIFF) + image, "file://{}".format(partition_file.name), tile_format=ImageFormat.TIFF) writer = codecs.getwriter("utf-8") json.dump(partition_doc, writer(partition_file)) partition_file.flush() @@ -282,7 +282,7 @@ def tile_opener(tileset_path, tile, ext): with tempfile.TemporaryDirectory() as tempdir, \ tempfile.NamedTemporaryFile(suffix=".json", dir=tempdir) as partition_file: partition_doc = slicedimage.v0_0_0.Writer().generate_partition_document( - collection, partition_file.name, + collection, "file://{}".format(partition_file.name), partition_path_generator=partition_path_generator, tile_opener=tile_opener, )