hrm_omero.omero

Functions related to direct interaction with OMERO.

  1"""Functions related to direct interaction with OMERO."""
  2
  3from datetime import datetime, timedelta
  4
  5import yaml
  6from Ice import ConnectionLostException  # pylint: disable-msg=no-name-in-module
  7from loguru import logger as log
  8
  9import omero.gateway
 10
 11from .decorators import connect_and_set_group
 12from .misc import printlog
 13
 14
 15def connect(user, passwd, host, port=4064):  # pragma: no cover
 16    """Establish the connection to an OMERO server.
 17
 18    DEPRECATED function, rather use BlitzGateway's `connect()` in a context manager or
 19    in a try/finally block to ensure the connection is properly `close()`d in any case!
 20
 21    NOTE: this does NOT check credentials - it only talks to the OMERO server to create
 22    the connection object. To verify a login, use `check_credentials()`.
 23
 24    Parameters
 25    ----------
 26    user : str
 27        The OMERO user name (e.g. `demo_user_01`).
 28    passwd : str
 29        The corresponding OMERO user password.
 30    host : str
 31        The OMERO server hostname or IP address.
 32    port : int, optional
 33        The OMERO port number, by default 4064.
 34
 35    Returns
 36    -------
 37    omero.gateway.BlitzGateway
 38        The OMERO connection object.
 39    """
 40    log.warning("'connect()' is DEPRECATED, will be removed in an upcoming release!")
 41    conn = omero.gateway.BlitzGateway(
 42        user, passwd, host=host, port=port, secure=True, useragent="HRM-OMERO.connector"
 43    )
 44    conn.connect()
 45    group = conn.getGroupFromContext()
 46    log.debug("Created new OMERO connection [user={}, group={}].", user, group.getId())
 47    return conn
 48
 49
 50def check_credentials(conn):
 51    """Check if supplied credentials are valid and print a message to stdout.
 52
 53    Parameters
 54    ----------
 55    conn : omero.gateway.BlitzGateway
 56        The OMERO connection object.
 57
 58    Returns
 59    -------
 60    bool
 61        True if connecting was successful (i.e. credentials are correct), False
 62        otherwise.
 63    """
 64    log.debug("Trying to connect to OMERO...")
 65    connected = conn.connect()
 66    if connected:
 67        uid = conn.getUserId()
 68        name = conn.getUser().getName()
 69        printlog("SUCCESS", f"Connected to OMERO [user={name}, uid={uid}].")
 70    else:
 71        printlog("WARNING", "ERROR logging into OMERO.")
 72
 73    try:
 74        group = conn.getGroupFromContext()
 75        log.debug(f"User's default group is {group.getId()} ({group.getName()}).")
 76    except ConnectionLostException:
 77        log.warning("Getting group context failed, password might be wrong!")
 78        return False
 79
 80    return connected
 81
 82
 83def extract_image_id(fname):
 84    """Parse the YAML returned by an 'omero import' call and extract the image ID.
 85
 86    Parameters
 87    ----------
 88    fname : str
 89        The path to the `yaml` file to parse.
 90
 91    Returns
 92    -------
 93    int or None
 94        The OMERO ID of the newly imported image, e.g. `1568386` or `None` in case
 95        parsing the file failed for any reason.
 96    """
 97    try:
 98        with open(fname, "r", encoding="utf-8") as stream:
 99            parsed = yaml.safe_load(stream)
100        if len(parsed[0]["Image"]) != 1:
101            msg = f"Unexpected YAML retrieved from OMERO, unable to parse:\n{parsed}"
102            printlog("ERROR", msg)
103            raise SyntaxError(msg)
104        image_id = parsed[0]["Image"][0]
105    except Exception as err:  # pylint: disable-msg=broad-except
106        printlog("ERROR", f"Error parsing imported image ID from YAML output: {err}")
107        return None
108
109    log.success(f"Successfully parsed Image ID from YAML: {image_id}")
110    return image_id
111
112
113@connect_and_set_group
114def add_annotation_keyvalue(conn, omero_id, annotation):
115    """Add a key-value "map" annotation to an OMERO object.
116
117    Parameters
118    ----------
119    conn : omero.gateway.BlitzGateway
120        The OMERO connection object.
121    omero_id : hrm_omero.misc.OmeroId
122        The ID of the OMERO object that should receive the annotation.
123    annotation : dict(dict)
124        The map annotation as returned by `hrm_omero.hrm.parse_summary()`.
125
126    Returns
127    -------
128    bool
129        True in case of success, False otherwise.
130
131    Raises
132    ------
133    RuntimeError
134        Raised in case re-establishing the OMERO connection fails.
135    """
136    log.trace(f"Adding a map annotation to {omero_id}")
137    target_obj = conn.getObject(omero_id.obj_type, omero_id.obj_id)
138    if target_obj is None:
139        log.warning(f"Unable to identify target object {omero_id} in OMERO!")
140        return False
141
142    for section in annotation:
143        namespace = f"Huygens Remote Manager - {section}"
144        log.trace(f"Using namespace [{namespace}] for annotation.")
145        map_ann = omero.gateway.MapAnnotationWrapper(conn)
146        map_ann.setValue(annotation[section].items())
147        map_ann.setNs(namespace)
148        map_ann.save()
149        target_obj.linkAnnotation(map_ann)
150        log.debug(f"Added key-value annotation using namespace [{namespace}].")
151
152    log.success(f"Added annotation to {omero_id}.")
153
154    return True
155
156
157@connect_and_set_group
158def new_project(conn, omero_id, proj_name):  # pragma: no cover
159    """Create a new Project in OMERO.
160
161    Parameters
162    ----------
163    conn : omero.gateway.BlitzGateway
164        The OMERO connection object.
165    omero_id : hrm_omero.misc.OmeroId
166        The ID of an OMERO object denoting an Experimenter.
167    proj_name : str
168        The name of the project to be created.
169    """
170    raise NotImplementedError("Creating Projects is not yet implemented.")
171
172
173@connect_and_set_group
174def new_dataset(conn, omero_id, ds_name):  # pragma: no cover
175    """Create a new Project in OMERO.
176
177    Parameters
178    ----------
179    conn : omero.gateway.BlitzGateway
180        The OMERO connection object.
181    omero_id : hrm_omero.misc.OmeroId
182        The ID of an OMERO object denoting a Project or an Experimenter.
183    ds_name : str
184        The name of the dataset to be created.
185    """
186    raise NotImplementedError("Creating Datasets is not yet implemented.")
187
188
189def find_recently_imported(conn, ds_id, label, age=15):
190    """Speculative way of identifying a recently imported image in a dataset.
191
192    Check children of a dataset in OMERO until one is found that is matching following
193    criteria:
194
195    * the import date is not more than the specified `age` tolerance ago (in seconds)
196    * the object name is matching the given label
197
198    Usually it will hit the right object in the first iteration as `listChildren()`
199    seems to give the images in reverse order of their import (newest ones first).
200
201    Parameters
202    ----------
203    conn : omero.gateway.BlitzGateway
204        The OMERO connection object.
205    ds_id : int or int-like
206        The ID of the dataset where to look for the image.
207    label : str
208        The label of the imported image, in the simplest case this is usually just the
209        file name of the original file without any path components.
210    age : int, optional
211        The maximum age in seconds that the identified image object in OMERO is allowed
212        to have, by default 15.
213
214    Returns
215    -------
216    omero.gateway._ImageWrapper or None
217        The "Image" object as returned by OMERO's BlitzGateway or None in case no image
218        object matching the criteria could be found.
219    """
220    imported = None
221    dset = conn.getObject("Dataset", ds_id)
222    for image in dset.listChildren():
223        if image.getName() != label:
224            continue
225
226        oldest_allowed_date = datetime.now() - timedelta(seconds=age)
227        date = image.getDate()
228        if date >= oldest_allowed_date:
229            imported = image
230            log.success(f"Found imported image: {image.getId()}")
231            break
232
233    return imported
def connect(user, passwd, host, port=4064):
16def connect(user, passwd, host, port=4064):  # pragma: no cover
17    """Establish the connection to an OMERO server.
18
19    DEPRECATED function, rather use BlitzGateway's `connect()` in a context manager or
20    in a try/finally block to ensure the connection is properly `close()`d in any case!
21
22    NOTE: this does NOT check credentials - it only talks to the OMERO server to create
23    the connection object. To verify a login, use `check_credentials()`.
24
25    Parameters
26    ----------
27    user : str
28        The OMERO user name (e.g. `demo_user_01`).
29    passwd : str
30        The corresponding OMERO user password.
31    host : str
32        The OMERO server hostname or IP address.
33    port : int, optional
34        The OMERO port number, by default 4064.
35
36    Returns
37    -------
38    omero.gateway.BlitzGateway
39        The OMERO connection object.
40    """
41    log.warning("'connect()' is DEPRECATED, will be removed in an upcoming release!")
42    conn = omero.gateway.BlitzGateway(
43        user, passwd, host=host, port=port, secure=True, useragent="HRM-OMERO.connector"
44    )
45    conn.connect()
46    group = conn.getGroupFromContext()
47    log.debug("Created new OMERO connection [user={}, group={}].", user, group.getId())
48    return conn

Establish the connection to an OMERO server.

DEPRECATED function, rather use BlitzGateway's connect() in a context manager or in a try/finally block to ensure the connection is properly close()d in any case!

NOTE: this does NOT check credentials - it only talks to the OMERO server to create the connection object. To verify a login, use check_credentials().

Parameters
  • user (str): The OMERO user name (e.g. demo_user_01).
  • passwd (str): The corresponding OMERO user password.
  • host (str): The OMERO server hostname or IP address.
  • port (int, optional): The OMERO port number, by default 4064.
Returns
  • omero.gateway.BlitzGateway: The OMERO connection object.
def check_credentials(conn):
51def check_credentials(conn):
52    """Check if supplied credentials are valid and print a message to stdout.
53
54    Parameters
55    ----------
56    conn : omero.gateway.BlitzGateway
57        The OMERO connection object.
58
59    Returns
60    -------
61    bool
62        True if connecting was successful (i.e. credentials are correct), False
63        otherwise.
64    """
65    log.debug("Trying to connect to OMERO...")
66    connected = conn.connect()
67    if connected:
68        uid = conn.getUserId()
69        name = conn.getUser().getName()
70        printlog("SUCCESS", f"Connected to OMERO [user={name}, uid={uid}].")
71    else:
72        printlog("WARNING", "ERROR logging into OMERO.")
73
74    try:
75        group = conn.getGroupFromContext()
76        log.debug(f"User's default group is {group.getId()} ({group.getName()}).")
77    except ConnectionLostException:
78        log.warning("Getting group context failed, password might be wrong!")
79        return False
80
81    return connected

Check if supplied credentials are valid and print a message to stdout.

Parameters
  • conn (omero.gateway.BlitzGateway): The OMERO connection object.
Returns
  • bool: True if connecting was successful (i.e. credentials are correct), False otherwise.
def extract_image_id(fname):
 84def extract_image_id(fname):
 85    """Parse the YAML returned by an 'omero import' call and extract the image ID.
 86
 87    Parameters
 88    ----------
 89    fname : str
 90        The path to the `yaml` file to parse.
 91
 92    Returns
 93    -------
 94    int or None
 95        The OMERO ID of the newly imported image, e.g. `1568386` or `None` in case
 96        parsing the file failed for any reason.
 97    """
 98    try:
 99        with open(fname, "r", encoding="utf-8") as stream:
100            parsed = yaml.safe_load(stream)
101        if len(parsed[0]["Image"]) != 1:
102            msg = f"Unexpected YAML retrieved from OMERO, unable to parse:\n{parsed}"
103            printlog("ERROR", msg)
104            raise SyntaxError(msg)
105        image_id = parsed[0]["Image"][0]
106    except Exception as err:  # pylint: disable-msg=broad-except
107        printlog("ERROR", f"Error parsing imported image ID from YAML output: {err}")
108        return None
109
110    log.success(f"Successfully parsed Image ID from YAML: {image_id}")
111    return image_id

Parse the YAML returned by an 'omero import' call and extract the image ID.

Parameters
  • fname (str): The path to the yaml file to parse.
Returns
  • int or None: The OMERO ID of the newly imported image, e.g. 1568386 or None in case parsing the file failed for any reason.
@connect_and_set_group
def add_annotation_keyvalue(conn, omero_id, annotation):
114@connect_and_set_group
115def add_annotation_keyvalue(conn, omero_id, annotation):
116    """Add a key-value "map" annotation to an OMERO object.
117
118    Parameters
119    ----------
120    conn : omero.gateway.BlitzGateway
121        The OMERO connection object.
122    omero_id : hrm_omero.misc.OmeroId
123        The ID of the OMERO object that should receive the annotation.
124    annotation : dict(dict)
125        The map annotation as returned by `hrm_omero.hrm.parse_summary()`.
126
127    Returns
128    -------
129    bool
130        True in case of success, False otherwise.
131
132    Raises
133    ------
134    RuntimeError
135        Raised in case re-establishing the OMERO connection fails.
136    """
137    log.trace(f"Adding a map annotation to {omero_id}")
138    target_obj = conn.getObject(omero_id.obj_type, omero_id.obj_id)
139    if target_obj is None:
140        log.warning(f"Unable to identify target object {omero_id} in OMERO!")
141        return False
142
143    for section in annotation:
144        namespace = f"Huygens Remote Manager - {section}"
145        log.trace(f"Using namespace [{namespace}] for annotation.")
146        map_ann = omero.gateway.MapAnnotationWrapper(conn)
147        map_ann.setValue(annotation[section].items())
148        map_ann.setNs(namespace)
149        map_ann.save()
150        target_obj.linkAnnotation(map_ann)
151        log.debug(f"Added key-value annotation using namespace [{namespace}].")
152
153    log.success(f"Added annotation to {omero_id}.")
154
155    return True

Add a key-value "map" annotation to an OMERO object.

Parameters
Returns
  • bool: True in case of success, False otherwise.
Raises
  • RuntimeError: Raised in case re-establishing the OMERO connection fails.
@connect_and_set_group
def new_project(conn, omero_id, proj_name):
158@connect_and_set_group
159def new_project(conn, omero_id, proj_name):  # pragma: no cover
160    """Create a new Project in OMERO.
161
162    Parameters
163    ----------
164    conn : omero.gateway.BlitzGateway
165        The OMERO connection object.
166    omero_id : hrm_omero.misc.OmeroId
167        The ID of an OMERO object denoting an Experimenter.
168    proj_name : str
169        The name of the project to be created.
170    """
171    raise NotImplementedError("Creating Projects is not yet implemented.")

Create a new Project in OMERO.

Parameters
  • conn (omero.gateway.BlitzGateway): The OMERO connection object.
  • omero_id (hrm_omero.misc.OmeroId): The ID of an OMERO object denoting an Experimenter.
  • proj_name (str): The name of the project to be created.
@connect_and_set_group
def new_dataset(conn, omero_id, ds_name):
174@connect_and_set_group
175def new_dataset(conn, omero_id, ds_name):  # pragma: no cover
176    """Create a new Project in OMERO.
177
178    Parameters
179    ----------
180    conn : omero.gateway.BlitzGateway
181        The OMERO connection object.
182    omero_id : hrm_omero.misc.OmeroId
183        The ID of an OMERO object denoting a Project or an Experimenter.
184    ds_name : str
185        The name of the dataset to be created.
186    """
187    raise NotImplementedError("Creating Datasets is not yet implemented.")

Create a new Project in OMERO.

Parameters
  • conn (omero.gateway.BlitzGateway): The OMERO connection object.
  • omero_id (hrm_omero.misc.OmeroId): The ID of an OMERO object denoting a Project or an Experimenter.
  • ds_name (str): The name of the dataset to be created.
def find_recently_imported(conn, ds_id, label, age=15):
190def find_recently_imported(conn, ds_id, label, age=15):
191    """Speculative way of identifying a recently imported image in a dataset.
192
193    Check children of a dataset in OMERO until one is found that is matching following
194    criteria:
195
196    * the import date is not more than the specified `age` tolerance ago (in seconds)
197    * the object name is matching the given label
198
199    Usually it will hit the right object in the first iteration as `listChildren()`
200    seems to give the images in reverse order of their import (newest ones first).
201
202    Parameters
203    ----------
204    conn : omero.gateway.BlitzGateway
205        The OMERO connection object.
206    ds_id : int or int-like
207        The ID of the dataset where to look for the image.
208    label : str
209        The label of the imported image, in the simplest case this is usually just the
210        file name of the original file without any path components.
211    age : int, optional
212        The maximum age in seconds that the identified image object in OMERO is allowed
213        to have, by default 15.
214
215    Returns
216    -------
217    omero.gateway._ImageWrapper or None
218        The "Image" object as returned by OMERO's BlitzGateway or None in case no image
219        object matching the criteria could be found.
220    """
221    imported = None
222    dset = conn.getObject("Dataset", ds_id)
223    for image in dset.listChildren():
224        if image.getName() != label:
225            continue
226
227        oldest_allowed_date = datetime.now() - timedelta(seconds=age)
228        date = image.getDate()
229        if date >= oldest_allowed_date:
230            imported = image
231            log.success(f"Found imported image: {image.getId()}")
232            break
233
234    return imported

Speculative way of identifying a recently imported image in a dataset.

Check children of a dataset in OMERO until one is found that is matching following criteria:

  • the import date is not more than the specified age tolerance ago (in seconds)
  • the object name is matching the given label

Usually it will hit the right object in the first iteration as listChildren() seems to give the images in reverse order of their import (newest ones first).

Parameters
  • conn (omero.gateway.BlitzGateway): The OMERO connection object.
  • ds_id (int or int-like): The ID of the dataset where to look for the image.
  • label (str): The label of the imported image, in the simplest case this is usually just the file name of the original file without any path components.
  • age (int, optional): The maximum age in seconds that the identified image object in OMERO is allowed to have, by default 15.
Returns
  • omero.gateway._ImageWrapper or None: The "Image" object as returned by OMERO's BlitzGateway or None in case no image object matching the criteria could be found.