14
14
import re
15
15
import typing
16
16
import warnings
17
- from typing import Union , Dict , List , Optional , Iterator , MutableMapping , TypeVar
17
+ from typing import Union , Dict , Optional , Iterator , MutableMapping , TypeVar
18
18
from urllib .parse import urlparse
19
19
20
20
from mmif .vocabulary import ThingTypesBase , DocumentTypesBase
@@ -46,19 +46,23 @@ class Annotation(MmifObject):
46
46
MmifObject that represents an annotation in a MMIF view.
47
47
"""
48
48
49
- def __init__ (self , anno_obj : Optional [Union [bytes , str , dict ]] = None ) -> None :
49
+ def __init__ (self , anno_obj : Optional [Union [bytes , str , dict ]] = None , * _ ) -> None :
50
50
self ._type : ThingTypesBase = ThingTypesBase ('' )
51
51
# to store the parent view ID
52
52
self ._parent_view_id = ''
53
53
self ._props_ephemeral : AnnotationProperties = AnnotationProperties ()
54
- self .reserved_names .update (('_parent_view_id' , '_props_ephemeral' ))
54
+ self ._alignments = {} # to hold alignment information (Alignment anno long_id -> aligned anno long_id)
55
+ self .reserved_names .update (('_parent_view_id' , '_props_ephemeral' , '_alignments' ))
55
56
if not hasattr (self , 'properties' ): # don't overwrite DocumentProperties on super() call
56
57
self .properties : AnnotationProperties = AnnotationProperties ()
57
58
self ._attribute_classes = {'properties' : AnnotationProperties }
58
59
self .disallow_additional_properties ()
59
60
self ._required_attributes = ["_type" , "properties" ]
60
61
super ().__init__ (anno_obj )
61
62
63
+ def __hash__ (self ):
64
+ return hash (self .serialize ())
65
+
62
66
def _deserialize (self , input_dict : dict ) -> None :
63
67
self .at_type = input_dict .pop ('_type' , '' )
64
68
# TODO (krim @ 6/1/21): If annotation IDs must follow a certain string format,
@@ -69,6 +73,40 @@ def _deserialize(self, input_dict: dict) -> None:
69
73
for k , v in self .properties .items ():
70
74
self ._add_prop_aliases (k , v )
71
75
76
+ def _cache_alignment (self , alignment_ann : 'Annotation' , alignedto_ann : 'Annotation' ) -> None :
77
+ """
78
+ Cache alignment information. This cache will not be serialized.
79
+
80
+ :param alignment_ann: the Alignment annotation that has this annotation on one side
81
+ :param alignedto_ann: the annotation that this annotation is aligned to (other side of Alignment)
82
+ """
83
+ self ._alignments [alignment_ann ] = alignedto_ann
84
+
85
+ def aligned_to_by (self , alignment : 'Annotation' ) -> Optional ['Annotation' ]:
86
+ """
87
+ Retrieves the other side of ``Alignment`` annotation that has this annotation on one side.
88
+
89
+ :param alignment: ``Alignment`` annotation that has this annotation on one side
90
+ :return: the annotation that this annotation is aligned to (other side of ``Alignment``),
91
+ or None if this annotation is not used in the ``Alignment``.
92
+ """
93
+ return self ._alignments .get (alignment )
94
+
95
+ def get_all_aligned (self ) -> Iterator ['Annotation' ]:
96
+ """
97
+ Generator to iterate through all alignments and aligned annotations. Note that this generator will yield
98
+ the `Alignment` annotations as well. Every odd-numbered yield will be an `Alignment` annotation, and every
99
+ even-numbered yield will be the aligned annotation. If there's a specific annotation type that you're looking
100
+ for, you need to filter the generated results outside.
101
+
102
+ :return: yields the alignment annotation and the aligned annotation.
103
+ The order is decided by the order of appearance of Alignment annotations in the MMIF
104
+ """
105
+ for alignment , aligned in self ._alignments .items ():
106
+ yield alignment
107
+ yield aligned
108
+
109
+
72
110
def _add_prop_aliases (self , key_to_add , val_to_add ):
73
111
"""
74
112
Method to handle aliases of the same property.
@@ -163,6 +201,7 @@ def add_property(self, name: str,
163
201
value : Union [PRMTV_TYPES , LIST_PRMTV , LIST_LIST_PRMTV , DICT_PRMTV , DICT_LIST_PRMTV ]) -> None :
164
202
"""
165
203
Adds a property to the annotation's properties.
204
+
166
205
:param name: the name of the property
167
206
:param value: the property's desired value
168
207
:return: None
@@ -241,7 +280,7 @@ class Document(Annotation):
241
280
242
281
:param document_obj: the JSON data that defines the document
243
282
"""
244
- def __init__ (self , doc_obj : Optional [Union [bytes , str , dict ]] = None ) -> None :
283
+ def __init__ (self , doc_obj : Optional [Union [bytes , str , dict ]] = None , * _ ) -> None :
245
284
# see https://github.com/clamsproject/mmif-python/issues/226 for discussion
246
285
# around the use of these three dictionaries
247
286
# (names changed since, `existing` >> `ephemeral` and `temporary` >> `pending`)
@@ -434,7 +473,7 @@ def __getitem__(self, key):
434
473
else :
435
474
return self ._unnamed_attributes [key ]
436
475
437
- def __init__ (self , mmif_obj : Optional [Union [bytes , str , dict ]] = None ) -> None :
476
+ def __init__ (self , mmif_obj : Optional [Union [bytes , str , dict ]] = None , * _ ) -> None :
438
477
self .id : str = ''
439
478
# any individual at_type (subclassing this class) can have its own set of required attributes
440
479
self ._required_attributes = ["id" ]
@@ -451,7 +490,7 @@ class DocumentProperties(AnnotationProperties):
451
490
:param mmif_obj: the JSON data that defines the properties
452
491
"""
453
492
454
- def __init__ (self , mmif_obj : Optional [Union [bytes , str , dict ]] = None ) -> None :
493
+ def __init__ (self , mmif_obj : Optional [Union [bytes , str , dict ]] = None , * _ ) -> None :
455
494
self .mime : str = ''
456
495
# note the trailing underscore here. I wanted to use the name `location`
457
496
# for @property in this class and `Document` class, so had to use a diff
@@ -572,7 +611,7 @@ def location_path_literal(self) -> Optional[str]:
572
611
573
612
class Text (MmifObject ):
574
613
575
- def __init__ (self , text_obj : Optional [Union [bytes , str , dict ]] = None ) -> None :
614
+ def __init__ (self , text_obj : Optional [Union [bytes , str , dict ]] = None , * _ ) -> None :
576
615
self ._value : str = ''
577
616
self ._language : str = ''
578
617
self .disallow_additional_properties ()
0 commit comments