File: datatype.py

package info (click to toggle)
python-setoptconf 0.3.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 252 kB
  • sloc: python: 1,427; sh: 7; makefile: 5
file content (135 lines) | stat: -rw-r--r-- 3,327 bytes parent folder | download | duplicates (3)
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
from .exception import DataTypeError


__all__ = (
    'DataType',
    'String',
    'Integer',
    'Float',
    'Boolean',
    'List',
    'Choice',
)


class DataType(object):
    def sanitize(self, value):
        raise NotImplementedError()

    def is_valid(self, value):
        try:
            self.sanitize(value)
        except DataTypeError:
            return False
        else:
            return True


class String(DataType):
    def sanitize(self, value):
        if value is not None:
            value = str(value)
        return value


class Integer(DataType):
    def sanitize(self, value):
        if value is not None:
            try:
                value = int(value)
            except:
                raise DataTypeError('"%s" is not valid Integer' % value)
        return value


class Float(DataType):
    def sanitize(self, value):
        if value is not None:
            try:
                value = float(value)
            except:
                raise DataTypeError('"%s" is not valid Float' % value)
        return value


class Boolean(DataType):
    TRUTHY_STRINGS = ('Y', 'YES', 'T', 'TRUE', 'ON', '1')
    FALSY_STRINGS = ('', 'N', 'NO', 'F', 'FALSE', 'OFF', '0')

    def sanitize(self, value):
        if value is None or isinstance(value, bool):
            return value

        if isinstance(value, int):
            return True if value else False

        if isinstance(value, str) and value:
            value = value.strip().upper()
            if value in self.TRUTHY_STRINGS:
                return True
            elif value in self.FALSY_STRINGS:
                return False
            else:
                raise DataTypeError(
                    'Could not coerce "%s" to a Boolean' % (
                        value,
                    )
                )

        return True if value else False


class List(DataType):
    def __init__(self, subtype):
        super(List, self).__init__()
        if isinstance(subtype, DataType):
            self.subtype = subtype
        elif isinstance(subtype, type) and issubclass(subtype, DataType):
            self.subtype = subtype()
        else:
            raise TypeError('subtype must be a DataType')

    def sanitize(self, value):
        if value is None:
            return value

        if not isinstance(value, (list, tuple)):
            value = [value]

        value = [
            self.subtype.sanitize(v)
            for v in value
        ]

        return value


class Choice(DataType):
    def __init__(self, choices, subtype=None):
        super(Choice, self).__init__()

        subtype = subtype or String()
        if isinstance(subtype, DataType):
            self.subtype = subtype
        elif isinstance(subtype, type) and issubclass(subtype, DataType):
            self.subtype = subtype()
        else:
            raise TypeError('subtype must be a DataType')

        self.choices = choices

    def sanitize(self, value):
        if value is None:
            return value

        value = self.subtype.sanitize(value)

        if value not in self.choices:
            raise DataTypeError(
                '"%s" is not one of (%s)' % (
                    value,
                    ', '.join([repr(c) for c in self.choices]),
                )
            )

        return value