1 import pyperry.response_parsers as parsers
2
4 """
5 Used to transport response data from a write adapter through the
6 adapter's call stack.
7
8 A write adapter returns a C{Response} object for all calls to its C{write}
9 or C{delete} methods. The write adapter is responsible for setting the
10 C{success}, C{raw}, C{raw_format}, C{status}, and C{meta} attributes on the
11 C{Response} object, but should perform no additional processing.
12 Middlewares can then use the response data to modify the model being saved.
13 For example, after a write, one middleware may refresh the model's
14 attributes, while another middleware may expire some cache entries for that
15 model. The C{parsed}, C{model_attributes}, and C{errors} methods are
16 provided to return the response data in formats that are easy for
17 middlewares to work with.
18
19 """
20
21 PARSERS = {
22 'json': parsers.JSONResponseParser
23 }
24
26
27 self.success = False
28 """True if the write or delete succeeded, False otherwise"""
29
30 self.status = None
31 """an adapter-specific status code (optional)"""
32
33 self.meta = {}
34 """adapter-specific information about the response (optional)"""
35
36 self.raw = None
37 """the raw (unmodified) response data received from the adapter"""
38
39 self.raw_format = 'json'
40 """the data format of the raw response data, such as 'json' or 'xml'"""
41
42 for k, v in kwargs.items():
43 self.__setattr__(k, v)
44
46 """
47 Returns a format-independent dictionary representation of the raw
48 response data. Both the model_attributes and errors methods transform
49 the result of the parsed method into a form that is meaningful.
50
51 """
52 if not hasattr(self, '_parsed'):
53 parser = self.PARSERS[self.raw_format]()
54 self._parsed = None
55 if self.raw is not None:
56 try:
57 self._parsed = parser.parse(self.raw)
58 except:
59 pass
60 return self._parsed
61
63 """
64 Returns a dictionary representing a model's attributes obtained by
65 transforming the result of the parsed method.
66
67 """
68 parsed = self.parsed()
69 if isinstance(parsed, dict):
70 if len(parsed) == 1 and isinstance(parsed.values()[0], dict):
71 self._model_attributes = parsed[parsed.keys()[0]]
72 else:
73 self._model_attributes = parsed
74 else:
75 self._model_attributes = {}
76 return self._model_attributes
77
79 """
80 Returns a dictionary in the same format as the model's errors
81 dictionary obtained by transforming the result of the parsed method.
82
83 """
84 parsed = self.parsed()
85 if isinstance(parsed, dict):
86 if 'errors' in parsed and isinstance(parsed['errors'], dict):
87 errors = parsed['errors']
88 else:
89 errors = parsed
90 else:
91 errors = {}
92 return errors
93
95 """
96 Prevent the parsed method from being replaced.
97
98 Allows a user to set response.parsed = {...} without replacing the
99 parsed method. This is because the parsed method will parse the
100 contents of the raw attribute and store its value in the _parsed
101 attribute if _parsed has not already been set to some other value.
102 Setting any other attribute still works like normal.
103
104 """
105 if name == 'parsed':
106 name = '_' + name
107 object.__setattr__(self, name, value)
108