def write_layers( path: str, layers: List[Layer], plugin_name: Optional[str] = None, writer: Optional[WriterContribution] = None, ) -> List[str]: """ Write layers to a file using an NPE2 plugin. Parameters ---------- path : str The path (file, directory, url) to write. layer_type : str All lower-class name of the layer class to be written. plugin_name : str, optional Name of the plugin to write data with. If None then all plugins corresponding to appropriate hook specification will be looped through to find the first one that can write the data. command_id : str, optional npe2 command identifier that uniquely identifies the command to ivoke to save layers. If specified, overrides, the plugin_name. Returns ------- list of str Empty list when no plugin was found, otherwise a list of file paths, if any, that were written. """ layer_data = [layer.as_layer_data_tuple() for layer in layers] if writer is None: try: return npe2.write( path=path, layer_data=layer_data, plugin_name=plugin_name ) except ValueError: return [] n = sum(ltc.max() for ltc in writer.layer_type_constraints()) args = (path, *layer_data[0][:2]) if n <= 1 else (path, layer_data) res = writer.exec(args=args) if isinstance( res, str ): # pragma: no cover # it shouldn't be... bad plugin. return [res] return res or []
def write_layer_data_with_plugins( path: str, layer_data: List[FullLayerData], *, plugin_name: Optional[str] = 'napari', ) -> List[str]: """Write layer data out into a folder one layer at a time. Call ``napari_write_<layer>`` for each layer using the ``layer.name`` variable to modify the path such that the layers are written to unique files in the folder. If ``plugin_name`` is ``None`` then we just directly call ``plugin_manager.hook.napari_write_<layer>()`` which will loop through implementations and stop when the first one returns a non-None result. The order in which implementations are called can be changed with the implementation sorter/disabler. If ``plugin_name`` is provided, then we call the ``napari_write_<layer_type>`` for that plugin, and if it fails we error. By default, we restrict this function to using only napari ``builtins`` plugins. Parameters ---------- path : str path to file/directory layer_data : list of napari.types.LayerData List of layer_data, where layer_data is ``(data, meta, layer_type)``. plugin_name : str, optional Name of the plugin to use for saving. If None then all plugins corresponding to appropriate hook specification will be looped through to find the first one that can save the data. By default, only builtin napari implementations are used. Returns ------- list of str A list of any filepaths that were written. """ from tempfile import TemporaryDirectory import npe2 if plugin_name == 'builtins': plugin_name = 'napari' # remember whether it was there to begin with already_existed = os.path.exists(path) # Try and make directory based on current path if it doesn't exist if not already_existed: os.makedirs(path) written: List[str] = [] # the files that were actually written try: # build in a temporary directory and then move afterwards, # it makes cleanup easier if an exception is raised inside. with TemporaryDirectory(dir=path) as tmp: # Loop through data for each layer for layer_data_tuple in layer_data: _, meta, type_ = layer_data_tuple # Create full path using name of layer full_path = abspath_or_url(os.path.join(tmp, meta['name'])) if type_ == 'image': # workaround for https://github.com/napari/npe2/issues/129 full_path += '.tif' # Write out data using first plugin found for this hook spec # or named plugin if provided out = npe2.write( path=full_path, layer_data=[layer_data_tuple], # type: ignore plugin_name=plugin_name, ) written.extend(out) for fname in os.listdir(tmp): shutil.move(os.path.join(tmp, fname), path) except Exception as exc: if not already_existed: shutil.rmtree(path, ignore_errors=True) raise exc return written