-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from hgromer/dev
[0.4.0] delegates are now functions to avoid creating a ton of classes
- Loading branch information
Showing
8 changed files
with
97 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
__version__ = '0.3.3' | ||
__version__ = '0.4.0' | ||
__all__ = ['Marshal', 'utils', 'arg_delegates', 'errors'] | ||
|
||
from pymarshaler.marshal import Marshal | ||
from pymarshaler import utils | ||
from pymarshaler import arg_delegates | ||
from pymarshaler import errors | ||
from pymarshaler import utils | ||
from pymarshaler.marshal import Marshal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,130 +1,66 @@ | ||
import datetime | ||
import typing | ||
|
||
import dateutil.parser as parser | ||
|
||
from pymarshaler.errors import UnknownFieldError | ||
from pymarshaler.utils import get_init_params | ||
|
||
|
||
class ArgBuilderDelegate: | ||
|
||
def __init__(self, cls): | ||
self.cls = cls | ||
|
||
def resolve(self, data): | ||
raise NotImplementedError(f'{ArgBuilderDelegate.__name__} has no implementation of resolve') | ||
|
||
|
||
class FunctionalArgBuilderDelegate(ArgBuilderDelegate): | ||
|
||
def __init__(self, cls, func): | ||
super().__init__(cls) | ||
self.func = func | ||
|
||
def resolve(self, data): | ||
raise NotImplementedError(f'{FunctionalArgBuilderDelegate.__name__} has no implementation of resolve') | ||
|
||
|
||
class EnumArgBuilderDelegate(ArgBuilderDelegate): | ||
|
||
def resolve(self, data): | ||
for v in self.cls.__members__.values(): | ||
if v.value == data: | ||
return v | ||
raise UnknownFieldError(f'Invalid value {data} for enum {self.cls.__name__}') | ||
|
||
|
||
class ListArgBuilderDelegate(FunctionalArgBuilderDelegate): | ||
|
||
def __init__(self, cls, func): | ||
super().__init__(cls, func) | ||
|
||
def resolve(self, data: typing.List): | ||
inner_type = self.cls.__args__[0] | ||
return [self.func(inner_type, x) for x in data] | ||
|
||
|
||
class SetArgBuilderDelegate(FunctionalArgBuilderDelegate): | ||
|
||
def __init__(self, cls, func): | ||
super().__init__(cls, func) | ||
|
||
def resolve(self, data: typing.Set): | ||
inner_type = self.cls.__args__[0] | ||
return {self.func(inner_type, x) for x in data} | ||
|
||
|
||
class TupleArgBuilderDelegate(FunctionalArgBuilderDelegate): | ||
|
||
def __init__(self, cls, func): | ||
super().__init__(cls, func) | ||
|
||
def resolve(self, data: typing.Tuple): | ||
inner_type = self.cls.__args__[0] | ||
return (self.func(inner_type, x) for x in data) | ||
|
||
|
||
class DictArgBuilderDelegate(FunctionalArgBuilderDelegate): | ||
|
||
def __init__(self, cls, func): | ||
super().__init__(cls, func) | ||
def enum_delegate(cls, data, ignore_func): | ||
for v in cls.__members__.values(): | ||
if v.value == data: | ||
return v | ||
raise UnknownFieldError(f'Invalid value {data} for enum {cls.__name__}') | ||
|
||
def resolve(self, data: dict): | ||
key_type = self.cls.__args__[0] | ||
value_type = self.cls.__args__[1] | ||
return { | ||
self.func(key_type, key): self.func(value_type, value) for key, value in data.items() | ||
} | ||
|
||
def list_delegate(cls, data, func): | ||
inner_type = cls.__args__[0] | ||
return [func(inner_type, x) for x in data] | ||
|
||
class BuiltinArgBuilderDelegate(ArgBuilderDelegate): | ||
|
||
def __init__(self, cls): | ||
super().__init__(cls) | ||
def set_builder_delegate(cls, data, func): | ||
inner_type = cls.__args__[0] | ||
return {func(inner_type, x) for x in data} | ||
|
||
def resolve(self, data): | ||
if data is None: | ||
return None | ||
else: | ||
return self.cls(data) | ||
|
||
def tuple_delegate(cls, data, func): | ||
inner_type = cls.__args__[0] | ||
return (func(inner_type, x) for x in data) | ||
|
||
class DateTimeArgBuilderDelegate(ArgBuilderDelegate): | ||
|
||
def __init__(self): | ||
super().__init__(datetime.datetime) | ||
def dict_delegate(cls, data, func): | ||
key_type = cls.__args__[0] | ||
value_type = cls.__args__[1] | ||
return { | ||
func(key_type, key): func(value_type, value) for key, value in data.items() | ||
} | ||
|
||
def resolve(self, data): | ||
return parser.parse(data) | ||
|
||
def builtin_delegate(cls, data, ignore_func): | ||
if data is None: | ||
return None | ||
else: | ||
return cls(data) | ||
|
||
class UserDefinedArgBuilderDelegate(FunctionalArgBuilderDelegate): | ||
|
||
def __init__(self, cls, func, ignore_unknown_fields: bool, walk_unknown_fields: bool): | ||
super().__init__(cls, func) | ||
self.ignore_unknown_fields = ignore_unknown_fields | ||
self.walk_unknown_fields = walk_unknown_fields | ||
def datetime_delegate(cls_ignore, data, ignore_func=None): | ||
return parser.parse(data) | ||
|
||
def resolve(self, data: dict): | ||
return self._resolve(self.cls, data) | ||
|
||
def _resolve(self, cls, data: dict): | ||
args = {} | ||
unsatisfied = get_init_params(cls) | ||
for key, value in data.items(): | ||
if key in unsatisfied: | ||
param_type = unsatisfied[key] | ||
args[key] = self.func(param_type, value) | ||
elif not self.ignore_unknown_fields: | ||
raise UnknownFieldError(f'Found unknown field ({key}: {value}). ' | ||
'If you would like to skip unknown fields ' | ||
'create a Marshal object who can skip ignore_unknown_fields') | ||
elif self.walk_unknown_fields: | ||
if isinstance(value, dict): | ||
args.update(self._resolve(cls, value)) | ||
elif isinstance(value, (list, set, tuple)): | ||
for x in value: | ||
if isinstance(x, dict): | ||
args.update(self._resolve(cls, x)) | ||
return args | ||
def user_defined_delegate(cls, data, func, ignore_unknown_fields: bool, walk_unknown_fields: bool): | ||
args = {} | ||
unsatisfied = get_init_params(cls) | ||
for key, value in data.items(): | ||
if key in unsatisfied: | ||
param_type = unsatisfied[key] | ||
args[key] = func(param_type, value) | ||
elif not ignore_unknown_fields: | ||
raise UnknownFieldError(f'Found unknown field ({key}: {value}). ' | ||
'If you would like to skip unknown fields ' | ||
'create a Marshal object who can skip ignore_unknown_fields') | ||
elif walk_unknown_fields: | ||
if isinstance(value, dict): | ||
args.update(user_defined_delegate(cls, value, func, ignore_unknown_fields, walk_unknown_fields)) | ||
elif isinstance(value, (list, set, tuple)): | ||
for x in value: | ||
if isinstance(x, dict): | ||
args.update(user_defined_delegate(cls, x, func, ignore_unknown_fields, walk_unknown_fields)) | ||
return args |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ | |
|
||
setuptools.setup( | ||
name="pymarshaler", | ||
version='0.3.3', | ||
version='0.4.0', | ||
author="Hernan Romer", | ||
author_email="[email protected]", | ||
description="Package to marshal and unmarshal python objects", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.