Convert Object FIELDS from list to dict
This allows for storing additional per-field metadata, for example validation rules or policy triggers. Change-Id: Ie6ad13ecc8e36a881fb2f0b08661fa4ef666b608 Blueprint: validation-cleanup
This commit is contained in:
parent
4b3443e036
commit
ef3a964e1b
@ -29,16 +29,22 @@ def get_attrname(name):
|
||||
|
||||
def make_class_properties(cls):
|
||||
"""Build getter and setter methods for all the objects attributes"""
|
||||
cls.FIELDS = list(cls.FIELDS)
|
||||
# Prepare an empty dict to gather the merged/final set of fields
|
||||
fields = {}
|
||||
|
||||
# Add each supercls's fields
|
||||
for supercls in cls.mro()[1:-1]:
|
||||
if not hasattr(supercls, 'FIELDS'):
|
||||
continue
|
||||
for field in supercls.FIELDS:
|
||||
if field not in cls.FIELDS:
|
||||
cls.FIELDS.append(field)
|
||||
fields.update(supercls.FIELDS)
|
||||
|
||||
for field in cls.FIELDS:
|
||||
# Add our fields
|
||||
fields.update(cls.FIELDS)
|
||||
|
||||
# Store the results
|
||||
cls.FIELDS = fields
|
||||
|
||||
for field in cls.FIELDS.keys():
|
||||
def getter(self, name=field):
|
||||
return getattr(self, get_attrname(name), None)
|
||||
|
||||
@ -63,7 +69,7 @@ class DesignateObjectMetaclass(type):
|
||||
|
||||
@six.add_metaclass(DesignateObjectMetaclass)
|
||||
class DesignateObject(object):
|
||||
FIELDS = []
|
||||
FIELDS = {}
|
||||
|
||||
@staticmethod
|
||||
def from_primitive(primitive):
|
||||
@ -96,7 +102,7 @@ class DesignateObject(object):
|
||||
self._obj_original_values = dict()
|
||||
|
||||
for name, value in kwargs.items():
|
||||
if name in self.FIELDS:
|
||||
if name in self.FIELDS.keys():
|
||||
setattr(self, name, value)
|
||||
else:
|
||||
raise TypeError("'%s' is an invalid keyword argument" % name)
|
||||
@ -115,7 +121,7 @@ class DesignateObject(object):
|
||||
|
||||
data = {}
|
||||
|
||||
for field in self.FIELDS:
|
||||
for field in self.FIELDS.keys():
|
||||
if self.obj_attr_is_set(field):
|
||||
if isinstance(getattr(self, field), DesignateObject):
|
||||
data[field] = getattr(self, field).to_primitive()
|
||||
@ -181,7 +187,7 @@ class DesignateObject(object):
|
||||
|
||||
c_obj = self.__class__()
|
||||
|
||||
for field in self.FIELDS:
|
||||
for field in self.FIELDS.keys():
|
||||
if self.obj_attr_is_set(field):
|
||||
c_field = copy.deepcopy(getattr(self, field), memodict)
|
||||
setattr(c_obj, field, c_field)
|
||||
@ -213,10 +219,10 @@ class DictObjectMixin(object):
|
||||
setattr(self, key, value)
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self.FIELDS
|
||||
return item in self.FIELDS.keys()
|
||||
|
||||
def get(self, key, default=NotSpecifiedSentinel):
|
||||
if key not in self.FIELDS:
|
||||
if key not in self.FIELDS.keys():
|
||||
raise AttributeError("'%s' object has no attribute '%s'" % (
|
||||
self.__class__, key))
|
||||
|
||||
@ -230,12 +236,12 @@ class DictObjectMixin(object):
|
||||
setattr(self, k, v)
|
||||
|
||||
def iteritems(self):
|
||||
for field in self.FIELDS:
|
||||
for field in self.FIELDS.keys():
|
||||
if self.obj_attr_is_set(field):
|
||||
yield field, getattr(self, field)
|
||||
|
||||
def __iter__(self):
|
||||
for field in self.FIELDS:
|
||||
for field in self.FIELDS.keys():
|
||||
if self.obj_attr_is_set(field):
|
||||
yield field, getattr(self, field)
|
||||
|
||||
@ -244,7 +250,7 @@ class DictObjectMixin(object):
|
||||
|
||||
class ListObjectMixin(object):
|
||||
"""Mixin class for lists of objects"""
|
||||
FIELDS = ['objects']
|
||||
FIELDS = {'objects': {}}
|
||||
LIST_ITEM_TYPE = DesignateObject
|
||||
|
||||
@classmethod
|
||||
@ -279,7 +285,7 @@ class ListObjectMixin(object):
|
||||
|
||||
data = {}
|
||||
|
||||
for field in self.FIELDS:
|
||||
for field in self.FIELDS.keys():
|
||||
if self.obj_attr_is_set(field):
|
||||
if field == 'objects':
|
||||
data[field] = [o.to_primitive() for o in self.objects]
|
||||
@ -365,7 +371,7 @@ class PersistentObjectMixin(object):
|
||||
|
||||
This adds the fields that we use in common for all persistent objects.
|
||||
"""
|
||||
FIELDS = ['id', 'created_at', 'updated_at', 'version']
|
||||
FIELDS = {'id': {}, 'created_at': {}, 'updated_at': {}, 'version': {}}
|
||||
|
||||
|
||||
class SoftDeleteObjectMixin(object):
|
||||
@ -374,4 +380,4 @@ class SoftDeleteObjectMixin(object):
|
||||
|
||||
This adds the fields that we use in common for all soft-deleted objects.
|
||||
"""
|
||||
FIELDS = ['deleted', 'deleted_at']
|
||||
FIELDS = {'deleted': {}, 'deleted_at': {}}
|
||||
|
@ -17,7 +17,10 @@ from designate.objects import base
|
||||
|
||||
class Blacklist(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||
base.DesignateObject):
|
||||
FIELDS = ['pattern', 'description']
|
||||
FIELDS = {
|
||||
'pattern': {},
|
||||
'description': {}
|
||||
}
|
||||
|
||||
|
||||
class BlacklistList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -17,9 +17,20 @@ from designate.objects import base
|
||||
|
||||
class Domain(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
||||
base.PersistentObjectMixin, base.DesignateObject):
|
||||
FIELDS = ['tenant_id', 'name', 'email', 'ttl', 'refresh', 'retry',
|
||||
'expire', 'minimum', 'parent_domain_id', 'serial', 'description',
|
||||
'status']
|
||||
FIELDS = {
|
||||
'tenant_id': {},
|
||||
'name': {},
|
||||
'email': {},
|
||||
'ttl': {},
|
||||
'refresh': {},
|
||||
'retry': {},
|
||||
'expire': {},
|
||||
'minimum': {},
|
||||
'parent_domain_id': {},
|
||||
'serial': {},
|
||||
'description': {},
|
||||
'status': {}
|
||||
}
|
||||
|
||||
|
||||
class DomainList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -17,7 +17,11 @@ from designate.objects import base
|
||||
|
||||
class Quota(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||
base.DesignateObject):
|
||||
FIELDS = ['tenant_id', 'resource', 'hard_limit']
|
||||
FIELDS = {
|
||||
'tenant_id': {},
|
||||
'resource': {},
|
||||
'hard_limit': {}
|
||||
}
|
||||
|
||||
|
||||
class QuotaList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -19,12 +19,24 @@ class Record(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||
base.DesignateObject):
|
||||
# TODO(kiall): `hash` is an implementation detail of our SQLA driver,
|
||||
# so we should remove it.
|
||||
FIELDS = ['data', 'priority', 'domain_id', 'managed',
|
||||
'managed_resource_type', 'managed_resource_id',
|
||||
'managed_plugin_name', 'managed_plugin_type', 'hash',
|
||||
'description', 'status', 'tenant_id', 'recordset_id',
|
||||
'managed_tenant_id', 'managed_resource_region',
|
||||
'managed_extra']
|
||||
FIELDS = {
|
||||
'data': {},
|
||||
'priority': {},
|
||||
'domain_id': {},
|
||||
'managed': {},
|
||||
'managed_resource_type': {},
|
||||
'managed_resource_id': {},
|
||||
'managed_plugin_name': {},
|
||||
'managed_plugin_type': {},
|
||||
'hash': {},
|
||||
'description': {},
|
||||
'status': {},
|
||||
'tenant_id': {},
|
||||
'recordset_id': {},
|
||||
'managed_tenant_id': {},
|
||||
'managed_resource_region': {},
|
||||
'managed_extra': {}
|
||||
}
|
||||
|
||||
|
||||
class RecordList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -17,8 +17,15 @@ from designate.objects import base
|
||||
|
||||
class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||
base.DesignateObject):
|
||||
FIELDS = ['tenant_id', 'domain_id', 'name', 'type', 'ttl', 'description',
|
||||
'records']
|
||||
FIELDS = {
|
||||
'tenant_id': {},
|
||||
'domain_id': {},
|
||||
'name': {},
|
||||
'type': {},
|
||||
'ttl': {},
|
||||
'description': {},
|
||||
'records': {}
|
||||
}
|
||||
|
||||
|
||||
class RecordSetList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -20,7 +20,9 @@ class RRData_A(Record):
|
||||
A Resource Record Type
|
||||
Defined in: RFC1035
|
||||
"""
|
||||
FIELDS = ['address']
|
||||
FIELDS = {
|
||||
'address': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,7 +20,9 @@ class RRData_AAAA(Record):
|
||||
AAAA Resource Record Type
|
||||
Defined in: RFC3596
|
||||
"""
|
||||
FIELDS = ['address']
|
||||
FIELDS = {
|
||||
'address': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,7 +20,9 @@ class RRData_CNAME(Record):
|
||||
CNAME Resource Record Type
|
||||
Defined in: RFC1035
|
||||
"""
|
||||
FIELDS = ['cname']
|
||||
FIELDS = {
|
||||
'cname': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -21,7 +21,9 @@ class RRData_MX(Record):
|
||||
Defined in: RFC1035
|
||||
"""
|
||||
# priority is maintained separately for MX records and not in 'data'
|
||||
FIELDS = ['exchange']
|
||||
FIELDS = {
|
||||
'exchange': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,7 +20,9 @@ class RRData_NS(Record):
|
||||
NS Resource Record Type
|
||||
Defined in: RFC1035
|
||||
"""
|
||||
FIELDS = ['nsdname']
|
||||
FIELDS = {
|
||||
'nsdname': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,7 +20,9 @@ class RRData_PTR(Record):
|
||||
PTR Resource Record Type
|
||||
Defined in: RFC1035
|
||||
"""
|
||||
FIELDS = ['ptrdname']
|
||||
FIELDS = {
|
||||
'ptrdname': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,8 +20,15 @@ class RRData_SOA(Record):
|
||||
SOA Resource Record Type
|
||||
Defined in: RFC1035
|
||||
"""
|
||||
FIELDS = ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire',
|
||||
'minimum']
|
||||
FIELDS = {
|
||||
'mname': {},
|
||||
'rname': {},
|
||||
'serial': {},
|
||||
'refresh': {},
|
||||
'retry': {},
|
||||
'expire': {},
|
||||
'minimum': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,7 +20,9 @@ class RRData_SPF(Record):
|
||||
SPF Resource Record Type
|
||||
Defined in: RFC4408
|
||||
"""
|
||||
FIELDS = ['txt-data']
|
||||
FIELDS = {
|
||||
'txt-data': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -21,7 +21,11 @@ class RRData_SRV(Record):
|
||||
Defined in: RFC2782
|
||||
"""
|
||||
# priority is maintained separately for SRV records and not in 'data'
|
||||
FIELDS = ['weight', 'port', 'target']
|
||||
FIELDS = {
|
||||
'weight': {},
|
||||
'port': {},
|
||||
'target': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,7 +20,11 @@ class RRData_SSHFP(Record):
|
||||
SSHFP Resource Record Type
|
||||
Defined in: RFC4255
|
||||
"""
|
||||
FIELDS = ['algorithm', 'fp_type', 'fingerprint']
|
||||
FIELDS = {
|
||||
'algorithm': {},
|
||||
'fp_type': {},
|
||||
'fingerprint': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -20,7 +20,9 @@ class RRData_TXT(Record):
|
||||
TXT Resource Record Type
|
||||
Defined in: RFC1035
|
||||
"""
|
||||
FIELDS = ['txt-data']
|
||||
FIELDS = {
|
||||
'txt-data': {}
|
||||
}
|
||||
|
||||
# The record type is defined in the RFC. This will be used when the record
|
||||
# is sent by mini-dns.
|
||||
|
@ -17,7 +17,9 @@ from designate.objects import base
|
||||
|
||||
class Server(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||
base.DesignateObject):
|
||||
FIELDS = ['name']
|
||||
FIELDS = {
|
||||
'name': {}
|
||||
}
|
||||
|
||||
|
||||
class ServerList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -16,7 +16,11 @@ from designate.objects import base
|
||||
|
||||
|
||||
class Tenant(base.DictObjectMixin, base.DesignateObject):
|
||||
FIELDS = ['id', 'domain_count', 'domains']
|
||||
FIELDS = {
|
||||
'id': {},
|
||||
'domain_count': {},
|
||||
'domains': {}
|
||||
}
|
||||
|
||||
|
||||
class TenantList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -17,7 +17,10 @@ from designate.objects import base
|
||||
|
||||
class Tld(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||
base.DesignateObject):
|
||||
FIELDS = ['name', 'description']
|
||||
FIELDS = {
|
||||
'name': {},
|
||||
'description': {}
|
||||
}
|
||||
|
||||
|
||||
class TldList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -17,7 +17,11 @@ from designate.objects import base
|
||||
|
||||
class TsigKey(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||
base.DesignateObject):
|
||||
FIELDS = ['name', 'algorithm', 'secret']
|
||||
FIELDS = {
|
||||
'name': {},
|
||||
'algorithm': {},
|
||||
'secret': {}
|
||||
}
|
||||
|
||||
|
||||
class TsigKeyList(base.ListObjectMixin, base.DesignateObject):
|
||||
|
@ -46,7 +46,7 @@ cfg.CONF.register_opts(options.database_opts, group='storage:sqlalchemy')
|
||||
def _set_object_from_model(obj, model, **extra):
|
||||
"""Update a DesignateObject with the values from a SQLA Model"""
|
||||
|
||||
for fieldname in obj.FIELDS:
|
||||
for fieldname in obj.FIELDS.keys():
|
||||
if hasattr(model, fieldname):
|
||||
if fieldname in extra.keys():
|
||||
obj[fieldname] = extra[fieldname]
|
||||
|
@ -27,7 +27,11 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
class TestObject(objects.DesignateObject):
|
||||
PATH = 'designate.tests.test_objects.test_base.TestObject'
|
||||
FIELDS = ['id', 'name', 'nested']
|
||||
FIELDS = {
|
||||
'id': {},
|
||||
'name': {},
|
||||
'nested': {},
|
||||
}
|
||||
|
||||
|
||||
class TestObjectDict(objects.DictObjectMixin, TestObject):
|
||||
|
Loading…
Reference in New Issue
Block a user