Spaces:
Sleeping
Sleeping
from typing import List, Tuple, Callable, Any | |
from .base import ILoaderClass, Loader, CAPTURE_EXCEPTIONS | |
from .exception import CompositeStructureError | |
from .types import method | |
from .utils import raw | |
MAPPING_ERROR_ITEM = Tuple[str, Exception] | |
MAPPING_ERRORS = List[MAPPING_ERROR_ITEM] | |
class MappingError(CompositeStructureError): | |
""" | |
Overview: | |
Mapping error. | |
Interfaces: | |
``__init__``, ``errors`` | |
""" | |
def __init__(self, key_errors: MAPPING_ERRORS, value_errors: MAPPING_ERRORS): | |
""" | |
Overview: | |
Initialize the MappingError. | |
Arguments: | |
- key_errors (:obj:`MAPPING_ERRORS`): The key errors. | |
- value_errors (:obj:`MAPPING_ERRORS`): The value errors. | |
""" | |
self.__key_errors = list(key_errors or []) | |
self.__value_errors = list(value_errors or []) | |
self.__errors = self.__key_errors + self.__value_errors | |
def key_errors(self) -> MAPPING_ERRORS: | |
""" | |
Overview: | |
Get the key errors. | |
""" | |
return self.__key_errors | |
def value_errors(self) -> MAPPING_ERRORS: | |
""" | |
Overview: | |
Get the value errors. | |
""" | |
return self.__value_errors | |
def errors(self) -> MAPPING_ERRORS: | |
""" | |
Overview: | |
Get the errors. | |
""" | |
return self.__errors | |
def mapping(key_loader, value_loader, type_back: bool = True) -> ILoaderClass: | |
""" | |
Overview: | |
Create a mapping loader. | |
Arguments: | |
- key_loader (:obj:`ILoaderClass`): The key loader. | |
- value_loader (:obj:`ILoaderClass`): The value loader. | |
- type_back (:obj:`bool`): Whether to convert the type back. | |
""" | |
key_loader = Loader(key_loader) | |
value_loader = Loader(value_loader) | |
def _load(value): | |
_key_errors = [] | |
_value_errors = [] | |
_result = {} | |
for key_, value_ in value.items(): | |
key_error, value_error = None, None | |
key_result, value_result = None, None | |
try: | |
key_result = key_loader(key_) | |
except CAPTURE_EXCEPTIONS as err: | |
key_error = err | |
try: | |
value_result = value_loader(value_) | |
except CAPTURE_EXCEPTIONS as err: | |
value_error = err | |
if not key_error and not value_error: | |
_result[key_result] = value_result | |
else: | |
if key_error: | |
_key_errors.append((key_, key_error)) | |
if value_error: | |
_value_errors.append((key_, value_error)) | |
if not _key_errors and not _value_errors: | |
if type_back: | |
_result = type(value)(_result) | |
return _result | |
else: | |
raise MappingError(_key_errors, _value_errors) | |
return method('items') & Loader(_load) | |
def mpfilter(check: Callable[[Any, Any], bool], type_back: bool = True) -> ILoaderClass: | |
""" | |
Overview: | |
Create a mapping filter loader. | |
Arguments: | |
- check (:obj:`Callable[[Any, Any], bool]`): The check function. | |
- type_back (:obj:`bool`): Whether to convert the type back. | |
""" | |
def _load(value): | |
_result = {key_: value_ for key_, value_ in value.items() if check(key_, value_)} | |
if type_back: | |
_result = type(value)(_result) | |
return _result | |
return method('items') & Loader(_load) | |
def mpkeys() -> ILoaderClass: | |
""" | |
Overview: | |
Create a mapping keys loader. | |
""" | |
return method('items') & method('keys') & Loader(lambda v: set(v.keys())) | |
def mpvalues() -> ILoaderClass: | |
""" | |
Overview: | |
Create a mapping values loader. | |
""" | |
return method('items') & method('values') & Loader(lambda v: set(v.values())) | |
def mpitems() -> ILoaderClass: | |
""" | |
Overview: | |
Create a mapping items loader. | |
""" | |
return method('items') & Loader(lambda v: set([(key, value) for key, value in v.items()])) | |
_INDEX_PRECHECK = method('__getitem__') | |
def item(key) -> ILoaderClass: | |
""" | |
Overview: | |
Create a item loader. | |
Arguments: | |
- key (:obj:`Any`): The key. | |
""" | |
return _INDEX_PRECHECK & Loader( | |
(lambda v: key in v.keys(), lambda v: v[key], KeyError('key {key} not found'.format(key=repr(key)))) | |
) | |
def item_or(key, default) -> ILoaderClass: | |
""" | |
Overview: | |
Create a item or loader. | |
Arguments: | |
- key (:obj:`Any`): The key. | |
- default (:obj:`Any`): The default value. | |
""" | |
return _INDEX_PRECHECK & (item(key) | raw(default)) | |