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.conn import get_default_manager 
 22   
23 -class Resource(object):
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
35 - def __init__(self, uri, **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 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 # set default response_class 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 # set default pool if needed 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 # detect credentials from url 62 u = urlparse.urlparse(uri) 63 if u.username: 64 password = u.password or "" 65 66 # add filters 67 filters = copy(self.filters) 68 filters.append(BasicAuth(u.username, password)) 69 client_opts['filters'] = filters 70 71 # update uri 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
78 - def __repr__(self):
79 return '<%s %s>' % (self.__class__.__name__, self.uri)
80
81 - def clone(self):
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
93 - def __call__(self, path):
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
109 - def close(self):
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
168 - def make_params(self, params):
169 return params or {}
170
171 - def make_headers(self, headers):
172 return headers or []
173
174 - def unauthorized(self, response):
175 return True
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 # make request 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 # race condition 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
227 - def update_uri(self, path):
228 """ 229 to set a new uri absolute path 230 """ 231 self.uri = util.make_uri(self.uri, path, charset=self.charset, 232 safe=self.safe, encode_keys=self.encode_keys) 233 self.initial['uri'] = util.make_uri(self.initial['uri'], path, 234 charset=self.charset, 235 safe=self.safe, 236 encode_keys=self.encode_keys)
237