diff --git a/goblin/api.py b/goblin/api.py index 3b021059246b1b7f6a910ae94e980bbdc7e2fa50..67d8e767053a6487d90a0f3f8ac73f2a00b382d3 100644 --- a/goblin/api.py +++ b/goblin/api.py @@ -272,8 +272,9 @@ class ElementMeta(type): for k, v in namespace.items(): if isinstance(v, properties.Property): props[k] = v - v = properties.PropertyDescriptor(k, v.data_type, - initval=v._initval) + data_type = v.data_type + v = properties.PropertyDescriptor(k, data_type, + default=v._default) new_namespace[k] = v new_namespace['__mapping__'] = mapper.create_mapping(namespace, props) @@ -303,7 +304,7 @@ class Edge(metaclass=ElementMeta): self._source = val def delsource(self): - del self._source + raise ValueError("Cant") source = property(getsource, setsource, delsource) diff --git a/goblin/properties.py b/goblin/properties.py index 20e506706e08d16719228ad1fa7b69df4c0ee0c4..9be2fd7be769ed57030964733c41d0ebcc3e108a 100644 --- a/goblin/properties.py +++ b/goblin/properties.py @@ -1,12 +1,15 @@ """Classes to handle proerties and data type definitions""" +import abc class Property: """API class used to define properties. Replaced with :py:class:`PropertyDescriptor` by :py:class:`api.ElementMeta`.""" - def __init__(self, data_type, *, initval=None): + def __init__(self, data_type, *, default=None): + if isinstance(data_type, type): + data_type = data_type() self._data_type = data_type - self._initval = initval + self._default = default @property def data_type(self): @@ -17,38 +20,54 @@ class PropertyDescriptor: """Descriptor that validates user property input and gets/sets properties as instance attributes.""" - def __init__(self, name, data_type, *, initval=None): + def __init__(self, name, data_type, *, default=None): self._name = '_' + name self._data_type = data_type - self._initval = initval + self._default = default def __get__(self, obj, objtype): if obj is None: return self._data_type - return getattr(obj, self._name, self._initval) + return getattr(obj, self._name, self._default) def __set__(self, obj, val): setattr(obj, self._name, self._data_type.validate(val)) def __delete__(self, obj): - raise ValueError("Cannot delete element properties") + # hmmm what is the best approach here + attr = getattr(obj, self._name, None) + if attr: + del attr + + +class DataType(abc.ABC): + + @abc.abstractmethod + def validate(self): + raise NotImplementedError + + @abc.abstractmethod + def to_db(self, val): + return val + + @abc.abstractmethod + def to_ogm(self, val): + return val # Data types -class String: +class String(DataType): """Simple string datatype""" - @classmethod - def validate(cls, val): - if val: + + def validate(self, val): + if val is not None: try: return str(val) except Exception as e: raise Exception("Invalid") from e - @classmethod - def to_db(cls, val): - return val + def to_db(self, val): + return super().to_db(val) - @classmethod - def to_ogm(cls, val): - return val + def to_ogm(self, val): + return super().to_ogm(val) diff --git a/tests/test_engine.py b/tests/test_engine.py index eea649f8cf797ab88addbce7f2b0b4ec442e91bd..fb0d3081ccf74e8c5317ceff0c9ab966ee6e216e 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -8,12 +8,12 @@ from goblin.properties import Property, String class TestVertex(Vertex): __label__ = 'test_vertex' name = Property(String) - notes = Property(String, initval='N/A') + notes = Property(String, default='N/A') class TestEdge(Edge): __label__ = 'test_edge' - notes = Property(String, initval='N/A') + notes = Property(String, default='N/A') class TestEngine(unittest.TestCase):