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