@ -24,7 +24,7 @@ approach."""
from . . topo_v3 import TopologyV3 , VertexID , Edge , VertexFinder
from . . topo_v3 import TopologyV3 , VertexID , Edge , VertexFinder
from collections import defaultdict
from collections import defaultdict
from collections . abc import Hashable
from collections . abc import Hashable , Sequence
from dataclasses import dataclass , field
from dataclasses import dataclass , field
from abc import ABC , abstractmethod
from abc import ABC , abstractmethod
from typing import Any
from typing import Any
@ -58,6 +58,7 @@ class AnnotatedTopology:
if ann_id in self . annotations :
if ann_id in self . annotations :
if ann_id . annotator . idempotent : return None # Shortcut :-)
if ann_id . annotator . idempotent : return None # Shortcut :-)
# Scrap old data before re-running
# Scrap old data before re-running
# FIXME: What to do with interfaces?
old_annot = self . annotations [ ann_id ]
old_annot = self . annotations [ ann_id ]
for v in old_annot . for_vertex :
for v in old_annot . for_vertex :
self . vertex_annotators [ v ] . remove ( ann_id )
self . vertex_annotators [ v ] . remove ( ann_id )
@ -73,9 +74,10 @@ class AnnotatedTopology:
if annotation . annotated_topology is not None and annotation . annotated_topology != self :
if annotation . annotated_topology is not None and annotation . annotated_topology != self :
raise ValueError ( ' Annotator claims to annotate different topology! ' )
raise ValueError ( ' Annotator claims to annotate different topology! ' )
annotation . topology = self
annotation . topology = self
if annotation . annotator_id is not None and annotation . annotator_id != ann_id :
if annotation . annotator_id is not None and annotation . annotator_id != ann_id and annotation . annotator_id not in ann_id . interfaces :
raise ValueError ( ' Annotator fakes its ID! ' )
raise ValueError ( ' Annotator fakes its ID! ' )
annotation . annotator_id = ann_id
if annotation . annotator_id is None :
annotation . annotator_id = ann_id
for v in annotation . for_vertex :
for v in annotation . for_vertex :
self . vertex_annotators [ v ] . add ( ann_id )
self . vertex_annotators [ v ] . add ( ann_id )
for e in annotation . for_edge :
for e in annotation . for_edge :
@ -146,8 +148,24 @@ class Annotator(ABC):
for use by other programs . Using basic types like scalars , lists and
for use by other programs . Using basic types like scalars , lists and
dictionaries is probably safe , but using sets is not ( please , think of the
dictionaries is probably safe , but using sets is not ( please , think of the
~ ~ kittens ~ ~ JSON and use dicts with 1 as a value . ) . Once the Annotation is
~ ~ kittens ~ ~ JSON and use dicts with 1 as a value . ) . Once the Annotation is
output , it must not be modified ( and reference to it should not be kept ) . """
output , it must not be modified ( and reference to it should not be kept ) .
The Annotation may by default only be scoped under the ID of the Annotator
( i . e . Annotation . annotator is the AnnotatorID of the Annotator which
created that Annotation ) . While this design prevents the clashes of
different Annotations , it does not provide any way for different Annotators
to provide Annotations in the same scope , thus requiring knowledge of the
exact Annotator that was used to create the retrieved Annotation . We
elevate this issue by allowing Annotators to specify a set of other
AnnotatorIDs in the : attr : interface attribute , which are also permitted to
be output . However , there can only exist one Annotation for each interface ,
so using this requires being careful . Also , an Annotator can only return
one Annotation , so you might want to use two Annotators : one for the actual
annotation , and second for transforming that Annotation into the interfaced
one . ( The specific syntax of the interface is determined by the class
mentioned in the interface ' s AnnotatorID.) " " "
idempotent : bool = False
idempotent : bool = False
interfaces : Sequence [ AnnotatorID ] = ( )
@abstractmethod
@abstractmethod
def __init__ ( self , param : None | Hashable ) : . . .
def __init__ ( self , param : None | Hashable ) : . . .
@abstractmethod
@abstractmethod