-
Notifications
You must be signed in to change notification settings - Fork 123
/
util.py
119 lines (98 loc) · 3.77 KB
/
util.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
118
119
import re
from collections import OrderedDict
from django.core.files import File
from django.http import QueryDict
from django.utils.datastructures import MultiValueDict
from django.utils.encoding import force_str
from django.utils.functional import Promise
from rest_framework.utils.serializer_helpers import ReturnDict
camelize_re = re.compile(r"[a-z0-9]?_[a-z0-9]")
def underscore_to_camel(match):
group = match.group()
if len(group) == 3:
return group[0] + group[2].upper()
else:
return group[1].upper()
def camelize(data, **options):
# Handle lazy translated strings.
ignore_fields = options.get("ignore_fields") or ()
ignore_keys = options.get("ignore_keys") or ()
if isinstance(data, Promise):
data = force_str(data)
if isinstance(data, dict):
if isinstance(data, ReturnDict):
new_dict = ReturnDict(serializer=data.serializer)
else:
new_dict = OrderedDict()
for key, value in data.items():
if isinstance(key, Promise):
key = force_str(key)
if isinstance(key, str) and "_" in key:
new_key = re.sub(camelize_re, underscore_to_camel, key)
else:
new_key = key
if key not in ignore_fields and new_key not in ignore_fields:
result = camelize(value, **options)
else:
result = value
if key in ignore_keys or new_key in ignore_keys:
new_dict[key] = result
else:
new_dict[new_key] = result
return new_dict
if is_iterable(data) and not isinstance(data, str):
return [camelize(item, **options) for item in data]
return data
def get_underscoreize_re(options):
if options.get("no_underscore_before_number"):
pattern = r"([a-z0-9]|[A-Z]?(?=[A-Z](?=[a-z])))([A-Z])"
else:
pattern = r"([a-z0-9]|[A-Z]?(?=[A-Z0-9](?=[a-z0-9]|(?<![A-Z])$)))([A-Z]|(?<=[a-z])[0-9](?=[0-9A-Z]|$)|(?<=[A-Z])[0-9](?=[0-9]|$))"
return re.compile(pattern)
def camel_to_underscore(name, **options):
underscoreize_re = get_underscoreize_re(options)
return underscoreize_re.sub(r"\1_\2", name).lower().lstrip("_")
def _get_iterable(data):
if isinstance(data, QueryDict):
return data.lists()
else:
return data.items()
def underscoreize(data, **options):
ignore_fields = options.get("ignore_fields") or ()
ignore_keys = options.get("ignore_keys") or ()
if isinstance(data, dict):
new_dict = {}
if type(data) == MultiValueDict:
new_data = MultiValueDict()
for key, value in data.items():
new_data.setlist(camel_to_underscore(key, **options), data.getlist(key))
return new_data
for key, value in _get_iterable(data):
if isinstance(key, str):
new_key = camel_to_underscore(key, **options)
else:
new_key = key
if key not in ignore_fields and new_key not in ignore_fields:
result = underscoreize(value, **options)
else:
result = value
if key in ignore_keys or new_key in ignore_keys:
new_dict[key] = result
else:
new_dict[new_key] = result
if isinstance(data, QueryDict):
new_query = QueryDict(mutable=True)
for key, value in new_dict.items():
new_query.setlist(key, value)
return new_query
return new_dict
if is_iterable(data) and not isinstance(data, (str, File)):
return [underscoreize(item, **options) for item in data]
return data
def is_iterable(obj):
try:
iter(obj)
except TypeError:
return False
else:
return True