Package restkit :: Module resource
[hide private]

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