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  _default_pool = None 
24 -def default_pool(keepalive, timeout):
25 global _default_pool 26 if _default_pool is None: 27 _default_pool = SimplePool(keepalive=keepalive, timeout=timeout) 28 return _default_pool
29
30 -class Resource(object):
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
42 - def __init__(self, uri, **client_opts):
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 # set default response_class 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 # set default pool if needed 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 # detect credentials from url 73 u = urlparse.urlparse(uri) 74 if u.username: 75 password = u.password or "" 76 77 # add filters 78 filters = copy(self.filters) 79 filters.append(BasicAuth(u.username, password)) 80 client_opts['filters'] = filters 81 82 # update uri 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
89 - def __repr__(self):
90 return '<%s %s>' % (self.__class__.__name__, self.uri)
91
92 - def clone(self):
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
104 - def __call__(self, path):
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
120 - def close(self):
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
174 - def make_params(self, params):
175 return params or {}
176
177 - def make_headers(self, headers):
178 return headers or []
179
180 - def unauthorized(self, response):
181 return True
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 # make request 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 # race condition 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
229 - def update_uri(self, path):
230 """ 231 to set a new uri absolute path 232 """ 233 self.uri = util.make_uri(self.uri, path, charset=self.charset, 234 safe=self.safe, encode_keys=self.encode_keys) 235 self.original['uri'] = util.make_uri(self.original['uri'], path, 236 charset=self.charset, 237 safe=self.safe, 238 encode_keys=self.encode_keys)
239