Skip to content

Commit

Permalink
Map annotation enhancement; list of values possible (#112)
Browse files Browse the repository at this point in the history
* added logic for multiple values per key as list

* deleted 'across_groups' from multi_post_map_annotation as it was not accessed

* corrected error in test_posts

* moving to docker compose v2

* implemented defaultdict solution for mapAnnDict

* corrected a wrong test assert statement

* reverting `defaultdict` implementation

---------

Co-authored-by: Erick Martins Ratamero <[email protected]>
  • Loading branch information
JensWendt and erickmartins authored Aug 28, 2024
1 parent b299fd6 commit 9b0d569
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 18 deletions.
12 changes: 9 additions & 3 deletions ezomero/_ezomero.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def put_map_annotation(conn: BlitzGateway, map_ann_id: int, kv_dict: dict,
--------
# Change only the values of an existing map annotation:
>>> new_values = {'testkey': 'testvalue', 'testkey2': 'testvalue2'}
>>> new_values = {'key1': 'value1', 'key2': ['value2', 'value3']}
>>> put_map_annotation(conn, 15, new_values)
# Change both the values and namespace of an existing map annotation:
Expand All @@ -124,8 +124,14 @@ def put_map_annotation(conn: BlitzGateway, map_ann_id: int, kv_dict: dict,
kv_pairs = []
for k, v in kv_dict.items():
k = str(k)
v = str(v)
kv_pairs.append([k, v])
if type(v) != list:
v = str(v)
kv_pairs.append([k, v])
else:
for value in v:
value = str(value)
kv_pairs.append([k, value])

map_ann.setValue(kv_pairs)
map_ann.save()
return None
Expand Down
18 changes: 16 additions & 2 deletions ezomero/_gets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,17 +1283,31 @@ def get_map_annotation(conn: BlitzGateway, map_ann_id: int,
-------
kv_dict : dict
The value of the specified map annotation object, as a Python dict.
If kv-pairs with the same key exist, the corresponding dict value
will be a list.
Examples
--------
>>> ma_dict = get_map_annotation(conn, 62)
>>> print(ma_dict)
{'testkey': 'testvalue', 'testkey2': 'testvalue2'}
{'testkey': 'testvalue', 'testkey2': ['testvalue2'. 'testvalue3']}
"""
if type(map_ann_id) is not int:
raise TypeError('Map annotation ID must be an integer')

map_annotation_dict = {}

map_annotation = conn.getObject('MapAnnotation', map_ann_id).getValue()

for item in map_annotation:
if item[0] in map_annotation_dict:
if not isinstance(map_annotation_dict[item[0]], list):
map_annotation_dict[item[0]] = [map_annotation_dict[item[0]]]
map_annotation_dict[item[0]].append(item[1])
else:
map_annotation_dict[item[0]] = item[1]

return dict(conn.getObject('MapAnnotation', map_ann_id).getValue())
return map_annotation_dict


@do_across_groups
Expand Down
14 changes: 9 additions & 5 deletions ezomero/_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,7 @@ def set_or_create_screen(conn: BlitzGateway, screen: Union[str, int],

def multi_post_map_annotation(conn: BlitzGateway, object_type: str,
object_ids: Union[int, List[int]], kv_dict: dict,
ns: str, across_groups: Optional[bool] = True
) -> int:
ns: str) -> int:
"""Create a single new MapAnnotation and link to multiple images.
Parameters
----------
Expand All @@ -192,7 +191,7 @@ def multi_post_map_annotation(conn: BlitzGateway, object_type: str,
--------
>>> ns = 'jax.org/jax/example/namespace'
>>> d = {'species': 'human',
'occupation': 'time traveler'
'occupation': ['time traveler', 'soldier'],
'first name': 'Kyle',
'surname': 'Reese'}
>>> multi_post_map_annotation(conn, "Image", [23,56,78], d, ns)
Expand All @@ -212,8 +211,13 @@ def multi_post_map_annotation(conn: BlitzGateway, object_type: str,
kv_pairs = []
for k, v in kv_dict.items():
k = str(k)
v = str(v)
kv_pairs.append([k, v])
if type(v) != list:
v = str(v)
kv_pairs.append([k, v])
else:
for value in v:
value = str(value)
kv_pairs.append([k, value])

map_ann = MapAnnotationWrapper(conn)
map_ann.setNs(str(ns))
Expand Down
13 changes: 10 additions & 3 deletions ezomero/_posts.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ def post_map_annotation(conn: BlitzGateway, object_type: str, object_id: int,
Notes
-----
All keys and values are converted to strings before saving in OMERO.
Passing a list of values will result in multiple instances of the key,
one for each value.
Returns
-------
Expand All @@ -262,7 +264,7 @@ def post_map_annotation(conn: BlitzGateway, object_type: str, object_id: int,
--------
>>> ns = 'jax.org/jax/example/namespace'
>>> d = {'species': 'human',
... 'occupation': 'time traveler'
... 'occupation': ['time traveler', 'soldier'].
... 'first name': 'Kyle',
... 'surname': 'Reese'}
>>> post_map_annotation(conn, "Image", 56, d, ns)
Expand All @@ -274,8 +276,13 @@ def post_map_annotation(conn: BlitzGateway, object_type: str, object_id: int,
kv_pairs = []
for k, v in kv_dict.items():
k = str(k)
v = str(v)
kv_pairs.append([k, v])
if type(v) != list:
v = str(v)
kv_pairs.append([k, v])
else:
for value in v:
value = str(value)
kv_pairs.append([k, value])
obj = None
if object_id is not None:
if type(object_id) is not int:
Expand Down
7 changes: 5 additions & 2 deletions tests/test_gets.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,8 @@ def test_get_image_ids_params(conn):

def test_get_map_annotation_and_ids(conn, project_structure):
kv = {"key1": "value1",
"key2": "value2"}
"key2": "value2",
"key3": ["value3", "value4"]}
ns = "jax.org/omeroutils/tests/v0"
image_info = project_structure[2]
im_id = image_info[0][1]
Expand Down Expand Up @@ -610,7 +611,9 @@ def test_get_map_annotation_and_ids(conn, project_structure):
with pytest.raises(TypeError):
_ = ezomero.get_map_annotation(conn, '10')
mpann = ezomero.get_map_annotation(conn, map_ann_ids[0])
assert mpann == kv
assert mpann["key1"] == kv["key1"]
assert mpann["key2"] == kv["key2"]
assert sorted(mpann["key3"]) == sorted(kv["key3"])
conn.deleteObjects("Annotation",
[map_ann_id, map_ann_id2, map_ann_id3, map_ann_id4],
deleteAnns=True,
Expand Down
4 changes: 3 additions & 1 deletion tests/test_posts.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ def test_post_get_map_annotation(conn, project_structure, users_groups):
im_id = image_info[0][1]
# This test both ezomero.post_map_annotation and ezomero.get_map_annotation
kv = {"key1": "value1",
"key2": "value2"}
"key2": "value2",
"key3": ["value3", 123]}
ns = "jax.org/omeroutils/tests/v0"

# test sanitized input on post
Expand All @@ -197,6 +198,7 @@ def test_post_get_map_annotation(conn, project_structure, users_groups):
map_ann_id = ezomero.post_map_annotation(conn, "Image", im_id, kv, ns)
kv_pairs = ezomero.get_map_annotation(conn, map_ann_id)
assert kv_pairs["key2"] == "value2"
assert sorted(kv_pairs["key3"]) == sorted(["value3", "123"])

# Test posting to non-existing object
im_id2 = 999999999
Expand Down
4 changes: 2 additions & 2 deletions tests/test_puts.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ def test_put_map_annotation(conn, project_structure, users_groups):
image_info = project_structure[2]
im_id = image_info[0][1]
map_ann_id = ezomero.post_map_annotation(conn, "Image", im_id, kv, ns)
kv = {"key1": "changed1",
kv = {"key1": ["changed1", "changed2"],
"key2": "value2"}
ezomero.put_map_annotation(conn, map_ann_id, kv)
kv_pairs = ezomero.get_map_annotation(conn, map_ann_id)
assert kv_pairs['key1'] == kv['key1']
assert sorted(kv_pairs['key1']) == sorted(kv['key1'])

# test cross-group
kv = {"key1": "value1",
Expand Down

0 comments on commit 9b0d569

Please sign in to comment.