File size: 4,646 Bytes
079c32c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
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))
|