diff --git a/src/caosdb/apiutils.py b/src/caosdb/apiutils.py index dbab28f963d4d167c4dfc097e25527dfc0baad50..e4987c489d7a19e25c8ca3355dbd258ef70a0da1 100644 --- a/src/caosdb/apiutils.py +++ b/src/caosdb/apiutils.py @@ -97,22 +97,6 @@ def create_id_query(ids): ["ID={}".format(id) for id in ids]) -def retrieve_entity_with_id(eid): - return execute_query("FIND ENTITY WITH ID={}".format(eid), unique=True) - - -def retrieve_entities_with_ids(entities): - collection = Container() - step = 20 - - for i in range(len(entities)//step+1): - collection.extend( - execute_query( - create_id_query(entities[i*step:(i+1)*step]))) - - return collection - - def get_type_of_entity_with(id_): objs = retrieve_entities_with_ids([id_]) @@ -136,385 +120,20 @@ def get_type_of_entity_with(id_): return Entity -class CaosDBPythonEntity(object): - - _last_id = 0 - - def __init__(self): - # Save a copy of the dry state - # of this object in order to be - # able to detect conflicts. - self.do_not_expand = False - self._parents = [] - self._id = CaosDBPythonEntity._get_id() - self._path = None - self._file = None - self.pickup = None - # TODO: - # 3.) resolve references up to a specific depth (including infinity) - # 4.) resolve parents function -> partially implemented by - # get_parent_names - self._references = {} - self._properties = set() - self._datatypes = {} - self._forbidden = dir(self) - - @staticmethod - def _get_id(): - CaosDBPythonEntity._last_id -= 1 - - return CaosDBPythonEntity._last_id - - def _set_property_from_entity(self, ent): - name = ent.name - val = ent.value - pr = ent.datatype - val, reference = self._type_converted_value(val, pr) - self.set_property(name, val, reference, datatype=pr) - - def set_property(self, name, value, is_reference=False, - overwrite=False, datatype=None): - """ - overwrite: Use this if you definitely only want one property with that name (set to True). - """ - self._datatypes[name] = datatype - - if isinstance(name, Entity): - name = name.name - - if name in self._forbidden: - raise RuntimeError("Entity cannot be converted to a corresponding " - "Python representation. Name of property " + - name + " is forbidden!") - already_exists = (name in dir(self)) - - if already_exists and not overwrite: - # each call to _set_property checks first if it already exists - # if yes: Turn the attribute into a list and - # place all the elements into that list. - att = self.__getattribute__(name) - - if isinstance(att, list): - pass - else: - old_att = self.__getattribute__(name) - self.__setattr__(name, [old_att]) - - if is_reference: - self._references[name] = [ - self._references[name]] - att = self.__getattribute__(name) - att.append(value) - - if is_reference: - self._references[name].append(int(value)) - else: - if is_reference: - self._references[name] = value - self.__setattr__(name, value) - - if not (already_exists and overwrite): - self._properties.add(name) - - add_property = set_property - - def set_id(self, idx): - self._id = idx - - def _type_converted_list(self, val, pr): - """Convert a list to a python list of the correct type.""" - prrealpre = pr.replace("<", "<").replace(">", ">") - prreal = prrealpre[prrealpre.index("<") + 1:prrealpre.rindex(">")] - lst = [self._type_converted_value(i, prreal) for i in val] - - return ([i[0] for i in lst], lst[0][1]) - - def _type_converted_value(self, val, pr): - """Convert val to the correct type which is indicated by the database - type string in pr. - - Returns a tuple with two entries: - - the converted value - - True if the value has to be interpreted as an id acting as a reference - """ - - if val is None: - return (None, False) - elif pr == DOUBLE: - return (float(val), False) - elif pr == BOOLEAN: - return (bool(val), False) - elif pr == INTEGER: - return (int(val), False) - elif pr == TEXT: - return (val, False) - elif pr == FILE: - return (int(val), False) - elif pr == REFERENCE: - return (int(val), True) - elif pr == DATETIME: - return (val, False) - elif pr[0:4] == "LIST": - return self._type_converted_list(val, pr) - elif isinstance(val, Entity): - return (convert_to_python_object(val), False) - else: - return (int(val), True) - - def attribute_as_list(self, name): - """This is a workaround for the problem that lists containing only one - element are indistinguishable from simple types in this - representation.""" - att = self.__getattribute__(name) - - if isinstance(att, list): - return att - else: - return [att] - - def _add_parent(self, parent): - self._parents.append(parent.id) - - def add_parent(self, parent_id=None, parent_name=None): - if parent_id is not None: - self._parents.append(parent_id) - elif parent_name is not None: - self._parents.append(parent_name) - else: - raise ValueError("no parent identifier supplied") - - def get_parent_names(self): - new_plist = [] - - for p in self._parents: - obj_type = get_type_of_entity_with(p) - ent = obj_type(id=p).retrieve() - new_plist.append(ent.name) - - return new_plist - - def resolve_references(self, deep=False, visited=dict()): - for i in self._references: - if isinstance(self._references[i], list): - for j in range(len(self._references[i])): - new_id = self._references[i][j] - obj_type = get_type_of_entity_with(new_id) - - if new_id in visited: - new_object = visited[new_id] - else: - ent = obj_type(id=new_id).retrieve() - new_object = convert_to_python_object(ent) - visited[new_id] = new_object - - if deep: - new_object.resolve_references(deep, visited) - self.__getattribute__(i)[j] = new_object - else: - new_id = self._references[i] - obj_type = get_type_of_entity_with(new_id) - - if new_id in visited: - new_object = visited[new_id] - else: - ent = obj_type(id=new_id).retrieve() - new_object = convert_to_python_object(ent) - visited[new_id] = new_object - - if deep: - new_object.resolve_references(deep, visited) - self.__setattr__(i, new_object) - - def __str__(self, indent=1, name=None): - if name is None: - result = str(self.__class__.__name__) + "\n" - else: - result = name + "\n" - - for p in self._properties: - value = self.__getattribute__(p) - - if isinstance(value, CaosDBPythonEntity): - result += indent * "\t" + \ - value.__str__(indent=indent + 1, name=p) - else: - result += indent * "\t" + p + "\n" - - return result - - -class CaosDBPythonRecord(CaosDBPythonEntity): - pass - - -class CaosDBPythonRecordType(CaosDBPythonEntity): - pass - - -class CaosDBPythonProperty(CaosDBPythonEntity): - pass - - -class CaosDBPythonFile(CaosDBPythonEntity): - def get_File(self, target=None): - f = File(id=self._id).retrieve() - self._file = f.download(target) - - -def _single_convert_to_python_object(robj, entity): - robj._id = entity.id - - for i in entity.properties: - robj._set_property_from_entity(i) - - for i in entity.parents: - robj._add_parent(i) - - if entity.path is not None: - robj._path = entity.path - - if entity.file is not None: - robj._file = entity.file - # if entity.pickup is not None: - # robj.pickup = entity.pickup - - return robj - - -def _single_convert_to_entity(entity, robj, recursive_depth, **kwargs): - """ - recursive_depth: disabled if 0 - """ - if robj._id is not None: - entity.id = robj._id - - if robj._path is not None: - entity.path = robj._path - - if robj._file is not None: - entity.file = robj._file - - if robj.pickup is not None: - entity.pickup = robj.pickup - children = [] - - for parent in robj._parents: - if sys.version_info[0] < 3: - if hasattr(parent, "encode"): - entity.add_parent(name=parent) - else: - entity.add_parent(id=parent) - else: - if hasattr(parent, "encode"): - entity.add_parent(name=parent) - else: - entity.add_parent(id=parent) - - def add_property(entity, prop, name, _recursive=False, datatype=None): - if datatype is None: - raise RuntimeError("Datatype must not be None.") +def retrieve_entity_with_id(eid): + return execute_query("FIND ENTITY WITH ID={}".format(eid), unique=True) - if isinstance(prop, CaosDBPythonEntity): - entity.add_property(name=name, value=str( - prop._id), datatype=datatype) - if _recursive and not prop.do_not_expand: - return convert_to_entity(prop, recursive=_recursive) - else: - return [] - else: - if isinstance(prop, float) or isinstance(prop, int): - prop = str(prop) - entity.add_property(name=name, value=prop, datatype=datatype) +def retrieve_entities_with_ids(entities): + collection = Container() + step = 20 - return [] + for i in range(len(entities)//step+1): + collection.extend( + execute_query( + create_id_query(entities[i*step:(i+1)*step]))) - if recursive_depth == 0: - recursive = False - else: - recursive = True - - for prop in robj._properties: - value = robj.__getattribute__(prop) - - if isinstance(value, list): - if robj._datatypes[prop][0:4] == "LIST": - lst = [] - - for v in value: - if isinstance(v, CaosDBPythonEntity): - lst.append(v._id) - - if recursive and not v.do_not_expand: - children.append(convert_to_entity( - v, recursive=recursive_depth-1)) - else: - if isinstance(v, float) or isinstance(v, int): - lst.append(str(v)) - else: - lst.append(v) - entity.add_property(name=prop, value=lst, - datatype=robj._datatypes[prop]) - else: - for v in value: - children.extend( - add_property( - entity, - v, - prop, - datatype=robj._datatypes[prop], - **kwargs)) - else: - children.extend( - add_property( - entity, - value, - prop, - datatype=robj._datatypes[prop], - **kwargs)) - - return [entity] + children - - -def convert_to_entity(python_object, **kwargs): - if isinstance(python_object, Container): - # Create a list of objects: - - return [convert_to_python_object(i, **kwargs) for i in python_object] - elif isinstance(python_object, CaosDBPythonRecord): - return _single_convert_to_entity(Record(), python_object, **kwargs) - elif isinstance(python_object, CaosDBPythonFile): - return _single_convert_to_entity(File(), python_object, **kwargs) - elif isinstance(python_object, CaosDBPythonRecordType): - return _single_convert_to_entity(RecordType(), python_object, **kwargs) - elif isinstance(python_object, CaosDBPythonProperty): - return _single_convert_to_entity(Property(), python_object, **kwargs) - elif isinstance(python_object, CaosDBPythonEntity): - return _single_convert_to_entity(Entity(), python_object, **kwargs) - else: - raise ValueError("Cannot convert an object of this type.") - - -def convert_to_python_object(entity): - """""" - - if isinstance(entity, Container): - # Create a list of objects: - - return [convert_to_python_object(i) for i in entity] - elif isinstance(entity, Record): - return _single_convert_to_python_object(CaosDBPythonRecord(), entity) - elif isinstance(entity, RecordType): - return _single_convert_to_python_object( - CaosDBPythonRecordType(), entity) - elif isinstance(entity, File): - return _single_convert_to_python_object(CaosDBPythonFile(), entity) - elif isinstance(entity, Property): - return _single_convert_to_python_object(CaosDBPythonProperty(), entity) - elif isinstance(entity, Entity): - return _single_convert_to_python_object(CaosDBPythonEntity(), entity) - else: - raise ValueError("Cannot convert an object of this type.") + return collection def getOriginUrlIn(folder):