Source code for plugins.download

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#
# Copyright 2007 - 2021 Glencoe Software, Inc. All rights reserved.
# Use is subject to license terms supplied in LICENSE.txt

"""
   download plugin

   Plugin read by omero.cli.Cli during initialization. The method(s)
   defined here will be added to the Cli class for later use.
"""

import sys
import omero
import os
from omero.cli import BaseControl, CLI, ProxyStringType
from omero.gateway import BlitzGateway

HELP = """Download a File, Image or Fileset with a specified ID to a target file
or directory.

Examples:

    # Download OriginalFile 2 to local_file
    omero download 2 local_file
    # Download Original File 2 to the stdout
    omero download 2 -

    # Download the OriginalFile linked to FileAnnotation 20 to local_file
    omero download FileAnnotation:20 local_file

    # Download the OriginalFiles linked to Image 5 into a directory
    # The Files will be named as they are in OMERO's Managed repository
    omero download Image:5 output_dir
    # Download the OriginalFiles linked to Fileset 6 into a directory
    omero download Fileset:6 output_dir
"""


[docs] class StdOutHandle(): """ File handle for writing bytes to std.out """ # https://github.com/pexpect/pexpect/pull/31/files
[docs] @staticmethod def write(b): # Handle stdout.write for bytes return sys.stdout.write(b.decode('ascii', 'replace'))
[docs] class DownloadControl(BaseControl): def _configure(self, parser): parser.add_argument( "object", type=ProxyStringType("OriginalFile"), help="Object to download of form <object>:<id>. " "OriginalFile is assumed if <object>: is omitted.") parser.add_argument( "filename", help="Local filename (or path for Fileset) to be saved to. '-' for stdout") parser.add_argument( "--insert_fileset_folder", action="store_true", help="Adding 'Fileset_xxxx' folder in the download path") parser.set_defaults(func=self.__call__) parser.add_login_arguments() def __call__(self, args): client = self.ctx.conn(args) obj = args.object # e.g. "ImageI" -> "Image" dtype = obj.__class__.__name__[:-1] conn = BlitzGateway(client_obj=client) conn.SERVICE_OPTS.setOmeroGroup(-1) insert_fileset_folder = args.insert_fileset_folder if dtype == "Fileset": fileset = self.get_object(conn, dtype, obj.id.val) self.download_fileset(conn, fileset, args.filename, insert_fileset_folder) elif dtype == "Image": image = self.get_object(conn, dtype, obj.id.val) fileset = image.getFileset() if fileset is None: self.ctx.die(602, 'Input image has no associated Fileset') self.download_fileset(conn, fileset, args.filename, insert_fileset_folder) else: orig_file = self.get_file(client.sf, dtype, obj.id.val) target_file = str(args.filename) # only expect single file self.download_file(client, orig_file, target_file)
[docs] def download_fileset(self, conn, fileset, dir_path, insert_fileset_folder=False): self.ctx.out(f"Fileset: {fileset.id}") template_prefix = fileset.getTemplatePrefix() if insert_fileset_folder: dir_path = os.path.join(dir_path, f"Fileset_{fileset.id}") for orig_file in fileset.listFiles(): file_path = orig_file.path.replace(template_prefix, "") target_dir = os.path.join(dir_path, file_path) os.makedirs(target_dir, exist_ok=True) target_path = os.path.join(target_dir, orig_file.name) self.download_file(conn.c, orig_file._obj, target_path)
[docs] def download_file(self, client, orig_file, target_file): perms = orig_file.details.permissions name = omero.constants.permissions.BINARYACCESS if perms.isRestricted(name): self.ctx.die(66, ("Download of OriginalFile:" "%s is restricted") % orig_file.id.val) try: if target_file == "-": client.download(orig_file, filehandle=StdOutHandle()) sys.stdout.flush() else: self.ctx.out( f"Downloading file ID: {orig_file.id.val} to {target_file}") if os.path.exists(target_file): self.ctx.out(f"File exists! Skipping...") else: client.download(orig_file, target_file) except omero.ClientError as ce: self.ctx.die(67, "ClientError: %s" % ce) except omero.ValidationException as ve: # Possible, though unlikely after previous check self.ctx.die(67, "Unknown ValidationException: %s" % ve.message) except omero.ResourceError as re: # ID exists in DB, but not on FS self.ctx.die(67, "ResourceError: %s" % re.message)
[docs] def get_object(self, conn, dtype, obj_id): result = conn.getObject(dtype, obj_id) if result is None: self.ctx.die(601, f'No {dtype} with input ID: {obj_id}') return result
[docs] def get_file(self, session, dtype, obj_id): query = session.getQueryService() # Handle OriginalFile:id if dtype == "OriginalFile": try: ofile = query.get("OriginalFile", obj_id, {'omero.group': '-1'}) return ofile except omero.ValidationException: self.ctx.die(601, 'No OriginalFile with input ID') # Handle FileAnnotation:id if dtype == "FileAnnotation": fa = None try: fa = query.findByQuery(( "select fa from FileAnnotation fa " "left outer join fetch fa.file " "where fa.id = :id"), omero.sys.ParametersI().addId(obj_id), {'omero.group': '-1'}) except omero.ValidationException: pass if fa is None: self.ctx.die(601, 'No FileAnnotation with input ID') return fa.getFile() self.ctx.die(601, 'Invalid object input. Use e.g. Image:ID')
try: register("download", DownloadControl, HELP) except NameError: if __name__ == "__main__": cli = CLI() cli.register("download", DownloadControl, HELP) cli.invoke(sys.argv[1:])