Browse Source
Allow transformation service to handle serialization and deserialization
merge-requests/1/head
Allow transformation service to handle serialization and deserialization
merge-requests/1/head
Drew Short
6 years ago
6 changed files with 227 additions and 66 deletions
-
54server/atheneum/service/serialization_service.py
-
100server/atheneum/service/transformation_service.py
-
52server/atheneum/service/user_service.py
-
63server/atheneum/service/user_token_service.py
-
2server/atheneum/utility/json_utility.py
-
22server/tests/service/test_transformation_service.py
@ -1,54 +0,0 @@ |
|||||
"""Handle Model Serialization.""" |
|
||||
from typing import Dict, Callable, Any, List, Optional, Type |
|
||||
|
|
||||
from atheneum import errors |
|
||||
from atheneum.db import db |
|
||||
|
|
||||
|
|
||||
class BaseSerializer: # pylint: disable=too-few-public-methods |
|
||||
"""Base Model serializer.""" |
|
||||
|
|
||||
def __init__(self, model: Type[db.Model]) -> None: |
|
||||
"""Initialize the base serializer.""" |
|
||||
self._fields: Dict[str, Callable[[db.Model], Any]] = {} |
|
||||
self.model = model |
|
||||
|
|
||||
def serialize(self, options: Optional[List[str]]) -> Any: |
|
||||
"""Convert Model field and factories to dicts.""" |
|
||||
field_factories = self._serializers() |
|
||||
if not options: |
|
||||
options = list(field_factories.keys()) |
|
||||
ret = {} |
|
||||
for key in options: |
|
||||
if key not in field_factories: |
|
||||
raise errors.ValidationError( |
|
||||
'Invalid key: %r. Valid keys: %r.' % ( |
|
||||
key, list(sorted(field_factories.keys())))) |
|
||||
factory = field_factories[key] |
|
||||
val = factory() |
|
||||
if val is not None: |
|
||||
ret[key] = val |
|
||||
return ret |
|
||||
|
|
||||
def _serializers(self) -> Dict[str, Callable[[], Any]]: |
|
||||
"""Field definitions.""" |
|
||||
raise NotImplementedError() |
|
||||
|
|
||||
|
|
||||
_model_serializers: Dict[str, Type[BaseSerializer]] = {} |
|
||||
|
|
||||
|
|
||||
def register_serializer( |
|
||||
model_name: str, model_serializer: Type[BaseSerializer]) -> None: |
|
||||
"""Add a model to the serializer mapping.""" |
|
||||
_model_serializers[model_name] = model_serializer |
|
||||
|
|
||||
|
|
||||
def serialize_model(model_obj: db.Model) -> Any: |
|
||||
"""Lookup a Model and hand off to the serializer.""" |
|
||||
try: |
|
||||
return _model_serializers[ |
|
||||
type(model_obj).__name__](model_obj).serialize(None) |
|
||||
except KeyError: |
|
||||
raise NotImplementedError( |
|
||||
'{} has no registered serializers'.format(model_obj.__name__)) |
|
@ -0,0 +1,100 @@ |
|||||
|
"""Handle Model Serialization.""" |
||||
|
import logging |
||||
|
from typing import Dict, Callable, Any, List, Optional, Type |
||||
|
|
||||
|
from atheneum import errors |
||||
|
from atheneum.db import db |
||||
|
|
||||
|
LOGGER = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class BaseTransformer: |
||||
|
"""Base Model serializer.""" |
||||
|
|
||||
|
type: Type[db.Model] |
||||
|
|
||||
|
def __init__(self, model: Type[db.Model]) -> None: |
||||
|
"""Initialize the base serializer.""" |
||||
|
self._fields: Dict[str, Callable[[db.Model], Any]] = {} |
||||
|
self.model = model |
||||
|
|
||||
|
def serialize(self, options: Optional[List[str]]) -> Any: |
||||
|
"""Convert Model field and factories to dicts.""" |
||||
|
field_factories = self._serializers() |
||||
|
if not options: |
||||
|
options = list(field_factories.keys()) |
||||
|
ret = {} |
||||
|
for key in options: |
||||
|
if key not in field_factories: |
||||
|
raise errors.ValidationError( |
||||
|
'Invalid key: %r. Valid keys: %r.' % ( |
||||
|
key, list(sorted(field_factories.keys())))) |
||||
|
factory = field_factories[key] |
||||
|
val = factory() |
||||
|
if val is not None: |
||||
|
ret[key] = val |
||||
|
return ret |
||||
|
|
||||
|
def deserialize(self, |
||||
|
json_model: dict, |
||||
|
options: Optional[List[str]]) -> Any: |
||||
|
"""Convert dict to Model.""" |
||||
|
field_factories = self._deserializers() |
||||
|
if not options: |
||||
|
options = list(field_factories.keys()) |
||||
|
for key in options: |
||||
|
if key not in field_factories: |
||||
|
raise errors.ValidationError( |
||||
|
'Invalid key: %r. Valid keys: %r.' % ( |
||||
|
key, list(sorted(field_factories.keys())))) |
||||
|
factory = field_factories[key] |
||||
|
try: |
||||
|
value = json_model[key] |
||||
|
if value is not None: |
||||
|
factory(self.model, value) |
||||
|
except KeyError as key_error: |
||||
|
LOGGER.error('Unable to transform field: %s %s', key, key_error) |
||||
|
return self.model |
||||
|
|
||||
|
def _serializers(self) -> Dict[str, Callable[[], Any]]: |
||||
|
"""Field definitions.""" |
||||
|
raise NotImplementedError() |
||||
|
|
||||
|
def _deserializers( |
||||
|
self) -> Dict[str, Callable[[db.Model, Any], None]]: |
||||
|
"""Field definitions.""" |
||||
|
raise NotImplementedError() |
||||
|
|
||||
|
|
||||
|
_model_transformers: Dict[str, Type[BaseTransformer]] = {} |
||||
|
|
||||
|
|
||||
|
def register_transformer( |
||||
|
model_name: str, model_serializer: Type[BaseTransformer]) -> None: |
||||
|
"""Add a model to the serializer mapping.""" |
||||
|
_model_transformers[model_name] = model_serializer |
||||
|
|
||||
|
|
||||
|
def serialize_model(model_obj: db.Model, |
||||
|
options: Optional[List[str]] = None) -> Any: |
||||
|
"""Lookup a Model and hand off to the serializer.""" |
||||
|
try: |
||||
|
return _model_transformers[ |
||||
|
type(model_obj).__name__](model_obj).serialize(options) |
||||
|
except KeyError: |
||||
|
raise NotImplementedError( |
||||
|
'{} has no registered serializers'.format(model_obj.__name__)) |
||||
|
|
||||
|
|
||||
|
def deserialize_model( |
||||
|
model_type: str, |
||||
|
json_model_object: dict, |
||||
|
options: Optional[List[str]] = None) -> Type[db.Model]: |
||||
|
"""Lookup a Model and hand it off to the deserializer.""" |
||||
|
try: |
||||
|
transformer = _model_transformers[model_type] |
||||
|
return transformer( |
||||
|
transformer.type()).deserialize(json_model_object, options) |
||||
|
except KeyError: |
||||
|
raise NotImplementedError( |
||||
|
'{} has no registered serializers'.format(model_type)) |
@ -0,0 +1,22 @@ |
|||||
|
from atheneum.model import UserToken |
||||
|
from atheneum.service.transformation_service import ( |
||||
|
serialize_model, |
||||
|
deserialize_model |
||||
|
) |
||||
|
|
||||
|
|
||||
|
def test_serialize_model(): |
||||
|
user_token = UserToken() |
||||
|
user_token.token = 'test' |
||||
|
result = serialize_model(user_token) |
||||
|
assert result is not None |
||||
|
assert result['token'] == 'test' |
||||
|
|
||||
|
|
||||
|
def test_deserialize_model(): |
||||
|
user_token_json = { |
||||
|
'token': 'test' |
||||
|
} |
||||
|
result = deserialize_model('UserToken', user_token_json) |
||||
|
assert result is not None |
||||
|
assert result.token == 'test' |
Write
Preview
Loading…
Cancel
Save
Reference in new issue