File size: 2,887 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
import re
from functools import wraps
from itertools import islice
from typing import Callable, Union, Pattern

from .base import Loader, ILoaderClass

STRING_PROCESSOR = Callable[[str], str]


def enum(*items, case_sensitive: bool = True) -> ILoaderClass:
    """
    Overview:
        Create an enum loader.
    Arguments:
        - items (:obj:`Iterable[str]`): The items.
        - case_sensitive (:obj:`bool`): Whether case sensitive.
    """

    def _case_sensitive(func: STRING_PROCESSOR) -> STRING_PROCESSOR:
        if case_sensitive:
            return func
        else:

            @wraps(func)
            def _new_func(value: str) -> str:
                return func(value).lower()

            return _new_func

    @_case_sensitive
    def _item_process(value):
        return str(value)

    item_set = set([_item_process(item) for item in items])

    def _load(value: str):
        real_value = _item_process(value)
        if real_value not in item_set:
            raise ValueError('unknown enum value {value}'.format(value=repr(value)))

        return real_value

    return Loader(_load)


def _to_regexp(regexp) -> Pattern:
    """
    Overview:
        Convert regexp to re.Pattern.
    Arguments:
        - regexp (:obj:`Union[str, re.Pattern]`): The regexp.
    """

    if isinstance(regexp, Pattern):
        return regexp
    elif isinstance(regexp, str):
        return re.compile(regexp)
    else:
        raise TypeError(
            'Regexp should be either str or re.Pattern but {actual} found.'.format(actual=repr(type(regexp).__name__))
        )


def rematch(regexp: Union[str, Pattern]) -> ILoaderClass:
    """
    Overview:
        Create a rematch loader.
    Arguments:
        - regexp (:obj:`Union[str, re.Pattern]`): The regexp.
    """

    regexp = _to_regexp(regexp)

    def _load(value: str):
        if not regexp.fullmatch(value):
            raise ValueError(
                'fully match with regexp {pattern} expected but {actual} found'.format(
                    pattern=repr(regexp.pattern),
                    actual=repr(value),
                )
            )

        return value

    return Loader(_load)


def regrep(regexp: Union[str, Pattern], group: int = 0) -> ILoaderClass:
    """
    Overview:
        Create a regrep loader.
    Arguments:
        - regexp (:obj:`Union[str, re.Pattern]`): The regexp.
        - group (:obj:`int`): The group.
    """

    regexp = _to_regexp(regexp)

    def _load(value: str):
        results = list(islice(regexp.finditer(value), 1))
        if results:
            return results[0][group]
        else:
            raise ValueError(
                'fully match with regexp {pattern} expected but {actual} found'.format(
                    pattern=repr(regexp.pattern),
                    actual=repr(value),
                )
            )

    return Loader(_load)