Пример #1
0
    def extract(self, path: Path, clean: bool = True):
        """
        Extract the archive content.

        Parameters
        ----------
        path : Path
            A non-existing directory path where the archive content is extracted
        clean : bool (default: True)
            Whether the archive content has to be cleaned from Mac OS hidden
            files (.DS_STORE, __MACOSX).
        """
        if path.exists() and not path.is_dir():
            raise ArchiveError(
                f"{self} cannot be extracted in {path} because "
                f"it already exists or it is not a directory"
            )

        try:
            shutil.unpack_archive(self.absolute(), path, self._format.name)
        except shutil.ReadError as e:
            raise ArchiveError(str(e))

        if clean:
            bad_filenames = ['.DS_STORE', '__MACOSX']
            for bad_filename in bad_filenames:
                for bad_path in path.rglob(bad_filename):
                    bad_path.unlink(missing_ok=True)
Пример #2
0
def test_roles(app, settings, fake_files):
    root = Path(settings.root)
    for ff in fake_files.values():
        name = ff['filepath']
        role = ff['role']
        path = root / Path(name)
        if role == "upload":
            assert path.has_upload_role()
            assert not path.has_original_role()
            assert not path.has_spatial_role()
            assert not path.has_spectral_role()
        elif role == "original":
            assert not path.has_upload_role()
            assert path.has_original_role()
            assert not path.has_spatial_role()
            assert not path.has_spectral_role()
        elif role == "visualisation":
            assert not path.has_upload_role()
            assert not path.has_original_role()
            assert path.has_spatial_role()
            assert not path.has_spectral_role()
        elif role == "spectral":
            assert not path.has_upload_role()
            assert not path.has_original_role()
            assert not path.has_spatial_role()
            assert path.has_spectral_role()
        else:
            assert not path.has_upload_role()
            assert not path.has_original_role()
            assert not path.has_spatial_role()
            assert not path.has_spectral_role()
Пример #3
0
 def mkdir(self, directory: Path):
     """Make a directory (with notifications)"""
     try:
         directory.mkdir()  # TODO: mode
     except (FileNotFoundError, FileExistsError, OSError) as e:
         self.notify(ImportEventType.FILE_ERROR, directory, exception=e)
         raise FileErrorProblem(directory)
Пример #4
0
def export_upload(
        background: BackgroundTasks,
        path: Path = Depends(imagepath_parameter),
):
    """
    Export the upload representation of an image.
    """
    image = path.get_original()
    check_representation_existence(image)

    upload_file = image.get_upload().resolve()
    media_type = image.media_type
    if upload_file.is_dir():
        # if archive has been deleted
        tmp_export = Path(f"/tmp/{unique_name_generator()}")
        make_zip_archive(tmp_export, upload_file)

        def cleanup(tmp):
            tmp.unlink(missing_ok=True)

        background.add_task(cleanup, tmp_export)
        upload_file = tmp_export
        media_type = "application/zip"

    return FileResponse(upload_file, media_type=media_type, filename=path.name)
Пример #5
0
def test_collection(app, settings, fake_files):
    root = Path(settings.root)
    for ff in fake_files.values():
        name = ff['filepath']
        is_collection = ff['collection']
        path = root / Path(name)
        assert path.is_collection() == is_collection
        assert path.is_single() == (not is_collection)
Пример #6
0
 def mksymlink(self, path: Path, target: Path):
     """Make a symlink from path to target (with notifications)"""
     try:
         path.symlink_to(
             target,
             target_is_directory=target.is_dir()
         )
     except (FileNotFoundError, FileExistsError, OSError) as e:
         self.notify(ImportEventType.FILE_ERROR, path, exception=e)
         raise FileErrorProblem(path)
Пример #7
0
def show_representation(representation: FileRole,
                        path: Path = Depends(imagepath_parameter)):
    """
    Get image representation info
    """
    rpr = path.get_representation(representation)
    return RepresentationInfo.from_path(rpr)
Пример #8
0
def show_plane_histogram(
    z_slices: conint(ge=0),
    timepoints: conint(ge=0),
    path: Path = Depends(imagepath_parameter),
    channels: Optional[List[conint(ge=0)]] = Query(
        None, description="Only return histograms for these channels"
    ),
):
    """
    Get histogram per plane.
    """
    in_image = path.get_spatial()
    check_representation_existence(in_image)

    channels = ensure_list(channels)
    z_slices = ensure_list(z_slices)
    timepoints = ensure_list(timepoints)

    channels = get_channel_indexes(in_image, channels)
    z_slices = get_zslice_indexes(in_image, z_slices)
    timepoints = get_timepoint_indexes(in_image, timepoints)

    hist_info = []
    htype = in_image.histogram_type()
    for c, z, t in itertools.product(channels, z_slices, timepoints):
        mini, maxi = in_image.plane_bounds(c, z, t)
        hist_info.append(
            PlaneHistogramInfo(
                channel=c, z_slice=z, timepoint=t, type=htype,
                color=in_image.channels[c].hex_color,
                minimum=mini, maximum=maxi
            )
        )

    return response_list(hist_info)
Пример #9
0
def show_channels_histogram_bounds(
    path: Path = Depends(imagepath_parameter),
    channels: Optional[List[conint(ge=0)]] = Query(
        None, description="Only return histograms for these channels"
    ),
):
    """
    Get histogram bounds per channel where all planes (Z,T) are merged.
    """
    in_image = path.get_spatial()
    check_representation_existence(in_image)

    channels = ensure_list(channels)
    channels = get_channel_indexes(in_image, channels)

    hist_info = []
    htype = in_image.histogram_type()
    hist_filter = operator.itemgetter(*channels)
    channels_bounds = hist_filter(in_image.channels_bounds())
    if len(channels) == 1:
        channels_bounds = [channels_bounds]

    for channel, bounds in zip(channels, channels_bounds):
        mini, maxi = bounds
        hist_info.append(
            ChannelHistogramInfo(
                channel=channel, type=htype,
                color=in_image.channels[channel].hex_color,
                minimum=mini, maximum=maxi
            )
        )

    return response_list(hist_info)
Пример #10
0
    def deploy_histogram(self, image: Image) -> Histogram:
        """
        Deploy an histogram representation of the image so that it can be used for
        efficient histogram requests.
        """
        self.histogram_path = self.processed_dir / Path(HISTOGRAM_STEM)
        self.notify(
            ImportEventType.START_HISTOGRAM_DEPLOY,
            self.histogram_path, image
        )
        try:
            self.histogram = build_histogram_file(
                image, self.histogram_path, HistogramType.FAST
            )
        except (FileNotFoundError, FileExistsError) as e:
            self.notify(
                ImportEventType.ERROR_HISTOGRAM, self.histogram_path, image,
                exception=e
            )
            raise FileErrorProblem(self.histogram_path)

        assert self.histogram.has_histogram_role()
        self.notify(
            ImportEventType.END_HISTOGRAM_DEPLOY, self.histogram_path, image
        )
        return self.histogram
Пример #11
0
 def end_spatial_deploy(self, spatial_path: Path, *args, **kwargs):
     if not spatial_path.is_symlink():
         # The spatial path is not a symbolic link
         # -> a conversion has been performed
         uf = self.get_uf(spatial_path)
         uf.status = UploadedFile.IMPORTED
         uf.update()
Пример #12
0
    def end_unpacking(self,
                      path: Path,
                      unpacked_path: Path,
                      *args,
                      format: AbstractFormat = None,
                      is_collection: bool = False,
                      **kwargs):
        parent = self.get_uf(path)
        parent.status = UploadedFile.UNPACKED
        parent.update()

        if not is_collection:
            uf = UploadedFile()
            uf.status = UploadedFile.UPLOADED  # Better status ?
            uf.contentType = format.get_identifier()  # TODO
            uf.size = unpacked_path.size
            uf.filename = str(unpacked_path.relative_to(FILE_ROOT_PATH))
            uf.originalFilename = str(format.main_path.name)
            uf.ext = ""
            uf.storage = parent.storage
            uf.user = parent.user
            uf.parent = parent.id
            uf.imageServer = parent.imageServer
            uf.save()
            self.path_uf_mapping[str(unpacked_path)] = uf
Пример #13
0
def _show_associated_image(
        request: Request,
        response: Response,  # required for @cache  # noqa
        path: Path,
        height,
        width,
        length,
        associated_key,
        headers,
        config: Settings):
    in_image = path.get_spatial()
    check_representation_existence(in_image)

    associated = getattr(in_image, f'associated_{associated_key.value}')
    if not associated or not associated.exists:
        raise NoAppropriateRepresentationProblem(path, associated_key)

    out_format, mimetype = get_output_format(OutputExtension.NONE,
                                             headers.accept,
                                             VISUALISATION_MIMETYPES)
    req_size = get_thumb_output_dimensions(associated, height, width, length)
    out_size = safeguard_output_dimensions(headers.safe_mode,
                                           config.output_size_limit, *req_size)
    out_width, out_height = out_size

    return AssociatedResponse(in_image, associated_key, out_width, out_height,
                              out_format).http_response(
                                  mimetype,
                                  extra_headers=add_image_size_limit_header(
                                      dict(), *req_size, *out_size))
Пример #14
0
def show_associated(path: Path = Depends(imagepath_parameter)):
    """
    Get associated file info
    """
    original = path.get_original()
    check_representation_existence(original)
    return response_list(AssociatedInfo.from_image(original))
Пример #15
0
def show_channels(path: Path = Depends(imagepath_parameter)):
    """
    Get image channel info
    """
    original = path.get_original()
    check_representation_existence(original)
    return response_list(ChannelsInfo.from_image(original))
Пример #16
0
def show_instrument(path: Path = Depends(imagepath_parameter)):
    """
    Get image instrument info
    """
    original = path.get_original()
    check_representation_existence(original)
    return InstrumentInfo.from_image(original)
Пример #17
0
def show_normalized_pyramid(path: Path = Depends(imagepath_parameter)):
    """
    Get image normalized pyramid
    """
    original = path.get_original()
    check_representation_existence(original)
    return PyramidInfo.from_pyramid(original.normalized_pyramid)
Пример #18
0
def show_image(path: Path = Depends(imagepath_parameter)):
    """
    Get standard image info
    """
    original = path.get_original()
    check_representation_existence(original)
    return ImageInfo.from_image(original)
Пример #19
0
def list_representations(path: Path = Depends(imagepath_parameter)):
    """
    Get all image representation info
    """
    return response_list([
        RepresentationInfo.from_path(rpr)
        for rpr in path.get_representations()
    ])
Пример #20
0
def show_metadata(path: Path = Depends(imagepath_parameter)):
    """
    Get image metadata
    """
    original = path.get_original()
    check_representation_existence(original)

    store = original.raw_metadata
    return response_list([Metadata.from_metadata(md) for md in store.values()])
Пример #21
0
def test_extensions(app, settings):
    files = ("upload0/myfile.svs", "upload2/processed/myfile.ome.tiff",
             "upload5/processed/visualisation.mrxs.format")
    extensions = (".svs", ".ome.tiff", ".mrxs.format")

    for f, ext in zip(files, extensions):
        path = Path(settings.root, f)
        assert path.extension == ext
        assert path.true_stem == f.split("/")[-1].replace(ext, "")
Пример #22
0
def show_metadata_annotations(path: Path = Depends(imagepath_parameter)):
    """
    Get image annotation metadata
    """
    original = path.get_original()
    check_representation_existence(original)
    return response_list([
        MetadataAnnotation.from_metadata_annotation(a)
        for a in original.annotations
    ])
Пример #23
0
async def _show_drawing(
    request: Request,
    response: Response,  # required for @cache  # noqa
    path: Path,
    annotations,
    context_factor,
    try_square,
    point_cross,
    point_envelope_length,
    height,
    width,
    length,
    zoom,
    level,
    channels,
    z_slices,
    timepoints,
    min_intensities,
    max_intensities,
    filters,
    gammas,
    threshold,
    log,
    extension,
    headers,
    config,
    colormaps=None,
    c_reduction=ChannelReduction.ADD,
    z_reduction=None,
    t_reduction=None,
):
    in_image = path.get_spatial()
    check_representation_existence(in_image)

    annots = parse_annotations(ensure_list(annotations),
                               ignore_fields=['fill_color'],
                               default={'stroke_width': 1},
                               point_envelope_length=point_envelope_length,
                               origin=headers.annot_origin,
                               im_height=in_image.height)

    region = get_annotation_region(in_image, annots, context_factor,
                                   try_square)

    annot_style = dict(mode=AnnotationStyleMode.DRAWING,
                       point_cross=point_cross,
                       point_envelope_length=point_envelope_length)

    return await _show_window(request, response, path, region, height, width,
                              length, zoom, level, channels, z_slices,
                              timepoints, min_intensities, max_intensities,
                              filters, gammas, threshold, 8, Colorspace.AUTO,
                              annots, annot_style, extension, headers, config,
                              colormaps, c_reduction, z_reduction, t_reduction)
Пример #24
0
def export_file(path: Path = Depends(filepath_parameter)):
    """
    Export a file. All files in the server base path can be exported.
    """
    if path.is_dir():
        # TODO: zip and return the folder archive ?
        raise NotAFileProblem(path)

    return FileResponse(path,
                        media_type="application/octet-stream",
                        filename=path.name)
Пример #25
0
def show_image_histogram_bounds(
    path: Path = Depends(imagepath_parameter)
):
    """
    Get histogram info for full image where all planes (C,Z,T) are merged.
    """
    in_image = path.get_spatial()
    check_representation_existence(in_image)

    htype = in_image.histogram_type()
    mini, maxi = in_image.image_bounds()
    return HistogramInfo(type=htype, minimum=mini, maximum=maxi)
Пример #26
0
async def _show_crop(
    request: Request,
    response: Response,
    path: Path,
    annotations,
    context_factor,
    background_transparency,
    height,
    width,
    length,
    zoom,
    level,
    channels,
    z_slices,
    timepoints,
    min_intensities,
    max_intensities,
    filters,
    gammas,
    threshold,
    bits,
    colorspace,
    extension,
    headers,
    config,
    colormaps=None,
    c_reduction=ChannelReduction.ADD,
    z_reduction=None,
    t_reduction=None,
):
    in_image = path.get_spatial()
    check_representation_existence(in_image)

    annots = parse_annotations(ensure_list(annotations),
                               ignore_fields=['stroke_width', 'stroke_color'],
                               default={'fill_color': WHITE},
                               origin=headers.annot_origin,
                               im_height=in_image.height)

    region = get_annotation_region(in_image, annots, context_factor)

    annot_style = dict(mode=AnnotationStyleMode.CROP,
                       background_transparency=background_transparency)

    return await _show_window(request, response, path, region, height, width,
                              length, zoom, level, channels, z_slices,
                              timepoints, min_intensities, max_intensities,
                              filters, gammas, threshold, bits, colorspace,
                              annots, annot_style, extension, headers, config,
                              colormaps, c_reduction, z_reduction, t_reduction)
Пример #27
0
def compute_histogram(
    response: Response,
    background: BackgroundTasks,
    path: Path = Depends(imagepath_parameter),
    # companion_file_id: Optional[int] = Body(None, description="Cytomine ID for the histogram")
    sync: bool = True,
    overwrite: bool = True
):
    """
    Ask for histogram computation
    """
    in_image = path.get_spatial()
    check_representation_existence(in_image)

    hist_type = HistogramType.FAST  # TODO: allow to build complete histograms
    hist_path = in_image.processed_root() / Path(HISTOGRAM_STEM)

    if sync:
        build_histogram_file(in_image, hist_path, hist_type, overwrite)
        response.status_code = status.HTTP_201_CREATED
    else:
        background.add_task(build_histogram_file, in_image, hist_path, hist_type, overwrite)
        response.status_code = status.HTTP_202_ACCEPTED
Пример #28
0
def run_import(
    filepath: str, name: str, extra_listeners: Optional[List[ImportListener]] = None,
    prefer_copy: bool = False
):
    pending_file = Path(filepath)

    if extra_listeners is not None:
        if not type(extra_listeners) is list:
            extra_listeners = list(extra_listeners)
    else:
        extra_listeners = []

    listeners = [StdoutListener(name)] + extra_listeners
    fi = FileImporter(pending_file, name, listeners)
    fi.run(prefer_copy)
Пример #29
0
    def register_file(self, path: Path, parent_path: Path, *args, **kwargs):
        parent = self.get_uf(parent_path)

        uf = UploadedFile()
        uf.status = UploadedFile.UPLOADED
        uf.contentType = ""
        uf.size = path.size
        uf.filename = str(path.relative_to(FILE_ROOT_PATH))
        uf.originalFilename = str(path.name)
        uf.ext = ""
        uf.storage = parent.storage
        uf.user = parent.user
        uf.parent = parent.id
        uf.imageServer = parent.imageServer
        uf.save()
        self.path_uf_mapping[str(path)] = uf
Пример #30
0
def show_info(path: Path = Depends(imagepath_parameter)):
    """
    Get all image info
    """
    original = path.get_original()
    check_representation_existence(original)
    data = dict()
    data["image"] = ImageInfo.from_image(original)
    data["instrument"] = InstrumentInfo.from_image(original)
    data["associated"] = AssociatedInfo.from_image(original)
    data["channels"] = ChannelsInfo.from_image(original)
    data["representations"] = [
        RepresentationInfo.from_path(rpr)
        for rpr in original.get_representations()
    ]
    return data