-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjsonproperty.py
More file actions
134 lines (103 loc) · 3.41 KB
/
jsonproperty.py
File metadata and controls
134 lines (103 loc) · 3.41 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
import copy
import simplejson
from google.appengine.api import datastore_errors
from google.appengine.api import datastore_types
from google.appengine.ext import db
class JsonMixin(object):
"""Simple, stateless json utilities mixin.
Requires class to implement two methods:
to_json(self): convert data to json-compatible datastructure (dict,
list, strings, numbers)
@classmethod from_json(cls, json): load data from json-compatible structure.
"""
def to_json_str(self):
"""Convert data to json string representation.
Returns:
json representation as string.
"""
return simplejson.dumps(self.to_json(), sort_keys=True)
@classmethod
def from_json_str(cls, json_str):
"""Convert json string representation into class instance.
Args:
json_str: json representation as string.
Returns:
New instance of the class with data loaded from json string.
"""
return cls.from_json(simplejson.loads(json_str))
class JsonProperty(db.UnindexedProperty):
"""Property type for storing json representation of data.
Requires data types to implement two methods:
to_json(self): convert data to json-compatible datastructure (dict,
list, strings, numbers)
@classmethod from_json(cls, json): load data from json-compatible structure.
"""
def __init__(self, data_type, default=None, **kwargs):
"""Constructor.
Args:
data_type: underlying data type as class.
default: default value for the property. The value is deep copied
fore each model instance.
kwargs: remaining arguments.
"""
kwargs["default"] = default
super(JsonProperty, self).__init__(**kwargs)
self.data_type = data_type
def get_value_for_datastore(self, model_instance):
"""Gets value for datastore.
Args:
model_instance: instance of the model class.
Returns:
datastore-compatible value.
"""
value = super(JsonProperty, self).get_value_for_datastore(model_instance)
if not value:
return None
json_value = value.to_json()
if not json_value:
return None
return datastore_types.Text(simplejson.dumps(
json_value, sort_keys=True))
def make_value_from_datastore(self, value):
"""Convert value from datastore representation.
Args:
value: datastore value.
Returns:
value to store in the model.
"""
if value is None:
return None
return self.data_type.from_json(simplejson.loads(value))
def validate(self, value):
"""Validate value.
Args:
value: model value.
Returns:
Whether the specified value is valid data type value.
Raises:
BadValueError: when value is not of self.data_type type.
"""
if value is not None and not isinstance(value, self.data_type):
raise datastore_errors.BadValueError(
"Property %s must be convertible to a %s instance (%s)" %
(self.name, self.data_type, value))
return super(JsonProperty, self).validate(value)
def empty(self, value):
"""Checks if value is empty.
Args:
value: model value.
Returns:
True passed value is empty.
"""
return not value
def default_value(self):
"""Create default model value.
If default option was specified, then it will be deeply copied.
None otherwise.
Returns:
default model value.
"""
if self.default:
return copy.deepcopy(self.default)
else:
return None