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