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