Package restkit :: Module resource
[hide private]
[frames] | no frames]

Source Code for Module restkit.resource

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