-
Notifications
You must be signed in to change notification settings - Fork 2
/
utils.py
117 lines (83 loc) · 3.24 KB
/
utils.py
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
from datetime import date, datetime, time, timedelta
from json.encoder import JSONEncoder as BaseJSONEncoder
import re
from enum import Enum
from .fields import MultiTypeField
from .model_types import ListModel
from .models import BaseModel
__all__ = ['factory', 'JSONEncoder', 'Factory']
def underscore_to_camel(string):
"""
Converts underscored string to camel case.
"""
return re.sub('_([a-z])', lambda x: x.group(1).upper(), string)
class BaseFormatterIter:
pass
class BaseFieldtypeFormatterIter(BaseFormatterIter):
def __init__(self, obj, field, parent_formatter):
self.obj = obj
self.field = field
self.parent_formatter = parent_formatter
class ListFormatterIter(BaseFieldtypeFormatterIter):
def __iter__(self):
for item in self.obj:
yield self.parent_formatter.format_field(self.field, item)
class BaseModelFormatterIter(BaseFormatterIter):
"""
Base formatter iterator for Dirty Models.
"""
def __init__(self, model):
self.model = model
def __iter__(self):
fields = self.model.get_fields()
for fieldname in fields:
field = self.model.get_field_obj(fieldname)
name = self.model.get_real_name(fieldname)
yield name, self.format_field(field,
self.model.get_field_value(fieldname))
def format_field(self, field, value):
if isinstance(field, MultiTypeField):
return self.format_field(field.get_field_type_by_value(value), value)
elif isinstance(value, BaseModel):
return self.__class__(value)
elif isinstance(value, ListModel):
return ListFormatterIter(obj=value, field=value.get_field_type(), parent_formatter=self)
elif isinstance(value, Enum):
return self.format_field(field, value.value)
return value
class ModelFormatterIter(BaseModelFormatterIter):
"""
Iterate over model fields formatting them.
"""
def format_field(self, field, value):
if isinstance(value, (date, datetime, time)) and not isinstance(field, MultiTypeField):
try:
return field.get_formatted_value(value)
except AttributeError:
return str(value)
elif isinstance(value, timedelta):
return value.total_seconds()
return super(ModelFormatterIter, self).format_field(field, value)
class JSONEncoder(BaseJSONEncoder):
"""
Json encoder for Dirty Models
"""
default_model_iter = ModelFormatterIter
def default(self, obj):
if isinstance(obj, BaseModel):
return {k: v for k, v in self.default_model_iter(obj)}
elif isinstance(obj, (BaseModelFormatterIter)):
return {k: v for k, v in obj}
elif isinstance(obj, ListFormatterIter):
return list(obj)
class Factory:
"""
Factory decorator could be used to define result of a function as default value. It could
be useful to define a :class:`~dirty_models.fields.DateTimeField` with :meth:`datetime.datetime.now`
in order to set the current datetime.
"""
def __init__(self, func):
self.func = func
def __call__(self):
return self.func()
factory = Factory