67 lines
1.8 KiB
Python
67 lines
1.8 KiB
Python
import abc
|
|
|
|
|
|
class AutoStorage:
|
|
__counter = 0
|
|
|
|
def __init__(self):
|
|
cls = self.__class__
|
|
prefix = cls.__name__
|
|
index = cls.__counter
|
|
self.storage_name = '_{}#{}'.format(prefix, index)
|
|
cls.__counter += 1
|
|
|
|
def __get__(self, instance, owner):
|
|
if instance is None:
|
|
return self
|
|
else:
|
|
return getattr(instance, self.storage_name)
|
|
|
|
def __set__(self, instance, value):
|
|
setattr(instance, self.storage_name, value)
|
|
|
|
|
|
class Validated(abc.ABC, AutoStorage):
|
|
|
|
def __set__(self, instance, value):
|
|
value = self.validate(instance, value)
|
|
super().__set__(instance, value)
|
|
|
|
@abc.abstractmethod
|
|
def validate(self, instance, value):
|
|
"""return validated value or raise ValueError"""
|
|
|
|
|
|
class Quantity(Validated):
|
|
"""a number greater than zero"""
|
|
|
|
def validate(self, instance, value):
|
|
if value <= 0:
|
|
raise ValueError('value must be > 0')
|
|
return value
|
|
|
|
|
|
class NonBlank(Validated):
|
|
"""a string with at least one non-space character"""
|
|
|
|
def validate(self, instance, value):
|
|
value = value.strip()
|
|
if len(value) == 0:
|
|
raise ValueError('value cannot be empty or blank')
|
|
return value
|
|
|
|
# tag::MODEL_V7[]
|
|
class EntityMeta(type):
|
|
"""Metaclass for business entities with validated fields"""
|
|
|
|
def __init__(cls, name, bases, attr_dict):
|
|
super().__init__(name, bases, attr_dict) # <1>
|
|
for key, attr in attr_dict.items(): # <2>
|
|
if isinstance(attr, Validated):
|
|
type_name = type(attr).__name__
|
|
attr.storage_name = '_{}#{}'.format(type_name, key)
|
|
|
|
class Entity(metaclass=EntityMeta): # <3>
|
|
"""Business entity with validated fields"""
|
|
# end::MODEL_V7[]
|