Skip to content
Snippets Groups Projects
Commit 52023318 authored by Alexander Schlemmer's avatar Alexander Schlemmer
Browse files

ENH: moved functions from apiutils to high level API

parent 85c60671
No related branches found
No related tags found
2 merge requests!57RELEASE 0.7.3,!52F refactor high level api
......@@ -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("&lt;", "<").replace("&gt;", ">")
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):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment