hrm_omero.tree

Functions related to OMERO's tree view.

  1"""Functions related to OMERO's tree view."""
  2
  3from loguru import logger as log
  4
  5from .decorators import connect_and_set_group
  6
  7
  8def gen_obj_dict(obj, id_pfx=""):
  9    """Create a dict from an OMERO object.
 10
 11    Parameters
 12    ----------
 13    obj : omero.gateway._*Wrapper
 14        The OMERO object to process.
 15    id_pfx : str, optional
 16        A string prefix that will be added to the `id` value, by default ''.
 17
 18    Returns
 19    -------
 20    dict
 21        A dictionary with the following structure:
 22        ```
 23            {
 24                'children': [],
 25                'id': 'Project:1154',
 26                'label': 'HRM_TESTDATA',
 27                'owner': u'demo01',
 28                'class': 'Project'
 29            }
 30        ```
 31    """
 32    obj_dict = {}
 33    obj_dict["label"] = obj.getName()
 34    obj_dict["class"] = obj.OMERO_CLASS
 35    if obj.OMERO_CLASS == "Experimenter":
 36        obj_dict["owner"] = obj.getId()
 37        obj_dict["label"] = obj.getFullName()
 38    elif obj.OMERO_CLASS == "ExperimenterGroup":
 39        # for some reason getOwner() et al. return nothing on a group, so we
 40        # simply put it to None for group objects:
 41        obj_dict["owner"] = None
 42    else:
 43        obj_dict["owner"] = obj.getOwnerOmeName()
 44    obj_dict["id"] = id_pfx + f"{obj.OMERO_CLASS}:{obj.getId()}"
 45    obj_dict["children"] = []
 46    return obj_dict
 47
 48
 49@connect_and_set_group
 50def gen_children(conn, omero_id):
 51    """Get the children for a given node.
 52
 53    Parameters
 54    ----------
 55    conn : omero.gateway.BlitzGateway
 56        The OMERO connection object.
 57    omero_id : hrm_omero.misc.OmeroId
 58        An object denoting an OMERO target.
 59
 60    Returns
 61    -------
 62    list
 63        A list with children nodes (of type `dict`), having the `load_on_demand`
 64        property set to `True` required by the jqTree JavaScript library (except for
 65        nodes of type `Dataset` as they are the last / lowest level).
 66    """
 67    if omero_id.obj_type == "BaseTree":
 68        return gen_base_tree(conn)
 69
 70    log.debug(f"generating children for [{omero_id}]")
 71
 72    # conn.SERVICE_OPTS.setOmeroGroup(gid)
 73    obj = conn.getObject(omero_id.obj_type, omero_id.obj_id)
 74    # we need different child-wrappers, depending on the object type:
 75    if omero_id.obj_type == "Experimenter":
 76        children_wrapper = []
 77        for proj in conn.listProjects(omero_id.obj_id):
 78            children_wrapper.append(proj)
 79        # OMERO.web is showing "orphaned" datasets (i.e. that do NOT belong to a
 80        # certain project) at the top level, next to the projects - so we are going to
 81        # add them to the tree at the same hierarchy level:
 82        for dataset in conn.listOrphans("Dataset", eid=omero_id.obj_id):
 83            children_wrapper.append(dataset)
 84
 85    elif omero_id.obj_type == "ExperimenterGroup":
 86        log.warning(
 87            f"{__name__} has been called with omero_id='{str(omero_id)}', but "
 88            "'ExperimenterGroup' trees should be generated via `gen_group_tree()`!",
 89        )
 90        return []
 91
 92    else:
 93        children_wrapper = obj.listChildren()
 94
 95    # now process children:
 96    children = []
 97    for child in children_wrapper:
 98        children.append(gen_obj_dict(child, "G:" + omero_id.group + ":"))
 99    children = sorted(children, key=lambda d: d["label"].lower())
100
101    # set the on-demand flag unless the children are the last level:
102    if not omero_id.obj_type == "Dataset":
103        for child in children:
104            child["load_on_demand"] = True
105
106    return children
107
108
109def gen_base_tree(conn):
110    """Generate all group trees with their members as the basic tree.
111
112    Parameters
113    ----------
114    conn : omero.gateway.BlitzGateway
115        The OMERO connection object.
116
117    Returns
118    -------
119    list
120        A list of grouptree dicts as generated by `gen_group_tree()`.
121    """
122    log.debug("Generating base tree...")
123    tree = []
124    for group in conn.getGroupsMemberOf():
125        tree.append(gen_group_tree(conn, group))
126    tree_sorted = sorted(tree, key=lambda d: d["label"].lower())
127    return tree_sorted
128
129
130def gen_group_tree(conn, group=None):
131    """Create the tree nodes for a group and its members.
132
133    Parameters
134    ----------
135    conn : omero.gateway.BlitzGateway
136        The OMERO connection object.
137    group : int or str or omero.gateway._ExperimenterGroupWrapper, optional
138        The group object (or the group ID as int or str) to generate the tree for, by
139        default `None` which will result in the group being derived from the current
140        connection's context.
141
142    Returns
143    -------
144    dict
145        A nested dict of the given group (or the default group if not specified
146        explicitly) and its members as a list of dicts in the `children` item, starting
147        with the current user as the first entry.
148    """
149    if group is None:
150        log.debug("Getting group from current context...")
151        group = conn.getGroupFromContext()
152
153    if isinstance(group, (int, str)):
154        target_gid = int(group)
155        group = None
156        for candidate in conn.getGroupsMemberOf():
157            if int(candidate.getId()) == target_gid:
158                log.debug(f"Found group object for ID {target_gid}!")
159                group = candidate
160                break
161        if group is None:
162            msg = f"Unable to identify group with ID {target_gid}!"
163            log.error(msg)
164            raise RuntimeError(msg)
165
166    gid = str(group.getId())
167    log.debug(f"Generating tree for group {gid}...")
168    conn.setGroupForSession(gid)
169
170    group_dict = gen_obj_dict(group)
171    # add the user's own tree first:
172    user = conn.getUser()
173    user_dict = gen_obj_dict(user, "G:" + gid + ":")
174    user_dict["load_on_demand"] = True
175    group_dict["children"].append(user_dict)
176    all_user_dicts = []
177    # then add the trees for other group members
178    for user in conn.listColleagues():
179        user_dict = gen_obj_dict(user, "G:" + gid + ":")
180        user_dict["load_on_demand"] = True
181        all_user_dicts.append(user_dict)
182
183    group_dict["children"] += sorted(all_user_dicts, key=lambda d: d["label"].lower())
184    return group_dict
def gen_obj_dict(obj, id_pfx=''):
 9def gen_obj_dict(obj, id_pfx=""):
10    """Create a dict from an OMERO object.
11
12    Parameters
13    ----------
14    obj : omero.gateway._*Wrapper
15        The OMERO object to process.
16    id_pfx : str, optional
17        A string prefix that will be added to the `id` value, by default ''.
18
19    Returns
20    -------
21    dict
22        A dictionary with the following structure:
23        ```
24            {
25                'children': [],
26                'id': 'Project:1154',
27                'label': 'HRM_TESTDATA',
28                'owner': u'demo01',
29                'class': 'Project'
30            }
31        ```
32    """
33    obj_dict = {}
34    obj_dict["label"] = obj.getName()
35    obj_dict["class"] = obj.OMERO_CLASS
36    if obj.OMERO_CLASS == "Experimenter":
37        obj_dict["owner"] = obj.getId()
38        obj_dict["label"] = obj.getFullName()
39    elif obj.OMERO_CLASS == "ExperimenterGroup":
40        # for some reason getOwner() et al. return nothing on a group, so we
41        # simply put it to None for group objects:
42        obj_dict["owner"] = None
43    else:
44        obj_dict["owner"] = obj.getOwnerOmeName()
45    obj_dict["id"] = id_pfx + f"{obj.OMERO_CLASS}:{obj.getId()}"
46    obj_dict["children"] = []
47    return obj_dict

Create a dict from an OMERO object.

Parameters
  • obj (omero.gateway._*Wrapper): The OMERO object to process.
  • id_pfx (str, optional): A string prefix that will be added to the id value, by default ''.
Returns
  • dict: A dictionary with the following structure:
    {
        'children': [],
        'id': 'Project:1154',
        'label': 'HRM_TESTDATA',
        'owner': u'demo01',
        'class': 'Project'
    }
@connect_and_set_group
def gen_children(conn, omero_id):
 50@connect_and_set_group
 51def gen_children(conn, omero_id):
 52    """Get the children for a given node.
 53
 54    Parameters
 55    ----------
 56    conn : omero.gateway.BlitzGateway
 57        The OMERO connection object.
 58    omero_id : hrm_omero.misc.OmeroId
 59        An object denoting an OMERO target.
 60
 61    Returns
 62    -------
 63    list
 64        A list with children nodes (of type `dict`), having the `load_on_demand`
 65        property set to `True` required by the jqTree JavaScript library (except for
 66        nodes of type `Dataset` as they are the last / lowest level).
 67    """
 68    if omero_id.obj_type == "BaseTree":
 69        return gen_base_tree(conn)
 70
 71    log.debug(f"generating children for [{omero_id}]")
 72
 73    # conn.SERVICE_OPTS.setOmeroGroup(gid)
 74    obj = conn.getObject(omero_id.obj_type, omero_id.obj_id)
 75    # we need different child-wrappers, depending on the object type:
 76    if omero_id.obj_type == "Experimenter":
 77        children_wrapper = []
 78        for proj in conn.listProjects(omero_id.obj_id):
 79            children_wrapper.append(proj)
 80        # OMERO.web is showing "orphaned" datasets (i.e. that do NOT belong to a
 81        # certain project) at the top level, next to the projects - so we are going to
 82        # add them to the tree at the same hierarchy level:
 83        for dataset in conn.listOrphans("Dataset", eid=omero_id.obj_id):
 84            children_wrapper.append(dataset)
 85
 86    elif omero_id.obj_type == "ExperimenterGroup":
 87        log.warning(
 88            f"{__name__} has been called with omero_id='{str(omero_id)}', but "
 89            "'ExperimenterGroup' trees should be generated via `gen_group_tree()`!",
 90        )
 91        return []
 92
 93    else:
 94        children_wrapper = obj.listChildren()
 95
 96    # now process children:
 97    children = []
 98    for child in children_wrapper:
 99        children.append(gen_obj_dict(child, "G:" + omero_id.group + ":"))
100    children = sorted(children, key=lambda d: d["label"].lower())
101
102    # set the on-demand flag unless the children are the last level:
103    if not omero_id.obj_type == "Dataset":
104        for child in children:
105            child["load_on_demand"] = True
106
107    return children

Get the children for a given node.

Parameters
  • conn (omero.gateway.BlitzGateway): The OMERO connection object.
  • omero_id (hrm_omero.misc.OmeroId): An object denoting an OMERO target.
Returns
  • list: A list with children nodes (of type dict), having the load_on_demand property set to True required by the jqTree JavaScript library (except for nodes of type Dataset as they are the last / lowest level).
def gen_base_tree(conn):
110def gen_base_tree(conn):
111    """Generate all group trees with their members as the basic tree.
112
113    Parameters
114    ----------
115    conn : omero.gateway.BlitzGateway
116        The OMERO connection object.
117
118    Returns
119    -------
120    list
121        A list of grouptree dicts as generated by `gen_group_tree()`.
122    """
123    log.debug("Generating base tree...")
124    tree = []
125    for group in conn.getGroupsMemberOf():
126        tree.append(gen_group_tree(conn, group))
127    tree_sorted = sorted(tree, key=lambda d: d["label"].lower())
128    return tree_sorted

Generate all group trees with their members as the basic tree.

Parameters
  • conn (omero.gateway.BlitzGateway): The OMERO connection object.
Returns
def gen_group_tree(conn, group=None):
131def gen_group_tree(conn, group=None):
132    """Create the tree nodes for a group and its members.
133
134    Parameters
135    ----------
136    conn : omero.gateway.BlitzGateway
137        The OMERO connection object.
138    group : int or str or omero.gateway._ExperimenterGroupWrapper, optional
139        The group object (or the group ID as int or str) to generate the tree for, by
140        default `None` which will result in the group being derived from the current
141        connection's context.
142
143    Returns
144    -------
145    dict
146        A nested dict of the given group (or the default group if not specified
147        explicitly) and its members as a list of dicts in the `children` item, starting
148        with the current user as the first entry.
149    """
150    if group is None:
151        log.debug("Getting group from current context...")
152        group = conn.getGroupFromContext()
153
154    if isinstance(group, (int, str)):
155        target_gid = int(group)
156        group = None
157        for candidate in conn.getGroupsMemberOf():
158            if int(candidate.getId()) == target_gid:
159                log.debug(f"Found group object for ID {target_gid}!")
160                group = candidate
161                break
162        if group is None:
163            msg = f"Unable to identify group with ID {target_gid}!"
164            log.error(msg)
165            raise RuntimeError(msg)
166
167    gid = str(group.getId())
168    log.debug(f"Generating tree for group {gid}...")
169    conn.setGroupForSession(gid)
170
171    group_dict = gen_obj_dict(group)
172    # add the user's own tree first:
173    user = conn.getUser()
174    user_dict = gen_obj_dict(user, "G:" + gid + ":")
175    user_dict["load_on_demand"] = True
176    group_dict["children"].append(user_dict)
177    all_user_dicts = []
178    # then add the trees for other group members
179    for user in conn.listColleagues():
180        user_dict = gen_obj_dict(user, "G:" + gid + ":")
181        user_dict["load_on_demand"] = True
182        all_user_dicts.append(user_dict)
183
184    group_dict["children"] += sorted(all_user_dicts, key=lambda d: d["label"].lower())
185    return group_dict

Create the tree nodes for a group and its members.

Parameters
  • conn (omero.gateway.BlitzGateway): The OMERO connection object.
  • group (int or str or omero.gateway._ExperimenterGroupWrapper, optional): The group object (or the group ID as int or str) to generate the tree for, by default None which will result in the group being derived from the current connection's context.
Returns
  • dict: A nested dict of the given group (or the default group if not specified explicitly) and its members as a list of dicts in the children item, starting with the current user as the first entry.