From fce8049cb6256b42c8bf617ee6fc8c1a0492c592 Mon Sep 17 00:00:00 2001 From: Graham Hayes Date: Fri, 13 Mar 2015 19:47:38 +0000 Subject: [PATCH] Move the DesignateAdapter to return non-wrapped objects Change-Id: Iaab9514fc5f443cc6dd09c10f928c042b9dbcfb7 Partially-Implements: blueprint validation-cleanup --- designate/objects/adapters/api_v1/base.py | 36 ---------------- designate/objects/adapters/api_v2/base.py | 39 ++++++------------ designate/objects/adapters/base.py | 41 ++++++++++++++----- designate/tests/test_objects/test_adapters.py | 23 ++--------- 4 files changed, 46 insertions(+), 93 deletions(-) diff --git a/designate/objects/adapters/api_v1/base.py b/designate/objects/adapters/api_v1/base.py index 09c3b96f..16488674 100644 --- a/designate/objects/adapters/api_v1/base.py +++ b/designate/objects/adapters/api_v1/base.py @@ -21,39 +21,3 @@ LOG = logging.getLogger(__name__) class APIv1Adapter(base.DesignateAdapter): ADAPTER_FORMAT = 'API_v1' - - ##################### - # Rendering methods # - ##################### - - @classmethod - def render(cls, object, *args, **kwargs): - return super(APIv1Adapter, cls).render( - cls.ADAPTER_FORMAT, object, *args, **kwargs) - - @classmethod - def _render_list(cls, list_object, *args, **kwargs): - inner = cls._render_inner_list(list_object, *args, **kwargs) - - return {cls.MODIFICATIONS['options']['collection_name']: inner} - - @classmethod - def _render_object(cls, object, *args, **kwargs): - return cls._render_inner_object(object, *args, **kwargs) - - ##################### - # Parsing methods # - ##################### - - @classmethod - def parse(cls, values, output_object, *args, **kwargs): - return super(APIv1Adapter, cls).parse( - cls.ADAPTER_FORMAT, values, output_object, *args, **kwargs) - - @classmethod - def _parse_list(cls, values, output_object, *args, **kwargs): - return cls._parse_inner_list(values, output_object, *args, **kwargs) - - @classmethod - def _parse_object(cls, values, output_object, *args, **kwargs): - return cls._parse_inner_object(values, output_object, *args, **kwargs) diff --git a/designate/objects/adapters/api_v2/base.py b/designate/objects/adapters/api_v2/base.py index 988171a2..623ad2b5 100644 --- a/designate/objects/adapters/api_v2/base.py +++ b/designate/objects/adapters/api_v2/base.py @@ -34,37 +34,32 @@ class APIv2Adapter(base.DesignateAdapter): # Rendering methods # ##################### - @classmethod - def render(cls, object, *args, **kwargs): - return super(APIv2Adapter, cls).render( - cls.ADAPTER_FORMAT, object, *args, **kwargs) - @classmethod def _render_list(cls, list_object, *args, **kwargs): - inner = cls._render_inner_list(list_object, *args, **kwargs) - outer = {} + r_list = super(APIv2Adapter, cls)._render_list( + list_object, *args, **kwargs) - if cls.MODIFICATIONS['options'].get('links', True): - outer['links'] = cls._get_collection_links( + if cls.MODIFICATIONS['options'].get('links', True)\ + and 'request' in kwargs: + r_list['links'] = cls._get_collection_links( list_object, kwargs['request']) # Check if we should include metadata if isinstance(list_object, obj_base.PagedListObjectMixin): metadata = {} metadata['total_count'] = list_object.total_count - outer['metadata'] = metadata + r_list['metadata'] = metadata - outer[cls.MODIFICATIONS['options']['collection_name']] = inner - - return outer + return r_list @classmethod def _render_object(cls, object, *args, **kwargs): - inner = cls._render_inner_object(object, *args, **kwargs) + obj = super(APIv2Adapter, cls)._render_object(object, *args, **kwargs) - if cls.MODIFICATIONS['options'].get('links', True): - inner['links'] = cls._get_resource_links(object, kwargs['request']) + if cls.MODIFICATIONS['options'].get('links', True)\ + and 'request' in kwargs: + obj['links'] = cls._get_resource_links(object, kwargs['request']) - return {cls.MODIFICATIONS['options']['resource_name']: inner} + return obj ##################### # Parsing methods # @@ -75,16 +70,6 @@ class APIv2Adapter(base.DesignateAdapter): return super(APIv2Adapter, cls).parse( cls.ADAPTER_FORMAT, values, output_object, *args, **kwargs) - @classmethod - def _parse_list(cls, values, output_object, *args, **kwargs): - - return cls._parse_inner_list(values, output_object, *args, **kwargs) - - @classmethod - def _parse_object(cls, values, output_object, *args, **kwargs): - inner = values[cls.MODIFICATIONS['options']['resource_name']] - return cls._parse_inner_object(inner, output_object, *args, **kwargs) - ##################### # Link methods # ##################### diff --git a/designate/objects/adapters/base.py b/designate/objects/adapters/base.py index e13d893b..60692377 100644 --- a/designate/objects/adapters/base.py +++ b/designate/objects/adapters/base.py @@ -57,7 +57,10 @@ class DesignateAdapter(object): @classmethod def get_object_adapter(cls, format_, object): - key = '%s:%s' % (format_, object.obj_name()) + if isinstance(object, objects.DesignateObject): + key = '%s:%s' % (format_, object.obj_name()) + else: + key = '%s:%s' % (format_, object) try: return cls._adapter_classes[key] except KeyError as e: @@ -85,7 +88,7 @@ class DesignateAdapter(object): format_, object)._render_object(object, *args, **kwargs) @classmethod - def _render_inner_object(cls, object, *args, **kwargs): + def _render_object(cls, object, *args, **kwargs): # The dict we will return to be rendered to JSON / output format r_obj = {} # Loop over all fields that are supposed to be output @@ -110,7 +113,7 @@ class DesignateAdapter(object): r_obj[key] = cls.get_object_adapter( cls.ADAPTER_FORMAT, object.FIELDS[obj_key].get('relation_cls')).render( - obj, *args, **kwargs) + cls.ADAPTER_FORMAT, obj, *args, **kwargs) else: # Just attach the damn item if there is no weird edge cases r_obj[key] = obj @@ -118,7 +121,7 @@ class DesignateAdapter(object): return r_obj @classmethod - def _render_inner_list(cls, list_object, *args, **kwargs): + def _render_list(cls, list_object, *args, **kwargs): # The list we will return to be rendered to JSON / output format r_list = [] # iterate and convert each DesignateObject in the list, and append to @@ -126,8 +129,8 @@ class DesignateAdapter(object): for object in list_object: r_list.append(cls.get_object_adapter( cls.ADAPTER_FORMAT, - object.obj_name()).render(object, *args, **kwargs)) - return r_list + object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs)) + return {cls.MODIFICATIONS['options']['collection_name']: r_list} ##################### # Parsing methods # @@ -140,17 +143,17 @@ class DesignateAdapter(object): # type_ = 'list' return cls.get_object_adapter( format_, - output_object.obj_name())._parse_list( + output_object)._parse_list( values, output_object, *args, **kwargs) else: # type_ = 'object' return cls.get_object_adapter( format_, - output_object.obj_name())._parse_object( + output_object)._parse_object( values, output_object, *args, **kwargs) @classmethod - def _parse_inner_object(cls, values, output_object, *args, **kwargs): + def _parse_object(cls, values, output_object, *args, **kwargs): error_keys = [] for key, value in values.iteritems(): @@ -163,6 +166,24 @@ class DesignateAdapter(object): if cls.MODIFICATIONS['fields'][key].get('rename', False): obj_key = cls.MODIFICATIONS['fields'][key].get('rename') + ############################################################## + # TODO(graham): Remove this section of code when validation # + # is moved into DesignateObjects properly # + ############################################################## + + # Check if the field should be allowed change after it is initially + # set (eg domain name) + if cls.MODIFICATIONS['fields'][key].get('idempotent', False): + if getattr(output_object, obj_key, False) and \ + getattr(output_object, obj_key) != value: + error_keys.append(key) + break + # Is this field a read only field + elif cls.MODIFICATIONS['fields'][key].get('read_only', True) and \ + getattr(output_object, obj_key) != value: + error_keys.append(key) + break + # Check if the key is a nested object if output_object.FIELDS.get(obj_key, {}).get('relation', False): # Get the right class name @@ -196,5 +217,5 @@ class DesignateAdapter(object): return output_object @classmethod - def _parse_inner_list(cls, values, output_object, *args, **kwargs): + def _parse_list(cls, values, output_object, *args, **kwargs): raise exceptions.NotImplemented('List adaption not implemented') diff --git a/designate/tests/test_objects/test_adapters.py b/designate/tests/test_objects/test_adapters.py index 8b906010..def50a0f 100644 --- a/designate/tests/test_objects/test_adapters.py +++ b/designate/tests/test_objects/test_adapters.py @@ -32,28 +32,11 @@ class DesignateTestAdapter(adapters.DesignateAdapter): 'options': {} } - @classmethod - def render(cls, object, *args, **kwargs): - return super(DesignateTestAdapter, cls).render( - cls.ADAPTER_FORMAT, object, *args, **kwargs) - - @classmethod - def _render_list(cls, list_object, *args, **kwargs): - inner = cls._render_inner_list(list_object, *args, **kwargs) - - return inner - - @classmethod - def _render_object(cls, object, *args, **kwargs): - inner = cls._render_inner_object(object, *args, **kwargs) - - return inner - class DesignateAdapterTest(tests.TestCase): def test_get_object_adapter(self): adapters.DesignateAdapter.get_object_adapter( - 'TEST_API', objects.DesignateObject) + 'TEST_API', objects.DesignateObject()) - def test_get_object_render(self): - adapters.DesignateAdapter.render('TEST_API', objects.DesignateObject) + def test_object_render(self): + adapters.DesignateAdapter.render('TEST_API', objects.DesignateObject())