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 HttpConnection
19 from restkit.filters import BasicAuth
20 from restkit import util
21 from restkit.pool.simple import SimplePool
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 pool_class = SimplePool
32 keepalive = True
33 basic_auth_url = True
34
35 - def __init__(self, uri, headers=None, **client_opts):
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 headers: dict, optionnal headers that will
42 be added to HTTP request.
43 :param client_opts: `restkit.client.HttpConnection` Options
44 """
45
46 pool_instance = client_opts.get('pool_instance')
47 keepalive = client_opts.get("keepalive") or 10
48 if not pool_instance and self.keepalive:
49 pool = self.pool_class(keepalive=keepalive)
50 client_opts['pool_instance'] = pool
51
52 self.filters = client_opts.get('filters') or []
53 if self.basic_auth_url:
54
55 u = urlparse.urlparse(uri)
56 if u.username:
57 password = u.password or ""
58
59
60 filters = copy(self.filters)
61 filters.append(BasicAuth(u.username, password))
62 client_opts['filters'] = filters
63
64
65 uri = urlparse.urlunparse((u.scheme, u.netloc.split("@")[-1],
66 u.path, u.params, u.query, u.fragment))
67
68 self.uri = uri
69 self._headers = headers or {}
70 self.client_opts = client_opts
71 self._body_parts = []
72
74 return '<%s %s>' % (self.__class__.__name__, self.uri)
75
77 for attr_name in ('charset', 'encode_keys', 'pool_class',
78 'keepalive', 'basic_auth_url'):
79 setattr(obj, attr_name, getattr(self, attr_name))
80 return obj
81
83 """if you want to add a path to resource uri, you can do:
84
85 .. code-block:: python
86
87 resr2 = res.clone()
88
89 """
90 client_opts = self.client_opts.copy()
91 client_opts["filters"] = self.filters
92 obj = self.__class__(self.uri, headers=self._headers,
93 **client_opts)
94 return self._set_default_attrs(obj)
95
97 """if you want to add a path to resource uri, you can do:
98
99 .. code-block:: python
100
101 Resource("/path").get()
102 """
103
104 client_opts = self.client_opts.copy()
105 client_opts["filters"] = self.filters
106
107 new_uri = util.make_uri(self.uri, path, charset=self.charset,
108 safe=self.safe, encode_keys=self.encode_keys)
109
110 obj = type(self)(new_uri, headers=self._headers, **client_opts)
111 return self._set_default_attrs(obj)
112
114 """ Close all the connections related to the resource """
115 pool = self.client_opts.get('pool_instance')
116 if not pool:
117 return
118
119 parsed_url = urlparse.urlparse(self.uri)
120 pool.clear_host(util.parse_netloc(parsed_url))
121
122 - def get(self, path=None, headers=None, **params):
123 """ HTTP GET
124
125 :param path: string additionnal path to the uri
126 :param headers: dict, optionnal headers that will
127 be added to HTTP request.
128 :param params: Optionnal parameterss added to the request.
129 """
130 return self.request("GET", path=path, headers=headers, **params)
131
132 - def head(self, path=None, headers=None, **params):
133 """ HTTP HEAD
134
135 see GET for params description.
136 """
137 return self.request("HEAD", path=path, headers=headers, **params)
138
139 - def delete(self, path=None, headers=None, **params):
140 """ HTTP DELETE
141
142 see GET for params description.
143 """
144 return self.request("DELETE", path=path, headers=headers, **params)
145
146 - def post(self, path=None, payload=None, headers=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)
158
159 - def put(self, path=None, payload=None, headers=None, **params):
160 """ HTTP PUT
161
162 see POST for params description.
163 """
164 return self.request("PUT", path=path, payload=payload,
165 headers=headers, **params)
166
167 - def do_request(self, url, method='GET', payload=None, headers=None):
171
172 - def request(self, method, path=None, payload=None, headers=None,
173 **params):
174 """ HTTP request
175
176 This method may be the only one you want to override when
177 subclassing `restkit.rest.Resource`.
178
179 :param payload: string or File object passed to the body of the request
180 :param path: string additionnal path to the uri
181 :param headers: dict, optionnal headers that will
182 be added to HTTP request.
183 :param params: Optionnal parameterss added to the request
184 """
185
186 headers = headers or []
187 uri = util.make_uri(self.uri, path, charset=self.charset,
188 safe=self.safe, encode_keys=self.encode_keys,
189 **params)
190
191 resp = self.do_request(uri, method=method, payload=payload,
192 headers=headers)
193
194 if resp is None:
195
196 raise ValueError("Unkown error: response object is None")
197
198 if resp.status_int >= 400:
199 if resp.status_int == 404:
200 raise ResourceNotFound(resp.body_string(), response=resp)
201 elif resp.status_int in (401, 403):
202 raise Unauthorized(resp.body_string(),
203 http_code=resp.status_int, response=resp)
204 else:
205 raise RequestFailed(resp.body_string(),
206 http_code=resp.status_int, response=resp)
207
208 return resp
209
216