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

ENH: Added serialization methods

parent 1bc2c28e
Branches
Tags
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 ...@@ -41,8 +41,11 @@ from .apiutils import get_type_of_entity_with
from typing import Any, Optional, List, Union, Dict from typing import Any, Optional, List, Union, Dict
import yaml
from dataclasses import dataclass, fields from dataclasses import dataclass, fields
from datetime import datetime from datetime import datetime
from dateutil import parser
@dataclass @dataclass
class CaosDBPropertyMetaData: class CaosDBPropertyMetaData:
...@@ -101,6 +104,9 @@ class CaosDBPythonEntity(object): ...@@ -101,6 +104,9 @@ class CaosDBPythonEntity(object):
self._description: Optional[str] = None self._description: Optional[str] = None
self._version: 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 # name: name of property, value: property metadata
self._properties_metadata: Dict[CaosDBPropertyMetaData] = dict() self._properties_metadata: Dict[CaosDBPropertyMetaData] = dict()
...@@ -130,6 +136,28 @@ class CaosDBPythonEntity(object): ...@@ -130,6 +136,28 @@ class CaosDBPythonEntity(object):
def name(self, val: str): def name(self, val: str):
self._name = val 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 @property
def description(self): def description(self):
""" """
...@@ -148,6 +176,10 @@ class CaosDBPythonEntity(object): ...@@ -148,6 +176,10 @@ class CaosDBPythonEntity(object):
""" """
return self._version return self._version
@version.setter
def version(self, val: str):
self._version = val
# @staticmethod # @staticmethod
# def _get_new_id(): # def _get_new_id():
# """ # """
...@@ -159,7 +191,7 @@ class CaosDBPythonEntity(object): ...@@ -159,7 +191,7 @@ class CaosDBPythonEntity(object):
# return CaosDBPythonEntity._last_id # 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. Set a new property using an entity from the normal python API.
...@@ -168,14 +200,17 @@ class CaosDBPythonEntity(object): ...@@ -168,14 +200,17 @@ class CaosDBPythonEntity(object):
""" """
val = self._type_converted_value(ent.value, ent.datatype) 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( self.set_property(
ent.name, ent.name,
val, val,
datatype=ent.datatype) 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: def get_property_metadata(self, prop_name: str) -> CaosDBPropertyMetaData:
""" """
...@@ -322,8 +357,7 @@ class CaosDBPythonEntity(object): ...@@ -322,8 +357,7 @@ class CaosDBPythonEntity(object):
""" """
if isinstance(val, datetime): if isinstance(val, datetime):
return val return val
# TODO: try different representations return parser.parse(val)
return datetime.strptime("%Y-%m-%d %H:%M:%S", val)
def get_property(self, name: str): def get_property(self, name: str):
""" """
...@@ -352,12 +386,18 @@ class CaosDBPythonEntity(object): ...@@ -352,12 +386,18 @@ class CaosDBPythonEntity(object):
return [att] return [att]
def add_parent(self, parent: Union[ def add_parent(self, parent: Union[
CaosDBPythonUnresolvedParent, "CaosDBPythonRecordType"]): CaosDBPythonUnresolvedParent, "CaosDBPythonRecordType", str]):
""" """
Add a parent to this entity. Either using an unresolved parent or Add a parent to this entity. Either using an unresolved parent or
using a real record type. 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): if self.has_parent(parent):
raise RuntimeError("Duplicate parent.") raise RuntimeError("Duplicate parent.")
self._parents.append(parent) self._parents.append(parent)
...@@ -374,16 +414,6 @@ class CaosDBPythonEntity(object): ...@@ -374,16 +414,6 @@ class CaosDBPythonEntity(object):
return True return True
return False 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()): def resolve_references(self, deep=False, visited=dict()):
for i in self._references: for i in self._references:
if isinstance(self._references[i], list): if isinstance(self._references[i], list):
...@@ -416,22 +446,59 @@ class CaosDBPythonEntity(object): ...@@ -416,22 +446,59 @@ class CaosDBPythonEntity(object):
new_object.resolve_references(deep, visited) new_object.resolve_references(deep, visited)
self.__setattr__(i, new_object) self.__setattr__(i, new_object)
def __str__(self, indent=1, name=None): def get_properties(self):
if name is None: """
result = str(self.__class__.__name__) + "\n" Return the names of all properties.
else: """
result = name + "\n"
for p in self._properties: return [p for p in self.__dict__
value = self.__getattribute__(p) if p not in self._forbidden]
if isinstance(value, CaosDBPythonEntity): def serialize(self, without_metadata: bool = False):
result += indent * "\t" + \ """
value.__str__(indent=indent + 1, name=p) 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: 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): class CaosDBPythonRecord(CaosDBPythonEntity):
...@@ -452,20 +519,22 @@ class CaosDBPythonFile(CaosDBPythonEntity): ...@@ -452,20 +519,22 @@ class CaosDBPythonFile(CaosDBPythonEntity):
self._file = f.download(target) self._file = f.download(target)
def _single_convert_to_python_object(robj, entity): def _single_convert_to_python_object(robj: CaosDBPythonEntity,
robj._id = entity.id entity: db.Entity):
robj.id = entity.id
for i in entity.properties: robj.name = entity.name
robj._set_property_from_entity(i) robj.description = entity.description
robj.version = entity.version
for i in entity.parents: for prop in entity.properties:
robj._add_parent(i) robj._set_property_from_entity(prop, entity.get_importance(prop))
if entity.path is not None: for parent in entity.parents:
robj._path = entity.path robj.add_parent(CaosDBPythonUnresolvedParent(id=parent.id,
name=parent.name))
if entity.file is not None: robj.path = entity.path
robj._file = entity.file robj.file = entity.file
return robj return robj
......
# -*- encoding: utf-8 -*-
#
# This file is a part of the CaosDB Project. # This file is a part of the CaosDB Project.
# #
# Copyright (C) 2018 Research Group Biomedical Physics, # Copyright (C) 2018 Research Group Biomedical Physics,
...@@ -72,4 +70,6 @@ def test_convert_record(): ...@@ -72,4 +70,6 @@ def test_convert_record():
obj = convert_to_python_object(r) obj = convert_to_python_object(r)
assert obj.a == 42 assert obj.a == 42
assert obj.b == "test" 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