1
2
3
4
5
6
7 """
8 restkit.resource
9 ~~~~~~~~~~~~~~~~
10
11 This module provide a common interface for all HTTP request.
12 """
13 from copy import copy
14 import urlparse
15
16 from restkit.errors import ResourceNotFound, Unauthorized, RequestFailed,\
17 ParserError, RequestError
18 from restkit.client import HttpRequest, HttpResponse
19 from restkit.filters import BasicAuth
20 from restkit import util
21 from restkit.conn import get_default_manager
22
24 """A class that can be instantiated for access to a RESTful resource,
25 including authentication.
26 """
27
28 charset = 'utf-8'
29 encode_keys = True
30 safe = "/:"
31 keepalive = True
32 basic_auth_url = True
33 response_class = HttpResponse
34
36 """Constructor for a `Resource` object.
37
38 Resource represent an HTTP resource.
39
40 :param uri: str, full uri to the server.
41 :param client_opts: `restkit.client.HttpRequest` Options
42 """
43 client_opts = client_opts or {}
44
45 self.initial = dict(
46 uri = uri,
47 client_opts = client_opts.copy()
48 )
49
50
51 if self.response_class is not None and \
52 not 'response_class' in client_opts:
53 client_opts['response_class'] = self.response_class
54
55
56 if not 'pool_instance' in client_opts and self.keepalive:
57 client_opts['connection_manager'] = get_default_manager()
58
59 self.filters = client_opts.get('filters') or []
60 if self.basic_auth_url:
61
62 u = urlparse.urlparse(uri)
63 if u.username:
64 password = u.password or ""
65
66
67 filters = copy(self.filters)
68 filters.append(BasicAuth(u.username, password))
69 client_opts['filters'] = filters
70
71
72 uri = urlparse.urlunparse((u.scheme, u.netloc.split("@")[-1],
73 u.path, u.params, u.query, u.fragment))
74
75 self.uri = uri
76 self.client_opts = client_opts
77
79 return '<%s %s>' % (self.__class__.__name__, self.uri)
80
82 """if you want to add a path to resource uri, you can do:
83
84 .. code-block:: python
85
86 resr2 = res.clone()
87
88 """
89 obj = self.__class__(self.initial['uri'],
90 **self.initial['client_opts'])
91 return obj
92
94 """if you want to add a path to resource uri, you can do:
95
96 .. code-block:: python
97
98 Resource("/path").get()
99 """
100
101 uri = self.initial['uri']
102
103 new_uri = util.make_uri(uri, path, charset=self.charset,
104 safe=self.safe, encode_keys=self.encode_keys)
105
106 obj = type(self)(new_uri, **self.initial['client_opts'])
107 return obj
108
110 """ Close all the connections related to the resource """
111 pool = self.client_opts.get('pool_instance')
112 if not pool:
113 return
114
115 parsed_url = urlparse.urlparse(self.uri)
116 pool.clear_host(util.parse_netloc(parsed_url))
117
118 - def get(self, path=None, headers=None, params_dict=None, **params):
119 """ HTTP GET
120
121 :param path: string additionnal path to the uri
122 :param headers: dict, optionnal headers that will
123 be added to HTTP request.
124 :param params: Optionnal parameterss added to the request.
125 """
126 return self.request("GET", path=path, headers=headers,
127 params_dict=params_dict, **params)
128
129 - def head(self, path=None, headers=None, params_dict=None, **params):
130 """ HTTP HEAD
131
132 see GET for params description.
133 """
134 return self.request("HEAD", path=path, headers=headers,
135 params_dict=params_dict, **params)
136
137 - def delete(self, path=None, headers=None, params_dict=None, **params):
138 """ HTTP DELETE
139
140 see GET for params description.
141 """
142 return self.request("DELETE", path=path, headers=headers,
143 params_dict=params_dict, **params)
144
145 - def post(self, path=None, payload=None, headers=None,
146 params_dict=None, **params):
147 """ HTTP POST
148
149 :param payload: string passed to the body of the request
150 :param path: string additionnal path to the uri
151 :param headers: dict, optionnal headers that will
152 be added to HTTP request.
153 :param params: Optionnal parameterss added to the request
154 """
155
156 return self.request("POST", path=path, payload=payload,
157 headers=headers, params_dict=params_dict, **params)
158
159 - def put(self, path=None, payload=None, headers=None,
160 params_dict=None, **params):
161 """ HTTP PUT
162
163 see POST for params description.
164 """
165 return self.request("PUT", path=path, payload=payload,
166 headers=headers, params_dict=params_dict, **params)
167
170
173
176
177 - def request(self, method, path=None, payload=None, headers=None,
178 params_dict=None, **params):
179 """ HTTP request
180
181 This method may be the only one you want to override when
182 subclassing `restkit.rest.Resource`.
183
184 :param payload: string or File object passed to the body of the request
185 :param path: string additionnal path to the uri
186 :param headers: dict, optionnal headers that will
187 be added to HTTP request.
188 :params_dict: Options parameters added to the request as a dict
189 :param params: Optionnal parameterss added to the request
190 """
191
192 params = params or {}
193 params.update(params_dict or {})
194
195 while True:
196 uri = util.make_uri(self.uri, path, charset=self.charset,
197 safe=self.safe, encode_keys=self.encode_keys,
198 **self.make_params(params))
199
200
201 http = HttpRequest(**self.client_opts)
202 resp = http.request(uri, method=method, body=payload,
203 headers=self.make_headers(headers))
204
205 if resp is None:
206
207 raise ValueError("Unkown error: response object is None")
208
209 if resp.status_int >= 400:
210 if resp.status_int == 404:
211 raise ResourceNotFound(resp.body_string(),
212 response=resp)
213 elif resp.status_int in (401, 403):
214 if self.unauthorized(resp):
215 raise Unauthorized(resp.body_string(),
216 http_code=resp.status_int,
217 response=resp)
218 else:
219 raise RequestFailed(resp.body_string(),
220 http_code=resp.status_int,
221 response=resp)
222 else:
223 break
224
225 return resp
226
237