Skip to content

Commit 90ec32f

Browse files
committed
Mmif.__getitem__ now search for an annotation with short ID
1 parent 445774a commit 90ec32f

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

mmif/serialize/mmif.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -661,30 +661,38 @@ def get_end(self, annotation: Annotation) -> Union[int, float]:
661661
def __getitem__(self, item: str) \
662662
-> Union[Document, View, Annotation, MmifMetadata, DocumentsList, ViewsList]:
663663
"""
664-
getitem implementation for Mmif. When nothing is found, this will raise an error
665-
rather than returning a None (although pytype doesn't think so...)
664+
getitem implementation for Mmif. This will try to find any object, given an identifier or an immediate
665+
attribute name. When nothing is found, this will raise an error rather than returning a None
666666
667667
:raises KeyError: if the item is not found or if the search results are ambiguous
668-
:param item: the search string, a document ID, a view ID, or a view-scoped annotation ID
668+
:param item: an attribute name or an object identifier (a document ID, a view ID, or an annotation ID). When
669+
annotation ID is given as a "short" ID (without view ID prefix), the method will try to find a
670+
match from the first view, and return immediately if found.
669671
:return: the object searched for
672+
:raise KeyError: if the item is not found or multiple objects are found with the same ID
670673
"""
671674
if item in self._named_attributes():
672675
return self.__dict__[item]
673676
split_attempt = item.split(self.id_delimiter)
674677

675-
document_result = self.documents.get(split_attempt[0])
676-
view_result = self.views.get(split_attempt[0])
678+
found = []
677679

678680
if len(split_attempt) == 1:
679-
anno_result = None
680-
elif view_result:
681-
anno_result = view_result[split_attempt[1]]
681+
found.append(self.documents.get(split_attempt[0]))
682+
found.append(self.views.get(split_attempt[0]))
683+
for view in self.views:
684+
found.append(view.annotations.get(split_attempt[0]))
685+
elif len(split_attempt) == 2:
686+
v = self.get_view_by_id(split_attempt[0])
687+
if v is not None:
688+
found.append(v.annotations.get(split_attempt[1]))
682689
else:
683690
raise KeyError("Tried to subscript into a view that doesn't exist")
691+
found = [x for x in found if x is not None]
684692

685-
if view_result and document_result:
693+
if len(found) > 1:
686694
raise KeyError("Ambiguous ID search result")
687-
if not (view_result or document_result):
695+
elif len(found) == 0:
688696
raise KeyError("ID not found: %s" % item)
689-
return anno_result or view_result or document_result
690-
697+
else:
698+
return found[-1]

tests/test_serialize.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,29 @@ def test_mmif_getitem_document(self):
516516
except KeyError:
517517
self.fail("didn't get document 'm1'")
518518

519+
def test_mmif_getitem_idconflict(self):
520+
m = Mmif(validate=False)
521+
v1 = m.new_view()
522+
v1.id = 'v1'
523+
v2 = m.new_view()
524+
v2.id = 'v1'
525+
with pytest.raises(KeyError):
526+
_ = m['v1']
527+
528+
m = Mmif(validate=False)
529+
v1 = m.new_view()
530+
v1a = v1.new_annotation(AnnotationTypes.Annotation, id='a1')
531+
v2 = m.new_view()
532+
v2a = v2.new_annotation(AnnotationTypes.Annotation, id='a1')
533+
self.assertIsNotNone(m[v1.id])
534+
self.assertIsNotNone(m[v2.id])
535+
# conflict short IDs
536+
self.assertEqual(v1a.id, v2a.id)
537+
with pytest.raises(KeyError):
538+
_ = m[v1a.id]
539+
self.assertIsNotNone(m[v1a.long_id])
540+
self.assertIsNotNone(m[v2a.long_id])
541+
519542
def test_mmif_getitem_view(self):
520543
try:
521544
v1 = self.mmif_obj['v1']

0 commit comments

Comments
 (0)