def test_association(): association1 = Association(identifier='test-association1', src_topic_ref='test-topic1', dest_topic_ref='test-topic2') # Instantiate and open topic store. store = TopicStore(username, password) store.open() # Persist association to store. if not store.topic_exists(TOPIC_MAP_IDENTIFIER, 'test-association1'): store.set_association(TOPIC_MAP_IDENTIFIER, association1) # Retrieve occurrence from store. association2 = store.get_association(TOPIC_MAP_IDENTIFIER, 'test-association1', resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES) store.close() assert association2.identifier == 'test-association1' assert association2.instance_of == 'association' assert association2.scope == '*' # Universal scope. assert len(association2.base_names) == 1 assert association2.first_base_name.name == 'Undefined' assert association2.first_base_name.language is Language.ENG assert len(association2.attributes) == 1 assert len(association2.occurrences) == 0 assert len(association2.members) == 2 assert association2.members[0].role_spec == 'related' assert association2.members[1].role_spec == 'related'
def test_occurrence(): occurrence1 = Occurrence(identifier='test-occurrence1', topic_identifier='test-topic1', resource_ref='http://example.com/resource.pdf', language=Language.DEU) # Instantiate and open topic store. store = TopicStore(username, password) store.open() # Persist occurrence to store. if not store.occurrence_exists(TOPIC_MAP_IDENTIFIER, 'test-occurrence1'): store.set_occurrence(TOPIC_MAP_IDENTIFIER, occurrence1) # Retrieve occurrence from store. occurrence2 = store.get_occurrence(TOPIC_MAP_IDENTIFIER, 'test-occurrence1', resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES) store.close() assert occurrence2.identifier == 'test-occurrence1' assert occurrence2.topic_identifier == 'test-topic1' assert occurrence2.instance_of == 'occurrence' assert occurrence2.scope == '*' # Universal scope. assert occurrence2.resource_ref == 'http://example.com/resource.pdf' assert occurrence2.resource_data is None assert occurrence2.language is Language.DEU assert len(occurrence2.attributes) == 1
def test_topic(): topic1 = Topic(identifier='test-topic1', base_name='Test Topic 1', language=Language.SPA) # Instantiate and open topic store. store = TopicStore(username, password) store.open() # Persist topic to store. if not store.topic_exists(TOPIC_MAP_IDENTIFIER, 'test-topic1'): store.set_topic(TOPIC_MAP_IDENTIFIER, topic1) # Retrieve topic from store. topic2 = store.get_topic(TOPIC_MAP_IDENTIFIER, 'test-topic1', resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES) store.close() assert topic2.identifier == 'test-topic1' assert topic2.instance_of == 'topic' assert len(topic2.base_names) == 1 assert topic2.first_base_name.name == 'Test Topic 1' assert topic2.first_base_name.language is Language.SPA assert len(topic2.attributes) == 1 assert len(topic2.occurrences) == 0
def test_attribute(): attribute1 = Attribute('name', 'true', 'test-entity1', identifier='test-attribute1', data_type=DataType.BOOLEAN, language=Language.FRA) # Instantiate and open topic store. store = TopicStore(username, password) store.open() # Persist attribute to store. if not store.attribute_exists(TOPIC_MAP_IDENTIFIER, 'test-entity1', 'name'): store.set_attribute(TOPIC_MAP_IDENTIFIER, attribute1) # Retrieve attribute from store. attribute2 = store.get_attribute(TOPIC_MAP_IDENTIFIER, 'test-attribute1') store.close() assert attribute2.identifier == 'test-attribute1' assert attribute2.name == 'name' assert attribute2.value == 'true' assert attribute2.entity_identifier == 'test-entity1' assert attribute2.scope == '*' # Universal scope. assert attribute2.data_type is DataType.BOOLEAN assert attribute2.language is Language.FRA
def __init__( self, username: str, password: str, host: str = "localhost", port: int = 5432, dbname: str = "storydb", source_directory: str = None, destination_directory: str = None, ) -> None: self.topic_store = TopicStore(username, password, host, port, dbname) self.source_directory = source_directory self.destination_directory = destination_directory
def test_topic_occurrences(): # Instantiate and open topic store. with TopicStore(database_username, database_password, dbname=database_name) as store: # Retrieve topic from store. topic2 = store.get_topic( TOPIC_MAP_IDENTIFIER, "test-topic1", resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, resolve_occurrences=RetrievalMode.RESOLVE_OCCURRENCES, ) assert topic2.identifier == "test-topic1" assert topic2.instance_of == "topic" assert len(topic2.base_names) == 1 assert topic2.first_base_name.name == "Test Topic 1" assert topic2.first_base_name.language is Language.SPA assert len(topic2.attributes) == 1 assert len(topic2.occurrences) >= 1 assert topic2.occurrences[0].identifier == "test-occurrence1" assert topic2.occurrences[0].topic_identifier == "test-topic1" assert topic2.occurrences[0].instance_of == "occurrence" assert topic2.occurrences[0].scope == "*" # Universal scope. assert topic2.occurrences[ 0].resource_ref == "http://example.com/resource.pdf" assert topic2.occurrences[0].resource_data is None assert topic2.occurrences[0].language is Language.DEU assert len(topic2.occurrences[0].attributes) == 0
def test_attribute(): attribute1 = Attribute( "name", "true", "test-entity1", identifier="test-attribute1", data_type=DataType.BOOLEAN, language=Language.FRA, ) # Instantiate and open topic store. with TopicStore(database_username, database_password, dbname=database_name) as store: # Persist attribute to store. if not store.attribute_exists(TOPIC_MAP_IDENTIFIER, "test-entity1", "name"): store.set_attribute(TOPIC_MAP_IDENTIFIER, attribute1) # Retrieve attribute from store. attribute2 = store.get_attribute(TOPIC_MAP_IDENTIFIER, "test-attribute1") assert attribute2.identifier == "test-attribute1" assert attribute2.name == "name" assert attribute2.value == "true" assert attribute2.entity_identifier == "test-entity1" assert attribute2.scope == "*" # Universal scope. assert attribute2.data_type is DataType.BOOLEAN assert attribute2.language is Language.FRA
def test_topic(): topic1 = Topic(identifier="test-topic1", base_name="Test Topic 1", language=Language.SPA) # Instantiate and open topic store. with TopicStore(database_username, database_password, dbname=database_name) as store: # Persist topic to store. if not store.topic_exists(TOPIC_MAP_IDENTIFIER, "test-topic1"): store.set_topic(TOPIC_MAP_IDENTIFIER, topic1) # Retrieve topic from store. topic2 = store.get_topic( TOPIC_MAP_IDENTIFIER, "test-topic1", resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, ) assert topic2.identifier == "test-topic1" assert topic2.instance_of == "topic" assert len(topic2.base_names) == 1 assert topic2.first_base_name.name == "Test Topic 1" assert topic2.first_base_name.language is Language.SPA assert len(topic2.attributes) == 1 assert len(topic2.occurrences) == 0
def test_occurrence_resource_data(): resource_data = b'<p>This is some text with a <a href="https://www.google.com">test</a> link.</p>' occurrence1 = Occurrence( identifier="test-occurrence2", topic_identifier="test-topic1", resource_data=resource_data, ) # Instantiate and open topic store. with TopicStore(database_username, database_password, dbname=database_name) as store: # Persist occurrence to store. if not store.occurrence_exists(TOPIC_MAP_IDENTIFIER, "test-occurrence2"): store.set_occurrence(TOPIC_MAP_IDENTIFIER, occurrence1) # Retrieve occurrence from store. occurrence2 = store.get_occurrence( TOPIC_MAP_IDENTIFIER, "test-occurrence2", resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, inline_resource_data=RetrievalMode.INLINE_RESOURCE_DATA, ) # Converting the resource data from bytes to string. assert ( occurrence2.resource_data.decode("utf-8") == '<p>This is some text with a <a href="https://www.google.com">test</a> link.</p>' )
def test_occurrence(): occurrence1 = Occurrence( identifier="test-occurrence1", topic_identifier="test-topic1", resource_ref="http://example.com/resource.pdf", language=Language.DEU, ) # Instantiate and open topic store. with TopicStore(database_username, database_password, dbname=database_name) as store: # Persist occurrence to store. if not store.occurrence_exists(TOPIC_MAP_IDENTIFIER, "test-occurrence1"): store.set_occurrence(TOPIC_MAP_IDENTIFIER, occurrence1) # Retrieve occurrence from store. occurrence2 = store.get_occurrence( TOPIC_MAP_IDENTIFIER, "test-occurrence1", resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, ) assert occurrence2.identifier == "test-occurrence1" assert occurrence2.topic_identifier == "test-topic1" assert occurrence2.instance_of == "occurrence" assert occurrence2.scope == "*" # Universal scope. assert occurrence2.resource_ref == "http://example.com/resource.pdf" assert occurrence2.resource_data is None assert occurrence2.language is Language.DEU assert len(occurrence2.attributes) == 1
def test_topic_occurrences(): # Instantiate and open topic store. store = TopicStore(username, password) store.open() # Retrieve topic from store. topic2 = store.get_topic(TOPIC_MAP_IDENTIFIER, 'test-topic1', resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES, resolve_occurrences=RetrievalOption.RESOLVE_OCCURRENCES) store.close() assert topic2.identifier == 'test-topic1' assert topic2.instance_of == 'topic' assert len(topic2.base_names) == 1 assert topic2.first_base_name.name == 'Test Topic 1' assert topic2.first_base_name.language is Language.SPA assert len(topic2.attributes) == 1 assert len(topic2.occurrences) >= 1 assert topic2.occurrences[0].identifier == 'test-occurrence1' assert topic2.occurrences[0].topic_identifier == 'test-topic1' assert topic2.occurrences[0].instance_of == 'occurrence' assert topic2.occurrences[0].scope == '*' # Universal scope. assert topic2.occurrences[0].resource_ref == 'http://example.com/resource.pdf' assert topic2.occurrences[0].resource_data is None assert topic2.occurrences[0].language is Language.DEU assert len(topic2.occurrences[0].attributes) == 0
def get_topic_store(): if "topicstore" not in g: g.topic_store = TopicStore( current_app.config["TOPIC_STORE_USER"], current_app.config["TOPIC_STORE_PASSWORD"], dbname=current_app.config["TOPIC_STORE_DBNAME"], ) g.topic_store.open() return g.topic_store
def test_occurrence_resource_data(): resource_data = '<p>This is some text with a <a href="https://www.google.com">test</a> link.</p>' occurrence1 = Occurrence(identifier='test-occurrence2', topic_identifier='test-topic1', resource_data=resource_data) # Instantiate and open topic store. store = TopicStore(username, password) store.open() # Persist occurrence to store. if not store.occurrence_exists(TOPIC_MAP_IDENTIFIER, 'test-occurrence2'): store.set_occurrence(TOPIC_MAP_IDENTIFIER, occurrence1) # Retrieve occurrence from store. occurrence2 = store.get_occurrence(TOPIC_MAP_IDENTIFIER, 'test-occurrence2', resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES, inline_resource_data=RetrievalOption.INLINE_RESOURCE_DATA) store.close() # Converting the resource data from bytes to string. assert occurrence2.resource_data.decode("utf-8") == '<p>This is some text with a <a href="https://www.google.com">test</a> link.</p>'
def test_association(): association1 = Association( identifier="test-association1", src_topic_ref="test-topic1", dest_topic_ref="test-topic2", ) # Instantiate and open topic store. with TopicStore(database_username, database_password, dbname=database_name) as store: # Associations are topics, as well (in TopicDB). For that reason, to check for the existence of an # association we can use the *topic_exists* method. if not store.topic_exists(TOPIC_MAP_IDENTIFIER, "test-association1"): store.set_association( TOPIC_MAP_IDENTIFIER, association1) # Persist association to store. # Retrieve occurrence from store. association2 = store.get_association( TOPIC_MAP_IDENTIFIER, "test-association1", resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, ) assert association2.identifier == "test-association1" assert association2.instance_of == "association" assert association2.scope == "*" # Universal scope. assert len(association2.base_names) == 1 assert association2.first_base_name.name == "Undefined" assert association2.first_base_name.language is Language.ENG assert len(association2.attributes) == 1 assert len(association2.occurrences) == 0 assert len(association2.members) == 2 assert association2.members[0].role_spec == "related" assert association2.members[1].role_spec == "related"
Brett Alistair Kromkamp ([email protected]) """ import configparser import os from topicdb.core.store.topicstore import TopicStore SETTINGS_FILE_PATH = os.path.join(os.path.dirname(__file__), '../settings.ini') config = configparser.ConfigParser() config.read(SETTINGS_FILE_PATH) username = config['DATABASE']['Username'] password = config['DATABASE']['Password'] # Instantiate and open topic store. store = TopicStore(username, password) store.open() store.set_topic_map( 1, "The Doomsday Weapon", "A soldier has to infiltrate behind enemy lines to steal the plans for a secret doomsday weapon." ) store.set_topic_map( 2, "An Unexpected Meeting", "Two people meet ever so briefly. A chance encounter that changes their lives forever." ) store.close()
from topicdb.core.store.topicstore import TopicStore SETTINGS_FILE_PATH = os.path.join(os.path.dirname(__file__), "../../settings.ini") USER_IDENTIFIER_1 = 1 USER_IDENTIFIER_2 = 2 config = configparser.ConfigParser() config.read(SETTINGS_FILE_PATH) database_username = config["DATABASE"]["Username"] database_password = config["DATABASE"]["Password"] database_name = config["DATABASE"]["Database"] # Instantiate and open topic store, create and subsequently populate topic maps. with TopicStore(database_username, database_password, dbname=database_name) as store: store.set_topic_map( USER_IDENTIFIER_1, "Bacon Ipsum Dolor", "Bacon ipsum dolor amet in ham esse sirloin turducken kevin occaecat qui kielbasa eiusmod cow anim andouille proident pig. Laborum tail id tempor voluptate.", ) store.set_topic_map( USER_IDENTIFIER_2, "Fatback Alcatra Short", "Fatback alcatra short loin, ribeye sirloin duis swine cupidatat. Biltong lorem in tail ut shank et. Pastrami culpa salami, aliquip alcatra enim short loin.", shared=True, ) store.set_topic_map( USER_IDENTIFIER_2, "Officia Sed Irure", "Officia sed irure, beef ham ham hock sunt ex ball tip in elit nulla magna duis aliquip. Est kielbasa ullamco meatloaf cupidatat magna tempor sausage id beef ribs commodo duis sint cow.",
class StoryStore: def __init__( self, username: str, password: str, host: str = "localhost", port: int = 5432, dbname: str = "storydb", source_directory: str = None, destination_directory: str = None, ) -> None: self.topic_store = TopicStore(username, password, host, port, dbname) self.source_directory = source_directory self.destination_directory = destination_directory def open(self) -> StoryStore: self.topic_store.open() return self def close(self) -> None: self.topic_store.close() @staticmethod def to_boolean(value): if isinstance(value, str) and value: if value.lower() in ["true", "t", "1"]: return True elif value.lower() in ["false", "f", "0"]: return False raise StoryDbError( f"The [{value}] is not recognized as a boolean value") # ========== CONTEXT MANAGER ========== def __enter__(self) -> StoryStore: return self.open() def __exit__(self, exc_type, exc_val, exc_tb) -> None: self.close() # ========== ENTITY ========== # Persist participant, thing, place and event entities def set_entity(self, map_identifier: int, entity: Entity, event_identifier: str = None) -> None: if (self.source_directory is None) or (self.destination_directory is None): raise StoryDbError("Missing resource directories") if not self.topic_store.topic_exists(map_identifier, entity.identifier): topic = Topic(entity.identifier, entity.instance_of, entity.name) timestamp = str(datetime.now()) modification_attribute = Attribute( "modification-timestamp", timestamp, topic.identifier, data_type=DataType.TIMESTAMP, ) self.topic_store.set_topic(map_identifier, topic) self.topic_store.set_attribute(map_identifier, modification_attribute) if hasattr(entity, "description") and entity.description: text_occurrence = Occurrence( instance_of="text", topic_identifier=entity.identifier, resource_data=entity.description, ) self.topic_store.set_occurrence(map_identifier, text_occurrence) if hasattr(entity, "animation") and entity.animation: entity.add_attribute( Attribute( "animation", entity.animation, entity.identifier, data_type=DataType.STRING, )) # Create the file directory for this topic map and topic if it doesn't already exist file_directory = os.path.join(self.destination_directory, str(map_identifier), entity.identifier) if not os.path.isdir(file_directory): os.makedirs(file_directory) for resource in entity.resources: occurrence = Occurrence( instance_of=resource.instance_of, topic_identifier=entity.identifier, resource_ref=resource.reference, resource_data=resource.data, ) title_attribute = Attribute( "title", resource.title, occurrence.identifier, data_type=DataType.STRING, ) self.topic_store.set_occurrence(map_identifier, occurrence) self.topic_store.set_attribute(map_identifier, title_attribute) # Copy resource file to appropriate (topic) directory if occurrence.resource_ref: source_file_path = os.path.join(self.source_directory, occurrence.resource_ref) destination_file_path = os.path.join( self.destination_directory, str(map_identifier), entity.identifier, occurrence.resource_ref, ) if not os.path.isfile(destination_file_path): shutil.copy(source_file_path, destination_file_path) if hasattr(entity, "tags"): self.topic_store.set_tags(map_identifier, entity.identifier, entity.tags) self.topic_store.set_attributes(map_identifier, entity.attributes) if event_identifier: association = Association( instance_of=entity.instance_of, src_topic_ref=entity.identifier, dest_topic_ref=event_identifier, src_role_spec="included-in", dest_role_spec="includes", ) self.topic_store.set_association(map_identifier, association) # ========== PARTICIPANT ========== def get_participant(self, map_identifier: int, identifier: str) -> Optional[Participant]: result = None topic = self.topic_store.get_topic( map_identifier, identifier, resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, ) if topic: result = Participant(topic.identifier, topic.first_base_name.name) result.description = ( topic.get_attribute_by_name("description").value if topic.get_attribute_by_name("description") else None) result.animation = (topic.get_attribute_by_name("animation").value if topic.get_attribute_by_name("animation") else None) occurrences = self.topic_store.get_topic_occurrences( map_identifier, identifier) for occurrence in occurrences: if occurrence.instance_of == "text": text_data = self.topic_store.get_occurrence_data( map_identifier, occurrence.identifier) result.add_resource( Resource( occurrence.instance_of, reference=occurrence.resource_ref, data=text_data, )) else: result.add_resource( Resource(occurrence.instance_of, reference=occurrence.resource_ref)) attributes = [ attribute for attribute in topic.attributes if attribute.name not in ("description", "animation") ] result.add_attributes(attributes) result.add_tags( self.topic_store.get_tags(map_identifier, identifier)) return result # ========== THING ========== def get_thing(self, map_identifier: int, identifier: str) -> Optional[Thing]: result = None topic = self.topic_store.get_topic( map_identifier, identifier, resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, ) if topic: result = Thing(topic.identifier, topic.first_base_name.name) result.description = ( topic.get_attribute_by_name("description").value if topic.get_attribute_by_name("description") else None) result.animation = (topic.get_attribute_by_name("animation").value if topic.get_attribute_by_name("animation") else None) occurrences = self.topic_store.get_topic_occurrences( map_identifier, identifier) for occurrence in occurrences: if occurrence.instance_of == "text": text_data = self.topic_store.get_occurrence_data( map_identifier, occurrence.identifier) result.add_resource( Resource( occurrence.instance_of, reference=occurrence.resource_ref, data=text_data, )) else: result.add_resource( Resource(occurrence.instance_of, reference=occurrence.resource_ref)) attributes = [ attribute for attribute in topic.attributes if attribute.name not in ("description", "animation") ] result.add_attributes(attributes) result.add_tags( self.topic_store.get_tags(map_identifier, identifier)) return result # ========== PLACE ========== def get_place(self, map_identifier: int, identifier: str) -> Optional[Place]: result = None topic = self.topic_store.get_topic( map_identifier, identifier, resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, ) if topic: result = Place(topic.identifier, topic.first_base_name.name) result.description = ( topic.get_attribute_by_name("description").value if topic.get_attribute_by_name("description") else None) result.animation = (topic.get_attribute_by_name("animation").value if topic.get_attribute_by_name("animation") else None) result.auto_rotate = (self.to_boolean( topic.get_attribute_by_name("auto-rotate").value) if topic.get_attribute_by_name("auto-rotate") else None) result.view_labels = (self.to_boolean( topic.get_attribute_by_name("view-labels").value) if topic.get_attribute_by_name("view-labels") else None) associations = self.topic_store.get_topic_associations( map_identifier, identifier, resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, ) for association in associations: if association.instance_of == "spatial-navigation": destination_identifier = association.get_member_by_role( "to").topic_refs[0] if destination_identifier != identifier: description = self.topic_store.get_topic( map_identifier, destination_identifier).first_base_name.name navigation_identifier = association.get_attribute_by_name( "navigation-identifier").value result.add_path( Path( navigation_identifier=navigation_identifier, event_identifier=destination_identifier, description=description, )) occurrences = self.topic_store.get_topic_occurrences( map_identifier, identifier) for occurrence in occurrences: if occurrence.instance_of == "text": text_data = self.topic_store.get_occurrence_data( map_identifier, occurrence.identifier) result.add_resource( Resource( occurrence.instance_of, reference=occurrence.resource_ref, data=text_data, )) else: result.add_resource( Resource(occurrence.instance_of, reference=occurrence.resource_ref)) attributes = [ attribute for attribute in topic.attributes if attribute.name not in ("description", "animation", "auto-rotate", "view-labels") ] result.add_attributes(attributes) return result def set_place(self, map_identifier: int, place: Place, event_identifier: str = None) -> None: place.add_attribute( Attribute( "auto-rotate", place.auto_rotate, place.identifier, data_type=DataType.BOOLEAN, )) place.add_attribute( Attribute( "view-labels", place.view_labels, place.identifier, data_type=DataType.BOOLEAN, )) self.set_entity(map_identifier, place, event_identifier) # ========== EVENT ========== def get_event( self, map_identifier: int, identifier: str, resolve_sub_events: ResolveMode = ResolveMode.RESOLVE_SUB_EVENTS, resolve_causes: ResolveMode = ResolveMode.RESOLVE_CAUSES, resolve_effects: ResolveMode = ResolveMode.RESOLVE_EFFECTS, call_level: int = 0, ) -> Optional[Event]: result = None topic = self.topic_store.get_topic( map_identifier, identifier, resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES, resolve_occurrences=RetrievalMode.RESOLVE_OCCURRENCES, ) if topic: rank = topic.get_attribute_by_name("rank").value # What? action_property = topic.get_attribute_by_name( "action-property").value result = Event( topic.identifier, action_property, rank=int(rank), name=topic.first_base_name.name, ) topic_occurrences = self.topic_store.get_topic_occurrences( map_identifier, identifier, inline_resource_data=RetrievalMode.INLINE_RESOURCE_DATA) for occurrence in topic_occurrences: if occurrence.instance_of == "text" and occurrence.resource_data: result.description = occurrence.resource_data.decode() associations = self.topic_store.get_topic_associations( map_identifier, identifier) # Who, where, what and why? groups = self.topic_store.get_association_groups( map_identifier, identifier, associations=associations) if len(groups) > 0: for instance_of in groups.dict: for role in groups.dict[instance_of]: for topic_ref in groups[instance_of, role]: if topic_ref == identifier: continue elif instance_of == "thing": result.add_thing( self.get_thing(map_identifier, topic_ref)) elif instance_of == "participant": result.add_participant( self.get_participant( map_identifier, topic_ref)) elif instance_of == "place": result.where = self.get_place( map_identifier, topic_ref) elif (resolve_causes is ResolveMode.RESOLVE_CAUSES and role == "cause" and instance_of == "temporal-navigation"): if call_level < 1: # Recursive call cause = self.get_event( map_identifier, topic_ref, call_level=call_level + 1) result.add_cause(cause) elif (resolve_effects is ResolveMode.RESOLVE_EFFECTS and role == "effect" and instance_of == "temporal-navigation"): if call_level < 1: # Recursive call effect = self.get_event( map_identifier, topic_ref, call_level=call_level + 1) result.add_effect(effect) elif (resolve_sub_events is ResolveMode.RESOLVE_SUB_EVENTS and role == "included-in" and instance_of == "event"): if call_level < 1: # Recursive call sub_event = self.get_event( map_identifier, topic_ref, call_level=call_level + 1) result.events[topic_ref] = sub_event # When? from_time_point = topic.get_attribute_by_name( "from-time-point").value to_time_point = topic.get_attribute_by_name("to-time-point").value result.when = TimeInterval(from_time_point, to_time_point) for occurrence in topic.occurrences: if occurrence.instance_of == "text": text_data = self.topic_store.get_occurrence_data( map_identifier, occurrence.identifier) result.add_resource( Resource( occurrence.instance_of, reference=occurrence.resource_ref, data=text_data, )) else: result.add_resource( Resource(occurrence.instance_of, reference=occurrence.resource_ref)) attributes = [ attribute for attribute in topic.attributes if attribute.name not in ("description") ] result.add_attributes(attributes) # Tags-to-entities mapping result.entities_tags = self.get_entities_tags( map_identifier, identifier, associations=associations) return result def set_event(self, map_identifier: int, event: Event, parent_event: Event = None) -> None: if not self.topic_store.topic_exists(map_identifier, event.identifier): event.add_attribute( Attribute("rank", str(event.rank), event.identifier, data_type=DataType.NUMBER)) # What? event.add_attribute( Attribute( "action-property", event.action_property, event.identifier, data_type=DataType.STRING, )) # When? if event.when is None: timestamp = str(datetime.now()) event.when = TimeInterval(timestamp, timestamp) event.add_attribute( Attribute( "from-time-point", event.when.from_time_point, event.identifier, data_type=DataType.TIMESTAMP, )) event.add_attribute( Attribute( "to-time-point", event.when.to_time_point, event.identifier, data_type=DataType.TIMESTAMP, )) self.set_entity(map_identifier, event) # What? if parent_event: association = Association( instance_of="event", src_topic_ref=event.identifier, dest_topic_ref=parent_event.identifier, src_role_spec="included-in", dest_role_spec="includes", ) self.topic_store.set_association(map_identifier, association) for key, value in event.events.items(): self.set_event(map_identifier, value, event) # Recursive call # Who? for key, value in event.participants.items(): self.set_entity(map_identifier, value, event.identifier) for key, value in event.things.items(): self.set_entity(map_identifier, value, event.identifier) # Where? if event.where: self.set_place(map_identifier, event.where, event.identifier) # ========== TAG ========== def get_entities_tags( self, map_identifier: int, identifier: str, associations: Optional[List[Association]] = None, ) -> Dict[str, Set[str]]: result: Dict[str, Set[str]] = {} # Map from topics with tags to tags with topics. For example, the below topic -> tags mappings: # topic1 -> tag1, tag2, tag3 # topic2 -> tag2, tag4 # topic3 -> tag3, tag4, tag5 # topic4 -> tag4, tag5, tag6, tag7 # topic5 -> tag1, tag8 # # Should become the following tag -> topics mappings: # tag1 -> topic1, topic5 # tag2 -> topic1, topic2 # tag3 -> topic1, topic3 # tag4 -> topic2, topic3, topic4 # tag5 -> topic3, topic4 # tag6 -> topic4 # tag7 -> topic4 # tag8 -> topic5 topic_tags = {} groups = self.topic_store.get_association_groups( map_identifier, identifier, associations=associations) if groups: for instance_of in groups.dict: for role in groups.dict[instance_of]: for topic_ref in groups[instance_of, role]: if topic_ref == identifier: continue if instance_of in ("participant", "thing"): topic_tags[topic_ref] = self.topic_store.get_tags( map_identifier, topic_ref) for topic, tags in topic_tags.items(): for tag in tags: if tag not in result.keys(): result[tag] = { topic } # Topics set. Will guarantee that topic identifiers are unique for each tag. else: result[tag].add(topic) return result def get_tag(self, map_identifier: int, identifier: str) -> Optional[Tag]: result = None topic = self.topic_store.get_topic( map_identifier, identifier, resolve_occurrences=RetrievalMode.RESOLVE_OCCURRENCES, ) if topic: result = Tag(topic.identifier) for occurrence in topic.occurrences: if occurrence.instance_of == "text": text_data = self.topic_store.get_occurrence_data( map_identifier, occurrence.identifier) result.description = text_data return result # ========== TIMELINE ========== def get_timeline(self, map_identifier: int, event_identifier: str, timeline: List[Event] = None) -> List[Event]: if timeline is None: result = [] else: result = timeline event = self.get_event( map_identifier, event_identifier, ResolveMode.DONT_RESOLVE_SUB_EVENTS, ResolveMode.RESOLVE_CAUSES, ) result.append(event) # Recursive call for effect_identifier in event.effects.keys(): self.get_timeline(map_identifier, effect_identifier, result) return result # ========== NARRATIVE ========== def get_narrative( self, map_identifier: int, event_identifier: str, description_identifier: str = "home") -> Optional[Narrative]: result = None topic = self.topic_store.get_topic(map_identifier, description_identifier) if topic: topic_occurrences = self.topic_store.get_topic_occurrences( map_identifier, description_identifier, inline_resource_data=RetrievalMode.INLINE_RESOURCE_DATA) description = "" for occurrence in topic_occurrences: if occurrence.instance_of == "text" and occurrence.resource_data: if occurrence.resource_data: description = occurrence.resource_data.decode() result = Narrative(topic.first_base_name.name, description) result.timeline = self.get_timeline(map_identifier, event_identifier) result.timeline = sorted(result.timeline, key=lambda event: event.rank) return result # ========== CONNECTION ========== def set_spatial_connection( self, map_identifier: int, source_identifier: str, destination_identifier: str, navigation_identifier: str, ) -> None: association = Association( instance_of="spatial-navigation", src_topic_ref=source_identifier, dest_topic_ref=destination_identifier, src_role_spec="from", dest_role_spec="to", ) attribute = Attribute( "navigation-identifier", navigation_identifier, association.identifier, data_type=DataType.STRING, ) self.topic_store.set_association(map_identifier, association) self.topic_store.set_attribute(map_identifier, attribute) def set_temporal_connection(self, map_identifier: int, source_identifier: str, destination_identifier: str) -> None: association = Association( instance_of="temporal-navigation", src_topic_ref=source_identifier, dest_topic_ref=destination_identifier, src_role_spec="cause", dest_role_spec="effect", ) self.topic_store.set_association(map_identifier, association) # ========== MISCELLANEOUS ========== def initialise(self, map_identifier: int, user_identifier: int) -> None: base_topics = { ("event", "Event"), ("thing", "Thing"), ("participant", "Participant"), ("place", "Place"), ("included-in", "Included In"), ("includes", "Includes"), ("cause", "Cause"), ("effect", "Effect"), ("temporal-navigation", "Temporal Navigation"), ("spatial-navigation", "Spatial Navigation"), ("from", "From"), ("to", "To"), } for item in base_topics: topic = Topic( identifier=item[TopicField.IDENTIFIER.value], name=item[TopicField.BASE_NAME.value], ) self.topic_store.set_topic(map_identifier, topic, TaxonomyMode.LENIENT) self.topic_store.initialise_topic_map(map_identifier, user_identifier)
class SceneStore: def __init__(self, username, password, host='localhost', port=5432): self.topic_store = TopicStore(username, password, host, port) def open(self): self.topic_store.open() def close(self): self.topic_store.close() def get_character(self, topic_map_identifier, identifier): result = None topic = self.topic_store.get_topic( topic_map_identifier, identifier, resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES) if topic: result = Character(topic.identifier, topic.first_base_name.name) result.description = topic.get_attribute_by_name( 'description').value if topic.get_attribute_by_name( 'description') else None result.location = topic.get_attribute_by_name('location').value result.rotation = topic.get_attribute_by_name('rotation').value result.scale = topic.get_attribute_by_name('scale').value occurrences = self.topic_store.get_topic_occurrences( topic_map_identifier, identifier) for occurrence in occurrences: result.add_asset( Asset(occurrence.instance_of, occurrence.resource_ref)) attributes = [ attribute for attribute in topic.attributes if attribute.name not in ('description', 'location', 'rotation', 'scale') ] result.add_attributes(attributes) return result def get_prop(self, topic_map_identifier, identifier): result = None topic = self.topic_store.get_topic( topic_map_identifier, identifier, resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES) if topic: result = Prop(topic.identifier, topic.first_base_name.name) result.description = topic.get_attribute_by_name( 'description').value if topic.get_attribute_by_name( 'description') else None result.location = topic.get_attribute_by_name('location').value result.rotation = topic.get_attribute_by_name('rotation').value result.scale = topic.get_attribute_by_name('scale').value occurrences = self.topic_store.get_topic_occurrences( topic_map_identifier, identifier) for occurrence in occurrences: result.add_asset( Asset(occurrence.instance_of, occurrence.resource_ref)) attributes = [ attribute for attribute in topic.attributes if attribute.name not in ('description', 'location', 'rotation', 'scale') ] result.add_attributes(attributes) return result def get_scene(self, topic_map_identifier, identifier): result = None topic = self.topic_store.get_topic( topic_map_identifier, identifier, resolve_attributes=RetrievalOption.RESOLVE_ATTRIBUTES) if topic: result = Scene(topic.identifier, topic.first_base_name.name) result.description = topic.get_attribute_by_name( 'description').value if topic.get_attribute_by_name( 'description') else None result.location = topic.get_attribute_by_name('location').value result.rotation = topic.get_attribute_by_name('rotation').value result.scale = topic.get_attribute_by_name('scale').value result.ordinal = topic.get_attribute_by_name( 'ordinal').value if topic.get_attribute_by_name( 'ordinal') else None result.add_associations( self.topic_store.get_topic_associations( topic_map_identifier, identifier)) # Add scene's entities (props and characters). if result.associations: groups = self.topic_store.get_association_groups( topic_map_identifier, identifier) for instance_of in groups.dict: for role in groups.dict[instance_of]: for topic_ref in groups[instance_of, role]: if topic_ref == identifier: continue if instance_of == 'navigation': path = Path(role, topic_ref) result.add_path(path) elif instance_of == 'prop': result.add_entity( self.get_prop(topic_map_identifier, topic_ref)) elif instance_of == 'character': result.add_entity( self.get_prop(topic_map_identifier, topic_ref)) elif instance_of == 'categorization': # Tags. result.add_tag(topic_ref) occurrences = self.topic_store.get_topic_occurrences( topic_map_identifier, identifier) for occurrence in occurrences: result.add_asset( Asset(occurrence.instance_of, occurrence.resource_ref)) attributes = [ attribute for attribute in topic.attributes if attribute.name not in ('description', 'location', 'rotation', 'scale', 'ordinal') ] result.add_attributes(attributes) result.entities_tags = self.get_entities_tags( topic_map_identifier, identifier) return result def get_quest(self, topic_map_identifier, identifier): result = None # TODO: Implement. return result def set_character(self, topic_map_identifier, character, scene_identifier): topic = Topic(character.identifier, character.instance_of, character.name) self.topic_store.set_topic(topic_map_identifier, topic) description_attribute = Attribute( 'description', character.description, topic.identifier) if character.description else None location_attribute = Attribute('location', character.location, topic.identifier) rotation_attribute = Attribute('rotation', character.rotation, topic.identifier) scale_attribute = Attribute('scale', character.scale, topic.identifier) attributes = [ x for x in [ description_attribute, location_attribute, rotation_attribute, scale_attribute ] if x is not None ] self.topic_store.set_attributes(topic_map_identifier, attributes) for asset in character.assets: occurrence = Occurrence(instance_of=asset.instance_of, topic_identifier=topic.identifier, resource_ref=asset.reference, resource_data=asset.data) self.topic_store.set_occurrence(topic_map_identifier, occurrence) scene_association = Association( instance_of='character', src_topic_ref=topic.identifier, # The character's reference. dest_topic_ref=scene_identifier, src_role_spec='included-in', dest_role_spec='includes') self.topic_store.set_association(topic_map_identifier, scene_association) book_association = Association( instance_of='character', src_topic_ref=topic.identifier, # The character's reference. dest_topic_ref='genesis', src_role_spec='included-in', dest_role_spec='includes', scope='book') self.topic_store.set_association(topic_map_identifier, book_association) def set_prop(self, topic_map_identifier, prop, scene_identifier): topic = Topic(prop.identifier, prop.instance_of, prop.name) self.topic_store.set_topic(topic_map_identifier, topic) description_attribute = Attribute( 'description', prop.description, topic.identifier) if prop.description else None location_attribute = Attribute('location', prop.location, topic.identifier) rotation_attribute = Attribute('rotation', prop.rotation, topic.identifier) scale_attribute = Attribute('scale', prop.scale, topic.identifier) attributes = [ x for x in [ description_attribute, location_attribute, rotation_attribute, scale_attribute ] if x is not None ] self.topic_store.set_attributes(topic_map_identifier, attributes) for asset in prop.assets: occurrence = Occurrence(instance_of=asset.instance_of, topic_identifier=topic.identifier, resource_ref=asset.reference, resource_data=asset.data) self.topic_store.set_occurrence(topic_map_identifier, occurrence) scene_association = Association( instance_of='prop', src_topic_ref=topic.identifier, # The prop's reference. dest_topic_ref=scene_identifier, src_role_spec='included-in', dest_role_spec='includes') self.topic_store.set_association(topic_map_identifier, scene_association) book_association = Association( instance_of='prop', src_topic_ref=topic.identifier, # The prop's reference. dest_topic_ref='genesis', src_role_spec='included-in', dest_role_spec='includes', scope='book') self.topic_store.set_association(topic_map_identifier, book_association) def set_scene(self, topic_map_identifier, scene): topic = Topic(scene.identifier, scene.instance_of, scene.name) self.topic_store.set_topic(topic_map_identifier, topic) description_attribute = Attribute( 'description', scene.description, topic.identifier) if scene.description else None location_attribute = Attribute('location', scene.location, topic.identifier) rotation_attribute = Attribute('rotation', scene.rotation, topic.identifier) scale_attribute = Attribute('scale', scene.scale, topic.identifier) ordinal_attribute = Attribute( 'ordinal', scene.ordinal, topic.identifier) if scene.ordinal else None attributes = [ x for x in [ description_attribute, location_attribute, rotation_attribute, scale_attribute, ordinal_attribute ] if x is not None ] self.topic_store.set_attributes(topic_map_identifier, attributes) for asset in scene.assets: occurrence = Occurrence(instance_of=asset.instance_of, topic_identifier=topic.identifier, resource_ref=asset.reference, resource_data=asset.data) self.topic_store.set_occurrence(topic_map_identifier, occurrence) book_association = Association( instance_of='scene', src_topic_ref=topic.identifier, # The scene's reference. dest_topic_ref='genesis', src_role_spec='included-in', dest_role_spec='includes', scope='book') self.topic_store.set_association(topic_map_identifier, book_association) def set_quest(self, topic_map_identifier, quest, scene_identifier): # TODO: Implement. pass def set_navigation(self, topic_map_identifier, src_scene_identifier, dest_scene_identifier, src_scene_role='previous', dest_scene_role='next'): association = Association(instance_of='navigation', src_topic_ref=src_scene_identifier, dest_topic_ref=dest_scene_identifier, src_role_spec=src_scene_role, dest_role_spec=dest_scene_role) self.topic_store.set_association(topic_map_identifier, association) def get_entities_tags(self, topic_map_identifier, identifier): result = {} # Map from topics with tags to tags with topics. For example, the below topic -> tags mappings: # topic1 -> tag1, tag2, tag3 # topic2 -> tag2, tag4 # topic3 -> tag3, tag4, tag5 # topic4 -> tag4, tag5, tag6, tag7 # topic5 -> tag1, tag8 # # Should become the following tag -> topics mappings: # tag1 -> topic1, topic5 # tag2 -> topic1, topic2 # tag3 -> topic1, topic3 # tag4 -> topic2, topic3, topic4 # tag5 -> topic3, topic4 # tag6 -> topic4 # tag7 -> topic4 # tag8 -> topic5 topic_tags = {} groups = self.topic_store.get_association_groups( topic_map_identifier, identifier) for instance_of in groups.dict: for role in groups.dict[instance_of]: for topic_ref in groups[instance_of, role]: if topic_ref == identifier: continue if instance_of == 'prop' or instance_of == 'character': topic_tags[topic_ref] = self.topic_store.get_tags( topic_map_identifier, topic_ref) for topic, tags in topic_tags.items(): for tag in tags: if tag not in result.keys(): result[tag] = { topic } # Topics set. Will guarantee that topic identifiers are unique for each tag. else: result[tag].add(topic) return result # ========== TOPIC STORE PROXY METHODS ========== def get_association( self, topic_map_identifier, identifier, language=None, resolve_attributes=RetrievalOption.DONT_RESOLVE_ATTRIBUTES, resolve_occurrences=RetrievalOption.DONT_RESOLVE_OCCURRENCES): return self.topic_store.get_association(topic_map_identifier, identifier, language, resolve_attributes, resolve_occurrences) def get_association_groups(self, topic_map_identifier, identifier='', associations=None, instance_of=None, scope=None): return self.topic_store.get_association_groups(topic_map_identifier, identifier, associations, instance_of=instance_of, scope=scope) def get_attributes(self, topic_map_identifier, entity_identifier, scope=None, language=None): return self.topic_store.get_attributes(topic_map_identifier, entity_identifier, scope, language) def get_attribute(self, topic_map_identifier, identifier): return self.topic_store.get_attribute(topic_map_identifier, identifier) def get_occurrence( self, topic_map_identifier, identifier, inline_resource_data=RetrievalOption.DONT_INLINE_RESOURCE_DATA, resolve_attributes=RetrievalOption.DONT_RESOLVE_ATTRIBUTES): return self.topic_store.get_occurrence(topic_map_identifier, identifier, inline_resource_data, resolve_attributes) def get_topic_occurrences( self, topic_map_identifier, identifier, instance_of=None, scope=None, language=None, inline_resource_data=RetrievalOption.DONT_INLINE_RESOURCE_DATA, resolve_attributes=RetrievalOption.DONT_RESOLVE_ATTRIBUTES): return self.topic_store.get_topic_occurrences(topic_map_identifier, identifier, instance_of, scope, language, inline_resource_data, resolve_attributes) def get_topic( self, topic_map_identifier, identifier, language=None, resolve_attributes=RetrievalOption.DONT_RESOLVE_ATTRIBUTES, resolve_occurrences=RetrievalOption.DONT_RESOLVE_OCCURRENCES): return self.topic_store.get_topic(topic_map_identifier, identifier, language, resolve_attributes, resolve_occurrences) def get_topic_identifiers(self, topic_map_identifier, query, offset=0, limit=100): return self.topic_store.get_topic_identifiers( topic_map_identifier, query, instance_of=['prop', 'character', 'scene'], offset=offset, limit=limit) def get_topics(self, topic_map_identifier, instance_of=None, language=None, offset=0, limit=100, resolve_attributes=RetrievalOption.DONT_RESOLVE_ATTRIBUTES): return self.topic_store.get_topics(topic_map_identifier, instance_of, language, offset, limit, resolve_attributes) def get_topics_network(self, topic_map_identifier, identifier, maximum_depth=10, cumulative_depth=0, accumulative_tree=None, accumulative_nodes=None): return self.topic_store.get_topics_network( topic_map_identifier, identifier, maximum_depth, cumulative_depth, accumulative_tree, accumulative_nodes, instance_of=['prop', 'character', 'scene', 'navigation'], scope='*') def get_topic_map(self, identifier): return self.topic_store.get_topic_map(identifier) def get_topic_maps(self): return self.topic_store.get_topic_maps() def set_attribute(self, topic_map_identifier, attribute, ontology_mode=OntologyMode.LENIENT): self.topic_store.set_attribute(topic_map_identifier, attribute, ontology_mode) def set_tags(self, topic_map_identifier, identifier, tags): self.topic_store.set_tags(topic_map_identifier, identifier, tags) def set_occurrence(self, topic_map_identifier, occurrence, ontology_mode=OntologyMode.STRICT): self.topic_store.set_occurrence(topic_map_identifier, occurrence, ontology_mode) def set_topic(self, topic_map_identifier, topic, ontology_mode=OntologyMode.STRICT): self.topic_store.set_topic(topic_map_identifier, topic, ontology_mode)
def get_topic_store(): if "topic_store" not in g: g.topic_store = TopicStore( database_path=current_app.config["DATABASE_PATH"]) return g.topic_store
def __init__(self, username, password, host='localhost', port=5432): self.topic_store = TopicStore(username, password, host, port)
SETTINGS_FILE_PATH = os.path.join(os.path.dirname(__file__), "../settings.ini") USER_IDENTIFIER_1 = 1 config = configparser.ConfigParser() config.read(SETTINGS_FILE_PATH) database_username = config["DATABASE"]["Username"] database_password = config["DATABASE"]["Password"] database_name = config["DATABASE"]["Database"] database_host = config["DATABASE"]["Host"] database_port = config["DATABASE"]["Port"] # Instantiate and open topic store, create and subsequently populate topic maps with TopicStore( database_username, database_password, host=database_host, port=database_port, dbname=database_name, ) as store: store.set_topic_map( USER_IDENTIFIER_1, "Bacon Ipsum Dolor", "Bacon ipsum dolor amet in ham esse sirloin turducken kevin occaecat qui kielbasa eiusmod cow anim andouille proident pig. Laborum tail id tempor voluptate.", ) # Populate topic maps (with pre-defined topics) for 'USER_IDENTIFIER_1' for topic_map in store.get_topic_maps(USER_IDENTIFIER_1): store.initialise_topic_map(topic_map.identifier)
store_association( store, topic_map_identifier, previous_identifier, "previous", next_identifier, "next", ) # ================================================================================ if __name__ == "__main__": topic_store = TopicStore( database_username, database_password, host=database_host, port=database_port, dbname=database_name, ) tree = Tree() create_tree() print("-" * 80) tree.display(ROOT_TOPIC) print("-" * 80) for node in tree.traverse(ROOT_TOPIC, mode=TraversalMode.DEPTH): print(f"{node.payload.identifier} - {node.payload.instance_of} - {node.payload.first_base_name.name}") print("Creating topics...") create_topics(topic_store, TOPIC_MAP_IDENTIFIER) print("Topics created!") print("-" * 80) print("Creating associations...")