hyperstream/meta_data/meta_data_manager.py
# The MIT License (MIT)
# Copyright (c) 2014-2017 University of Bristol
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
from ..utils import Printable, MetaDataTree
from ..models import MetaDataModel
import logging
from mongoengine.context_managers import switch_db
from treelib.tree import NodeIDAbsentError
class MetaDataManager(Printable):
def __init__(self):
self.global_plate_definitions = MetaDataTree()
self.global_plate_definitions.create_node(identifier="root")
to_be_added = dict((i, d) for i, d, in enumerate(self.global_meta_data))
passes = 0
# Populate the global plate definitions from dict given in the database
while len(to_be_added) > 0:
passes += 1
if passes > 1000:
raise NodeIDAbsentError("Nodes absent for ids {}"
.format(", ".join(map(lambda x: x['identifier'], to_be_added.values()))))
items = list(to_be_added.items())
for i, item in items:
try:
self.global_plate_definitions.create_node(**item)
del to_be_added[i]
except NodeIDAbsentError:
pass
logging.info("Global plate definitions: ")
logging.info(self.global_plate_definitions)
@property
def global_meta_data(self):
"""
Get the global meta data, which will be stored in a tree structure
:return: The global meta data
"""
with switch_db(MetaDataModel, 'hyperstream'):
return sorted(map(lambda x: x.to_dict(), MetaDataModel.objects),
key=lambda x: len(x['identifier'].split('.')),
reverse=True)
def contains(self, identifier):
"""
Determines if the meta data with the given identifier is in the database
:param identifier: The identifier
:return: Whether the identifier is present
"""
return self.global_plate_definitions.contains(identifier)
def insert(self, tag, identifier, parent, data):
"""
Insert the given meta data into the database
:param tag: The tag (equates to meta_data_id)
:param identifier: The identifier (a combination of the meta_data_id and the plate value)
:param parent: The parent plate identifier
:param data: The data (plate value)
:return: None
"""
# First try to add it into the tree
if self.global_plate_definitions.contains(identifier):
raise KeyError("Identifier {} already exists in tree".format(identifier))
self.global_plate_definitions.create_node(tag=tag, identifier=identifier, parent=parent, data=data)
# Now try to add it into the database
with switch_db(MetaDataModel, 'hyperstream'):
meta_data = MetaDataModel(tag=tag, parent=parent, data=data)
meta_data.save()
logging.info("Meta data {} inserted".format(identifier))
def delete(self, identifier):
"""
Delete the meta data with the given identifier from the database
:param identifier: The identifier
:return: None
"""
try:
node = self.global_plate_definitions[identifier]
except NodeIDAbsentError:
logging.info("Meta data {} not present during deletion".format(identifier))
return
# First delete any children of the node: REMOVED as this seemed to be unreliable
# It's now better to call delete_plate with delete_meta_data=True
# for child in node.fpointer:
# self.delete(child)
self.global_plate_definitions.remove_node(identifier)
with switch_db(MetaDataModel, 'hyperstream'):
meta_data = MetaDataModel.objects(tag=node.tag, data=node.data, parent=node.bpointer).first()
if meta_data is not None:
meta_data.delete()
logging.info("Meta data {} deleted".format(identifier))