From 14aa8bcd90e7e98235f1654e33fa4ae45863570a Mon Sep 17 00:00:00 2001
From: Peter Swain <pswain@Home-iMac.local>
Date: Wed, 22 May 2024 13:23:45 +0100
Subject: [PATCH] docs(omero): cosmetic changes

---
 src/aliby/io/omero.py | 145 ++++++++++++++++++++----------------------
 1 file changed, 69 insertions(+), 76 deletions(-)

diff --git a/src/aliby/io/omero.py b/src/aliby/io/omero.py
index 8d453f5..d4c11a4 100644
--- a/src/aliby/io/omero.py
+++ b/src/aliby/io/omero.py
@@ -1,6 +1,4 @@
-"""
-Tools to manage I/O using a remote OMERO server.
-"""
+"""Tools to manage I/O using a remote OMERO server."""
 
 import re
 import typing as t
@@ -31,7 +29,8 @@ PIXEL_TYPES = {
 
 class BridgeOmero:
     """
-    Core to interact with OMERO, using credentials or fetching them from h5 file (temporary trick).
+    Interact with OMERO.
+
     See
     https://docs.openmicroscopy.org/omero/5.6.0/developers/Python.html
     """
@@ -44,6 +43,8 @@ class BridgeOmero:
         ome_id: int = None,
     ):
         """
+        Initialise with OMERO login details.
+
         Parameters
         ----------
         host : string
@@ -51,33 +52,40 @@ class BridgeOmero:
         username: string
         password : string
         ome_id: Optional int
-            Unique identifier on Omero database. Used to fetch specific objects.
+            Unique identifier on Omero database.
+            Used to fetch specific objects.
         """
-        # assert all((host, username, password)), str(f"Invalid credentials host:{host}, user:{username}, pass:{pass}")
-        assert all(
-            (host, username, password)
-        ), f"Invalid credentials. host: {host}, user: {username}, pwd: {password}"
-
+        if host is None or username is None or password is None:
+            raise Exception(
+                f"Invalid credentials. host: {host}, user: {username},"
+                f" pwd: {password}"
+            )
         self.conn = None
         self.host = host
         self.username = username
         self.password = password
         self.ome_id = ome_id
 
-    # standard method required for Python's with statement
     def __enter__(self):
+        """For Python's with statement."""
         self.create_gate()
-
         return self
 
+    def __exit__(self, *exc) -> bool:
+        """For Python's with statement."""
+        for e in exc:
+            if e is not None:
+                print(e)
+        self.conn.close()
+        return False
+
     @property
     def ome_class(self):
-        # Initialise Omero Object Wrapper for instances when applicable.
+        """Initialise Omero Object Wrapper for instances when applicable."""
         if not hasattr(self, "_ome_class"):
             assert (
                 self.conn.isConnected() and self.ome_id is not None
             ), "No Blitz connection or valid omero id"
-
             ome_type = [
                 valid_name
                 for valid_name in ("Dataset", "Image")
@@ -88,35 +96,22 @@ class BridgeOmero:
                 )
             ][0]
             self._ome_class = self.conn.getObject(ome_type, self.ome_id)
-
             assert self._ome_class, f"{ome_type} {self.ome_id} not found."
-
         return self._ome_class
 
     def create_gate(self) -> bool:
+        """Connect to OMERO."""
         self.conn = BlitzGateway(
             host=self.host, username=self.username, passwd=self.password
         )
         self.conn.connect()
         self.conn.c.enableKeepAlive(60)
-
         self.conn.isConnected()
 
-    # standard method required for Python's with statement
-    def __exit__(self, *exc) -> bool:
-        for e in exc:
-            if e is not None:
-                print(e)
-
-        self.conn.close()
-        return False
-
     @classmethod
-    def server_info_from_h5(
-        cls,
-        filepath: t.Union[str, Path],
-    ):
-        """Return server info from hdf5 file.
+    def server_info_from_h5(cls, filepath: t.Union[str, Path]):
+        """
+        Return server info from hdf5 file.
 
         Parameters
         ----------
@@ -124,11 +119,6 @@ class BridgeOmero:
             BridgeOmero class
         filepath : t.Union[str, Path]
             Location of hdf5 file.
-
-        Examples
-        --------
-        FIXME: Add docs.
-
         """
         bridge = BridgeH5(filepath)
         meta = safe_load(bridge.meta_h5["parameters"])["general"]
@@ -136,10 +126,12 @@ class BridgeOmero:
         return server_info
 
     def set_id(self, ome_id: int):
+        """Set ome_id attribute."""
         self.ome_id = ome_id
 
     @property
     def file_annotations(self):
+        """Get file annotations."""
         valid_annotations = [
             ann.getFileName()
             for ann in self.ome_class.listAnnotations()
@@ -150,7 +142,10 @@ class BridgeOmero:
     def add_file_as_annotation(
         self, file_to_upload: t.Union[str, Path], **kwargs
     ):
-        """Upload annotation to object on OMERO server. Only valid in subclasses.
+        """
+        Upload annotation to object on OMERO server.
+
+        Only valid in subclasses.
 
         Parameters
         ----------
@@ -158,7 +153,6 @@ class BridgeOmero:
         **kwargs: Additional keyword arguments passed on
             to BlitzGateway.createFileAnnfromLocalFile
         """
-
         file_annotation = self.conn.createFileAnnfromLocalFile(
             file_to_upload,
             mimetype="text/plain",
@@ -169,30 +163,35 @@ class BridgeOmero:
 
 class Dataset(BridgeOmero):
     """
-    Tool to interact with Omero Datasets remotely, access their
-    metadata and associated files and images.
+    Interact with Omero Datasets remotely.
 
+    Access their metadata and associated files and images.
 
     Parameters
     ----------
-    expt_id: int Dataset id on server
-    server_info: dict host, username and password
-
+    expt_id: int
+        Dataset id on server
+    server_info: dict
+        Host, username and password
     """
 
     def __init__(self, expt_id: int, **server_info):
+        """Initialise with experiment OMERO ID and server details."""
         super().__init__(ome_id=expt_id, **server_info)
 
     @property
     def name(self):
+        """Get name."""
         return self.ome_class.getName()
 
     @property
     def date(self):
+        """Get date."""
         return self.ome_class.getDate()
 
     @property
     def unique_name(self):
+        """Create unique name."""
         return "_".join(
             (
                 str(self.ome_id),
@@ -202,12 +201,13 @@ class Dataset(BridgeOmero):
         )
 
     def get_images(self):
+        """Get dict of image names and IDs from OMERO."""
         return {
             im.getName(): im.getId() for im in self.ome_class.listChildren()
         }
 
     def get_channels(self):
-        """Get channels from OMERO."""
+        """Get list of channels from OMERO."""
         for im in self.ome_class.listChildren():
             channels = [ch.getLabel() for ch in im.getChannels()]
             break
@@ -215,6 +215,7 @@ class Dataset(BridgeOmero):
 
     @property
     def files(self):
+        """Get files from OMERO."""
         if not hasattr(self, "_files"):
             self._files = {
                 x.getFileName(): x
@@ -227,11 +228,11 @@ class Dataset(BridgeOmero):
             )
         elif len(self.file_annotations) != len(self._files):
             raise Exception("Number of files and annotations do not match")
-
         return self._files
 
     @property
     def tags(self):
+        """Get tags from OMERO."""
         if self._tags is None:
             self._tags = {
                 x.getname(): x
@@ -241,6 +242,7 @@ class Dataset(BridgeOmero):
         return self._tags
 
     def cache_logs(self, root_dir):
+        """Save the log files for an experiment."""
         valid_suffixes = ("txt", "log")
         for _, annotation in self.files.items():
             filepath = root_dir / annotation.getFileName().replace("/", "_")
@@ -268,11 +270,6 @@ class Dataset(BridgeOmero):
             Image class
         filepath : t.Union[str, Path]
             Location of hdf5 file.
-
-        Examples
-        --------
-        FIXME: Add docs.
-
         """
         bridge = BridgeH5(filepath)
         dataset_keys = ("omero_id", "omero_id,", "dataset_id")
@@ -284,14 +281,11 @@ class Dataset(BridgeOmero):
 
 
 class Image(BridgeOmero):
-    """
-    Loads images from OMERO and gives access to the data and metadata.
-    """
+    """Load images from OMERO and their data and metadata."""
 
     def __init__(self, image_id: int, **server_info):
         """
-        Establishes the connection to the OMERO server via the Argo
-        base class.
+        Connect to the OMERO server.
 
         Parameters
         ----------
@@ -315,11 +309,6 @@ class Image(BridgeOmero):
             Image class
         filepath : t.Union[str, Path]
             Location of h5 file.
-
-        Examples
-        --------
-        FIXME: Add docs.
-
         """
         bridge = BridgeH5(filepath)
         image_id = bridge.meta_h5["image_id"]
@@ -327,17 +316,21 @@ class Image(BridgeOmero):
 
     @property
     def name(self):
+        """Get name."""
         return self.ome_class.getName()
 
     @property
     def data(self):
+        """Get image data as a 5D dask array - TCXYZ."""
         return get_data_lazy(self.ome_class)
 
     @property
     def metadata(self):
         """
-        Store metadata saved in OMERO: image size, number of time points,
-        labels of channels, and image name.
+        Get metadata from OMERO as a dict.
+
+        Get image size, number of time points, labels of channels,
+        and image name.
         """
         meta = dict()
         meta["size_x"] = self.ome_class.getSizeX()
@@ -352,17 +345,16 @@ class Image(BridgeOmero):
 
 class UnsafeImage(Image):
     """
-    Loads images from OMERO and gives access to the data and metadata.
-    This class is a temporary solution while we find a way to use
-    context managers inside napari. It risks resulting in zombie connections
-    and producing freezes in an OMERO server.
+    Load images from OMERO and gives access to the data and metadata.
 
+    This class is a temporary solution while we find a way to use
+    context managers inside napari. It risks resulting in zombie
+    connections and producing freezes in an OMERO server.
     """
 
     def __init__(self, image_id, **server_info):
         """
-        Establishes the connection to the OMERO server via the Argo
-        base class.
+        Connect to the OMERO server.
 
         Parameters
         ----------
@@ -375,6 +367,7 @@ class UnsafeImage(Image):
 
     @property
     def data(self):
+        """Get image data as a 5D dask array - TCXYZ."""
         try:
             return get_data_lazy(self.ome_class)
         except Exception as e:
@@ -384,26 +377,26 @@ class UnsafeImage(Image):
 
 def get_data_lazy(image) -> da.Array:
     """
-    Get 5D dask array, with delayed reading from OMERO image.
+    Get 5D dask array - TCXYZ.
+
+    Use delayed reading from OMERO image.
     """
     nt, nc, nz, ny, nx = [getattr(image, f"getSize{x}")() for x in "TCZYX"]
     pixels = image.getPrimaryPixels()
     dtype = PIXEL_TYPES.get(pixels.getPixelsType().value, None)
     # using dask
     get_plane = delayed(lambda idx: pixels.getPlane(*idx))
-
-    def get_lazy_plane(zct):
-        return da.from_delayed(get_plane(zct), shape=(ny, nx), dtype=dtype)
-
     # 5D stack: TCZXY
     t_stacks = []
-    for t in range(nt):
+    for tpt in range(nt):
         c_stacks = []
         for c in range(nc):
             z_stack = []
             for z in range(nz):
-                z_stack.append(get_lazy_plane((z, c, t)))
+                plane = da.from_delayed(
+                    get_plane((z, c, tpt)), shape=(ny, nx), dtype=dtype
+                )
+                z_stack.append(plane)
             c_stacks.append(da.stack(z_stack))
         t_stacks.append(da.stack(c_stacks))
-
     return da.stack(t_stacks)
-- 
GitLab