@@ -74,10 +74,11 @@ def _deserialize(self, input_dict: dict) -> None:
7474
7575 def _cache_alignment (self , alignment_ann : 'Annotation' , alignedto_ann : 'Annotation' ) -> None :
7676 """
77- Cache alignment information. This cache will not be serialized.
78-
77+ Cache alignment information. This cache will not be serialized.
78+
7979 :param alignment_ann: the Alignment annotation that has this annotation on one side
8080 :param alignedto_ann: the annotation that this annotation is aligned to (other side of Alignment)
81+ :return: None
8182 """
8283 self ._alignments [alignment_ann ] = alignedto_ann
8384
@@ -228,7 +229,7 @@ def add_property(self, name: str,
228229 value : Union [PRMTV_TYPES , LIST_PRMTV , LIST_LIST_PRMTV , DICT_PRMTV , DICT_LIST_PRMTV ]) -> None :
229230 """
230231 Adds a property to the annotation's properties.
231-
232+
232233 :param name: the name of the property
233234 :param value: the property's desired value
234235 :return: None
@@ -256,18 +257,41 @@ def __getitem__(self, prop_name: str):
256257
257258 def get (self , prop_name : str , default = None ):
258259 """
259- A getter for Annotation, will search for a property by its name,
260- and return the value if found, or the default value if not found.
261- This is designed to allow for directly accessing properties without
262- having to go through the properties object, or view-level
263- annotation metadata (common properties) encoded in the
264- ``view.metadata.contains`` dict. Note that the regular properties
265- will take the priority over the view-level common properties when
266- there are name conflicts.
267-
268- :param prop_name: the name of the property to get
269- :param default: the value to return if the property is not found
270- :return: the value of the property
260+ Safe property access with optional default value.
261+
262+ Searches for an annotation property by name and returns its value,
263+ or a default value if not found. This method searches in multiple
264+ locations with the following priority:
265+
266+ 1. Direct properties (in ``annotation.properties``)
267+ 2. Ephemeral properties (view-level metadata from ``contains``)
268+ 3. Special fields (``@type``, ``properties``)
269+
270+ This allows convenient access to properties without explicitly
271+ checking the ``properties`` object or view-level metadata.
272+
273+ :param prop_name: The name of the property to retrieve
274+ :param default: The value to return if the property is not found (default: None)
275+ :return: The property value, or the default value if not found
276+
277+ Examples
278+ --------
279+ .. code-block:: python
280+
281+ # Access annotation properties:
282+ label = annotation.get('label', default='unknown')
283+ start_time = annotation.get('start', default=0)
284+
285+ # Access @type:
286+ at_type = annotation.get('@type')
287+
288+ # Safe access with custom default:
289+ targets = annotation.get('targets', default=[])
290+
291+ See Also
292+ --------
293+ __getitem__ : Direct property access that raises KeyError when not found
294+ get_property : Alias for this method
271295 """
272296 try :
273297 return self .__getitem__ (prop_name )
@@ -336,29 +360,32 @@ def add_property(self, name: str,
336360 ) -> None :
337361 """
338362 Adds a property to the document's properties.
339-
340- Unlike the parent :class:`Annotation` class, added properties of a
341- ``Document`` object can be lost during serialization unless it belongs
342- to somewhere in a ``Mmif`` object. This is because we want to keep
343- ``Document`` object as "read-only" as possible. Thus, if you want to add
344- a property to a ``Document`` object,
345-
346- * add the document to a ``Mmif`` object (either in the documents list or
363+
364+ Unlike the parent :class:`Annotation` class, added properties of a
365+ ``Document`` object can be lost during serialization unless it belongs
366+ to somewhere in a ``Mmif`` object. This is because we want to keep
367+ ``Document`` object as "read-only" as possible. Thus, if you want to add
368+ a property to a ``Document`` object,
369+
370+ * add the document to a ``Mmif`` object (either in the documents list or
347371 in a view from the views list), or
348372 * directly write to ``Document.properties`` instead of using this method
349- (which is not recommended).
350-
351- With the former method, the SDK will record the added property as a
352- `Annotation` annotation object, separate from the original `Document`
373+ (which is not recommended).
374+
375+ With the former method, the SDK will record the added property as a
376+ `Annotation` annotation object, separate from the original `Document`
353377 object. See :meth:`.Mmif.generate_capital_annotations()` for more.
354-
378+
355379 A few notes to keep in mind:
356-
357- #. You can't overwrite an existing property of a ``Document`` object.
358- #. A MMIF can have multiple ``Annotation`` objects with the same
380+
381+ #. You can't overwrite an existing property of a ``Document`` object.
382+ #. A MMIF can have multiple ``Annotation`` objects with the same
359383 property name but different values. When this happens, the SDK will
360- only keep the latest value (in order of appearances in views list) of
384+ only keep the latest value (in order of appearances in views list) of
361385 the property, effectively overwriting the previous values.
386+
387+ :param name: the name of the property
388+ :param value: the property's desired value (note: Document accepts fewer value types than Annotation)
362389 """
363390 # we don't checking if this k-v already exists in _original (new props) or _ephemeral (read from existing MMIF)
364391 # because it is impossible to keep the _original updated when a new annotation is added (via `new_annotation`)
@@ -378,13 +405,44 @@ def add_property(self, name: str,
378405
379406 def get (self , prop_name , default = None ):
380407 """
381- A special getter for Document properties. The major difference from
382- the super class's :py:meth:`Annotation.get` method is that Document
383- class has one more set of *"pending"* properties, that are added after
384- the Document object is created and will be serialized as a separate
385- :py:class:`Annotation` object of which ``@type = Annotation``. The
386- pending properties will take the priority over the regular properties
387- when there are conflicts.
408+ Safe property access with optional default value for Document objects.
409+
410+ Searches for a document property by name and returns its value, or a
411+ default value if not found. Documents have a more complex property
412+ hierarchy than regular annotations:
413+
414+ Priority order (highest to lowest):
415+ 1. Special fields ('id', 'location')
416+ 2. Pending properties (added after creation, to be serialized as ``Annotation`` objects)
417+ 3. Ephemeral properties (from existing ``Annotation`` annotations or view metadata)
418+ 4. Original properties (in ``document.properties``)
419+
420+ This allows convenient access to all document properties regardless of
421+ where they're stored internally.
422+
423+ :param prop_name: The name of the property to retrieve
424+ :param default: The value to return if the property is not found (default: None)
425+ :return: The property value, or the default value if not found
426+
427+ Examples
428+ --------
429+ .. code-block:: python
430+
431+ # Access document properties:
432+ mime = document.get('mime', default='application/octet-stream')
433+ location = document.get('location')
434+
435+ # Access properties added after creation (pending):
436+ author = document.get('author', default='anonymous')
437+ publisher = document.get('publisher')
438+
439+ # Access ephemeral properties from Annotation objects:
440+ sentiment = document.get('sentiment', default='neutral')
441+
442+ See Also
443+ --------
444+ add_property : Add a new property to the document
445+ Mmif.generate_capital_annotations : How pending properties are serialized
388446 """
389447 if prop_name == 'id' :
390448 # because all three dicts have `id` key as required field, we need
@@ -399,7 +457,7 @@ class has one more set of *"pending"* properties, that are added after
399457 elif prop_name in self ._props_ephemeral :
400458 return self ._props_ephemeral [prop_name ]
401459 else :
402- return super ().get (prop_name )
460+ return super ().get (prop_name , default )
403461
404462 get_property = get
405463
@@ -559,8 +617,8 @@ def _deserialize(self, input_dict: dict) -> None:
559617 self .location = input_dict .pop ("location" )
560618 super ()._deserialize (input_dict )
561619
562- def _serialize (self , alt_container : Optional [ Dict ] = None ) -> dict :
563- serialized = super ()._serialize ()
620+ def _serialize (self , * args , ** kwargs ) -> dict :
621+ serialized = super ()._serialize (** kwargs )
564622 if "location_" in serialized :
565623 serialized ["location" ] = serialized .pop ("location_" )
566624 return serialized
0 commit comments