Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(286)

Side by Side Diff: appengine/findit/libs/meta_dict_serializer.py

Issue 2641583002: [Cuprit-finder] Add MetaDict class. (Closed)
Patch Set: Update doc. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | appengine/findit/libs/meta_object.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2017 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """This module offers a serializer for ``MetaDict``.
6
7 The ``MetaDictSerializer`` itself is a ``MetaDict``, only it is an ordered
8 ``MetaDict`` (using an ``OrderedDict`` internally).
9
10 Factory of metadict serializer is offered - ``GetSerializer``.
11 What the factory does is it copies the structure of keys of a passed-in
12 ``MetaObject`` and uses a ``key`` function to generate an ordered dict to
13 maintain the key orders.
14
15 Given the ``MetaDictSerializer`` we can serialize a
16 ``MetaDict`` to a list of ``Element``s, and de-serialize a list of ``Element``s
17 to a ``MetaDict``.
18
19 Serialization is needed when we need an ordered traversal of a ``MetaDict``.
20 De-Serialization is needed when we want to construct the list back to
21 a ``MetaDict`` so we can have our customized grouping and keyword matching.
22
23 An usecase in ``Predator`` is, in ``loglinear`` classification model, we use
24 scipy to train ``meta_weight``(inherit from ``MetaDict``), the ``meta_weight``
25 has to be serialized to a list of floats for training, and after the training it
26 should be de-serialized to a ``meta_weight`` to multiply with ``meta_feature``.
27 """
28
29 from collections import OrderedDict
30
31 from libs.meta_object import Element
32 from libs.meta_object import MetaDict
33
34
35 class ElementSerializer(Element):
36
37 def ToList(self, element, default=None):
38 """Serializes an ``Element`` to a list of this single element.
39
40 Args:
41 element (Element or None): The element to be serialized. If the element
42 is None, return a list of one default value.
43 default (Element or None) The default value to set when None element is
44 provided.
45
46 Returns:
47 A list of single element.
48
49 Raises:
50 Exception: An error occurs when the passed-in meta object is not an
51 ``Element`` object.
52 """
53 if element is None:
54 return [default]
55
56 assert element.is_element, Exception(
57 '%s can only serialize Element object.' % self.__class__.__name__)
58 return [element]
59
60 def FromList(self, element_list, constructor=None):
61 """De-serializes from element_list to an ``Element``.
62
63 Args:
64 element_list (list of Element): A list of ``Element`` object.
65 constructor (callable): contructor of ``Element`` class.
66
67 Returns:
68 The ``Element`` object in the element_list.
69
70 Raises:
71 Exception: An error occurs when the element_list is not 1.
72 """
73 assert len(element_list) == len(self), Exception(
74 'The element list should have the same length as serializer')
75
76 constructor = constructor or (lambda x: x)
77 return constructor(element_list[0])
78
79 def __len__(self):
80 return 1
81
82
83 class MetaDictSerializer(MetaDict):
84 """Class that serialize a ``MetaDict`` to a list of ``Element``s.
85
86 This class itself is a ``MetaDict``, it has the same structure as the
87 meta_dict it wants to serialize or de-serialize, and it is using a
88 ``OrderedDict`` to keep track of the serializing order.
89 """
90
91 def __init__(self, value):
92 super(MetaDictSerializer, self).__init__(value)
93 self._length = None
94
95 def ToList(self, meta_dict, default=None):
96 """Serializes a ``MetaDict`` to a list of ``Element``s.
97
98 Args:
99 meta_dict (MetaDict or None): The element to be serialized. If meta_dict
100 is None, return a list of default values.
101 default (Element or None) The default value to set when None meta_dict is
102 provided.
103
104 Returns:
105 A list of ``Element``s.
106 """
107 element_list = []
108 for key, serializer in self.iteritems():
109 sub_meta_dict = meta_dict.get(key) if meta_dict else None
110 element_list.extend(serializer.ToList(sub_meta_dict, default=default))
111
112 return element_list
113
114 def FromList(self, element_list,
115 meta_constructor=None, element_constructor=None):
116 """De-serializes from element_list to an ``MetaDict``.
117
118 Args:
119 element_list (list of Element): A list of ``Element`` object.
120 element_constructor (callable): The constructor of ``Element`` object that
121 takes one value in element_list as input.
122 meta_constructor (callable): The contructor of ``MetaDict`` object that
123 only take one dict of MetaObjects as input.
124
125 Returns:
126 The ``MetaDict`` object contructed from element_list.
127
128 Raises:
129 Exception: An error occurs when the length of element_list is not equal
130 to the serializer length.
131 """
132 assert len(self) == len(element_list), Exception(
133 'The element list should have the same length as serializer')
134
135 meta_constructor = meta_constructor or (lambda x: x)
136 meta_objs = {}
137 index = 0
138 for key, serializer in self.iteritems():
139 # Truncate the segment in the element list to construct
140 # the ``MetaObject`` corresponding to ``key``.
141 segment = element_list[index : (index + len(serializer))]
142 if serializer.is_element:
143 meta_objs[key] = serializer.FromList(segment, element_constructor)
144 else:
145 meta_objs[key] = serializer.FromList(segment, meta_constructor,
146 element_constructor)
147
148 index += len(serializer)
149
150 return meta_constructor(meta_objs)
151
152 def _Length(self):
153 """Methods to get the length of the serializer recusively.
154
155 Note, the length of a serializer is the number of elements, which is also
156 the number of "real values" in a ``MetaDict`` structure.
157 """
158 if self._length is not None:
159 return self._length
160
161 self._length = 0
162 for value in self.itervalues():
163 self._length += len(value)
164
165 return self._length
166
167 def __len__(self):
168 return self._Length()
169
170
171 def GetSerializer(meta_object, key=None):
172 """Factory to get a serializer corresponding to a ``MetaObject``.
173
174 Args:
175 meta_object (MetaObject): ``Element`` or ``MetaDict`` objects.
176 key (callable or None): Key function to sort ``MetaDict`` object.
177 """
178 if meta_object.is_element:
179 return ElementSerializer()
180
181 sorted_meta = sorted(meta_object.iteritems(), key=key)
182 ordered_dict = OrderedDict((key, GetSerializer(sub_meta))
183 for key, sub_meta in sorted_meta)
184
185 return MetaDictSerializer(ordered_dict)
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/libs/meta_object.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698