-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathfields.py
More file actions
146 lines (107 loc) · 4.26 KB
/
fields.py
File metadata and controls
146 lines (107 loc) · 4.26 KB
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
import operator
from datetime import timedelta
from mongoengine.base import BaseField
from mongoengine.fields import EmailField, IntField, ListField, StringField
try:
from functools import reduce
except ImportError:
# reduce is a builtin in Python2
pass
class TimedeltaField(BaseField):
"""A timedelta field.
Looks to the outside world like a datatime.timedelta, but stores
in the database as an integer (or float) number of seconds.
"""
def validate(self, value):
if not isinstance(value, (timedelta, int, float)):
self.error(u'cannot parse timedelta "%r"' % value)
def to_mongo(self, value):
return self.prepare_query_value(None, value)
def to_python(self, value):
return timedelta(seconds=value)
def prepare_query_value(self, op, value):
if value is None:
return value
if isinstance(value, timedelta):
return self.total_seconds(value)
if isinstance(value, (int, float)):
return value
@staticmethod
def total_seconds(value):
"""Implements Python 2.7's datetime.timedelta.total_seconds()
for backwards compatibility with Python 2.5 and 2.6.
"""
try:
return value.total_seconds()
except AttributeError:
return (value.days * 24 * 3600) + \
(value.seconds) + \
(value.microseconds / 1000000.0)
class LowerStringField(StringField):
def __set__(self, instance, value):
value = self.to_python(value)
return super(LowerStringField, self).__set__(instance, value)
def to_python(self, value):
if value:
value = value.lower()
return value
def prepare_query_value(self, op, value):
value = value.lower() if value else value
return super(LowerStringField, self).prepare_query_value(op, value)
class LowerEmailField(LowerStringField):
def validate(self, value):
if not EmailField.EMAIL_REGEX.match(value):
self.error('Invalid Mail-address: %s' % value)
super(LowerEmailField, self).validate(value)
class EnumField(object):
"""
A class to register Enum type (from the package enum34) into mongo
:param choices: must be of :class:`enum.Enum`: type
and will be used as possible choices
"""
def __init__(self, enum, *args, **kwargs):
self.enum = enum
kwargs['choices'] = [choice for choice in enum]
super(EnumField, self).__init__(*args, **kwargs)
def __get_value(self, enum):
return enum.value if hasattr(enum, 'value') else enum
def to_python(self, value):
return self.enum(super(EnumField, self).to_python(value))
def to_mongo(self, value):
return self.__get_value(value)
def prepare_query_value(self, op, value):
return super(EnumField, self).prepare_query_value(
op, self.__get_value(value))
def validate(self, value):
return super(EnumField, self).validate(self.__get_value(value))
def _validate(self, value, **kwargs):
return super(EnumField, self)._validate(
self.enum(self.__get_value(value)), **kwargs)
class IntEnumField(EnumField, IntField):
"""A variation on :class:`EnumField` for only int containing enumeration.
"""
pass
class IntFlagField(ListField):
def __init__(self, enum, **kwargs):
super(IntFlagField, self).__init__(IntEnumField(enum), **kwargs)
def __get__(self, instance, owner):
if instance is None:
return self
return self.field.enum(reduce(
operator.or_, instance._data.get(self.name, []), 0))
def __set__(self, instance, value):
# copy mongoengine
if value is None:
if self.null:
value = None
elif self.default is not None:
value = self.default
if callable(value):
value = value()
if value is not None and not isinstance(value, list):
value = [i for i in self.field.enum if i and i & value == i]
super(IntFlagField, self).__set__(instance, value)
class StringEnumField(EnumField, StringField):
"""A variation on :class:`EnumField` for only string containing enumeration.
"""
pass