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

ENH: Added serialization methods

parent 1bc2c28e
No related branches found
No related tags found
2 merge requests!57RELEASE 0.7.3,!52F refactor high level api
Pipeline #19518 failed
......@@ -41,8 +41,11 @@ from .apiutils import get_type_of_entity_with
from typing import Any, Optional, List, Union, Dict
import yaml
from dataclasses import dataclass, fields
from datetime import datetime
from dateutil import parser
@dataclass
class CaosDBPropertyMetaData:
......@@ -101,6 +104,9 @@ class CaosDBPythonEntity(object):
self._description: Optional[str] = None
self._version: Optional[str] = None
self._file: Optional[str] = None
self._path: Optional[str] = None
# name: name of property, value: property metadata
self._properties_metadata: Dict[CaosDBPropertyMetaData] = dict()
......@@ -130,6 +136,28 @@ class CaosDBPythonEntity(object):
def name(self, val: str):
self._name = val
@property
def file(self):
"""
Getter for the file.
"""
return self._file
@name.setter
def file(self, val: str):
self._file = val
@property
def path(self):
"""
Getter for the path.
"""
return self._path
@name.setter
def path(self, val: str):
self._path = val
@property
def description(self):
"""
......@@ -148,6 +176,10 @@ class CaosDBPythonEntity(object):
"""
return self._version
@version.setter
def version(self, val: str):
self._version = val
# @staticmethod
# def _get_new_id():
# """
......@@ -159,7 +191,7 @@ class CaosDBPythonEntity(object):
# return CaosDBPythonEntity._last_id
def _set_property_from_entity(self, ent: db.Entity):
def _set_property_from_entity(self, ent: db.Entity, importance: str):
"""
Set a new property using an entity from the normal python API.
......@@ -168,14 +200,17 @@ class CaosDBPythonEntity(object):
"""
val = self._type_converted_value(ent.value, ent.datatype)
metadata = self.get_property_metadata(ent.name)
for prop_name in fields(metadata):
k = prop_name.name
metadata.__setattr__(k, ent.__getattribute__(k))
self.set_property(
ent.name,
val,
datatype=ent.datatype)
metadata = self.get_property_metadata(ent.name)
for prop_name in fields(metadata):
k = prop_name.name
if k == "importance":
metadata.importance = importance
else:
metadata.__setattr__(k, ent.__getattribute__(k))
def get_property_metadata(self, prop_name: str) -> CaosDBPropertyMetaData:
"""
......@@ -322,8 +357,7 @@ class CaosDBPythonEntity(object):
"""
if isinstance(val, datetime):
return val
# TODO: try different representations
return datetime.strptime("%Y-%m-%d %H:%M:%S", val)
return parser.parse(val)
def get_property(self, name: str):
"""
......@@ -352,12 +386,18 @@ class CaosDBPythonEntity(object):
return [att]
def add_parent(self, parent: Union[
CaosDBPythonUnresolvedParent, "CaosDBPythonRecordType"]):
CaosDBPythonUnresolvedParent, "CaosDBPythonRecordType", str]):
"""
Add a parent to this entity. Either using an unresolved parent or
using a real record type.
Strings as argument for parent will automatically be converted to an
unresolved parent.
"""
if isinstance(parent, str):
parent = CaosDBPythonUnresolvedParent(name=parent)
if self.has_parent(parent):
raise RuntimeError("Duplicate parent.")
self._parents.append(parent)
......@@ -374,16 +414,6 @@ class CaosDBPythonEntity(object):
return True
return False
# 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):
......@@ -416,22 +446,59 @@ class CaosDBPythonEntity(object):
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"
def get_properties(self):
"""
Return the names of all properties.
"""
for p in self._properties:
value = self.__getattribute__(p)
return [p for p in self.__dict__
if p not in self._forbidden]
if isinstance(value, CaosDBPythonEntity):
result += indent * "\t" + \
value.__str__(indent=indent + 1, name=p)
def serialize(self, without_metadata: bool = False):
"""
Serialize necessary information into a dict.
"""
metadata: dict[str, Any] = dict()
properties = dict()
parents = list()
for parent in self._parents:
if isinstance(parent, CaosDBPythonEntity):
parents.append(parent.serialize())
elif isinstance(parent, CaosDBPythonUnresolvedParent):
parents.append({"name": parent.name, "id": parent.id,
"unresolved": True})
else:
raise RuntimeError("Incompatible class used as parent.")
for p in self.get_properties():
m = self.get_property_metadata(p)
metadata[p] = dict()
for f in fields(m):
metadata[p][f.name] = m.__getattribute__(f.name)
val = self.get_property(p)
if isinstance(val, CaosDBPythonUnresolvedReference):
properties[p] = {"id": val.id, "unresolved": True}
elif isinstance(val, CaosDBPythonEntity):
properties[p] = val.serialize(without_metadata)
else:
result += indent * "\t" + p + "\n"
properties[p] = val
if without_metadata:
return {
"properties": properties,
"parents": parents}
return {
"metadata": metadata,
"properties": properties,
"parents": parents}
return result
def __str__(self):
return yaml.dump(self.serialize(False))
def __repr__(self):
return yaml.dump(self.serialize(True))
class CaosDBPythonRecord(CaosDBPythonEntity):
......@@ -452,20 +519,22 @@ class CaosDBPythonFile(CaosDBPythonEntity):
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)
def _single_convert_to_python_object(robj: CaosDBPythonEntity,
entity: db.Entity):
robj.id = entity.id
robj.name = entity.name
robj.description = entity.description
robj.version = entity.version
for i in entity.parents:
robj._add_parent(i)
for prop in entity.properties:
robj._set_property_from_entity(prop, entity.get_importance(prop))
if entity.path is not None:
robj._path = entity.path
for parent in entity.parents:
robj.add_parent(CaosDBPythonUnresolvedParent(id=parent.id,
name=parent.name))
if entity.file is not None:
robj._file = entity.file
robj.path = entity.path
robj.file = entity.file
return robj
......
# -*- encoding: utf-8 -*-
#
# This file is a part of the CaosDB Project.
#
# Copyright (C) 2018 Research Group Biomedical Physics,
......@@ -72,4 +70,6 @@ def test_convert_record():
obj = convert_to_python_object(r)
assert obj.a == 42
assert obj.b == "test"
breakpoint()
with pytest.raises(RuntimeError):
obj.add_parent("bla")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment