Skip to content

handling of annotation props in contains metadata #396

Description

@keighrim

Bug Description

The MMIF spec is explicit that "the annotation-level value takes precedence over the view-level default", and the serialization package honors this when the canonical property name is used — the annotation's value lives in .properties, which Annotation.getitem checks before any distributed contains default.

However, when reading an older MMIF that carries the value under a deprecated property name (which the implementation aliases to the canonical name via _prop_aliases and _props_ephemeral for temporary storage for canonicalization),

view._parent_mmif = self
# this dict will be populated with properties
# that are not encoded in individual annotations objects themselves
extrinsic_props = defaultdict(dict)
for at_type, type_lv_props in view.metadata.contains.items():
for prop_key, prop_value in type_lv_props.items():
extrinsic_props[at_type][prop_key] = prop_value
for ann in view.get_annotations():
## for "capital" Annotation properties
# first add all extrinsic properties to the Annotation objects
# as "ephemeral" properties
for prop_key, prop_value in extrinsic_props[ann.at_type].items():
ann._props_ephemeral[prop_key] = prop_value
# then, do the same to associated Document objects. Note that,
# in a view, it is guaranteed that all Annotation objects are not duplicates
if ann.at_type == AnnotationTypes.Annotation:
doc_id = ann.get_property('document')
try:
for prop_key, prop_value in ann.properties.items():
doc = cast(Document, self.__getitem__(doc_id))
if not isinstance(doc, Document):
raise KeyError
doc._props_ephemeral[prop_key] = prop_value

the common-prop distribution step writes the "view-level default" value into that same temporary dict and hinders the canonicalization step, resulting in loss of the aliased (annotation-level) prop value. Namely the overwrite priority works in reverse.

Reproduction steps

For example,

{
  "metadata": { "mmif": "http://mmif.clams.ai/1.2.0" },
  "documents": [
    { "@type": "http://mmif.clams.ai/vocabulary/VideoDocument/v1",
      "properties": { "id": "m1", "mime": "video/mp4", "location": "file:///v.mp4" } }
  ],
  "views": [
    { "id": "v1",
      "metadata": {
        "app": "http://example.com/app/1.0",
        "contains": {
          "http://mmif.clams.ai/vocabulary/TimeFrame/v6": { "document": "m1", "label": "credits" }
        }
      },
      "annotations": [
        { "@type": "http://mmif.clams.ai/vocabulary/TimeFrame/v6",
          "properties": { "id": "v1:tf1", "start": 0, "end": 100, "frameType": "bars" } }
      ]
    }
  ]
}

After reading this MMIF,

m = Mmif(in_str)
print(m.get('v1:tf1').get('label'))
# "credits", not "bars"


### Expected behavior

_No response_

### Log output

```shell

Screenshots

No response

Additional context

this was found while working on #393

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛BSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions