Package restkit :: Module util
[hide private]

Source Code for Module restkit.util

  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  import os 
  7  import re 
  8  import time 
  9  import urllib 
 10  import urlparse 
 11  import warnings 
 12  import Cookie 
 13   
 14  from restkit.errors import InvalidUrl 
 15   
 16  absolute_http_url_re = re.compile(r"^https?://", re.I) 
 17   
 18  try:#python 2.6, use subprocess 
 19      import subprocess 
 20      subprocess.Popen  # trigger ImportError early 
 21      closefds = os.name == 'posix' 
 22       
23 - def popen3(cmd, mode='t', bufsize=0):
24 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, 25 stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, 26 close_fds=closefds) 27 p.wait() 28 return (p.stdin, p.stdout, p.stderr)
29 except ImportError: 30 subprocess = None 31 popen3 = os.popen3 32
33 -def locate_program(program):
34 if os.path.isabs(program): 35 return program 36 if os.path.dirname(program): 37 program = os.path.normpath(os.path.realpath(program)) 38 return program 39 paths = os.getenv('PATH') 40 if not paths: 41 return False 42 for path in paths.split(os.pathsep): 43 filename = os.path.join(path, program) 44 if os.access(filename, os.X_OK): 45 return filename 46 return False
47 48 weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] 49 monthname = [None, 50 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 51 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 52
53 -def http_date(timestamp=None):
54 """Return the current date and time formatted for a message header.""" 55 if timestamp is None: 56 timestamp = time.time() 57 year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp) 58 s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( 59 weekdayname[wd], 60 day, monthname[month], year, 61 hh, mm, ss) 62 return s
63
64 -def parse_netloc(uri):
65 host = uri.netloc 66 port = None 67 i = host.rfind(':') 68 j = host.rfind(']') # ipv6 addresses have [...] 69 if i > j: 70 try: 71 port = int(host[i+1:]) 72 except ValueError: 73 raise InvalidUrl("nonnumeric port: '%s'" % host[i+1:]) 74 host = host[:i] 75 else: 76 # default port 77 if uri.scheme == "https": 78 port = 443 79 else: 80 port = 80 81 82 if host and host[0] == '[' and host[-1] == ']': 83 host = host[1:-1] 84 return (host, port)
85
86 -def to_bytestring(s):
87 if not isinstance(s, basestring): 88 raise TypeError("value should be a str or unicode") 89 90 if isinstance(s, unicode): 91 return s.encode('utf-8') 92 return s
93
94 -def url_quote(s, charset='utf-8', safe='/:'):
95 """URL encode a single string with a given encoding.""" 96 if isinstance(s, unicode): 97 s = s.encode(charset) 98 elif not isinstance(s, str): 99 s = str(s) 100 return urllib.quote(s, safe=safe)
101 102
103 -def url_encode(obj, charset="utf8", encode_keys=False):
104 items = [] 105 if isinstance(obj, dict): 106 for k, v in list(obj.items()): 107 items.append((k, v)) 108 else: 109 items = list(items) 110 111 tmp = [] 112 for k, v in items: 113 if encode_keys: 114 k = encode(k, charset) 115 116 if not isinstance(v, (tuple, list)): 117 v = [v] 118 119 for v1 in v: 120 if v1 is None: 121 v1 = '' 122 elif callable(v1): 123 v1 = encode(v1(), charset) 124 else: 125 v1 = encode(v1, charset) 126 tmp.append('%s=%s' % (urllib.quote(k), urllib.quote_plus(v1))) 127 return '&'.join(tmp)
128
129 -def encode(v, charset="utf8"):
130 if isinstance(v, unicode): 131 v = v.encode(charset) 132 else: 133 v = str(v) 134 return v
135 136
137 -def make_uri(base, *args, **kwargs):
138 """Assemble a uri based on a base, any number of path segments, 139 and query string parameters. 140 141 """ 142 143 # get encoding parameters 144 charset = kwargs.pop("charset", "utf-8") 145 safe = kwargs.pop("safe", "/:") 146 encode_keys = kwargs.pop("encode_keys", True) 147 148 base_trailing_slash = False 149 if base and base.endswith("/"): 150 base_trailing_slash = True 151 base = base[:-1] 152 retval = [base] 153 154 # build the path 155 _path = [] 156 trailing_slash = False 157 for s in args: 158 if s is not None and isinstance(s, basestring): 159 if len(s) > 1 and s.endswith('/'): 160 trailing_slash = True 161 else: 162 trailing_slash = False 163 _path.append(url_quote(s.strip('/'), charset, safe)) 164 165 path_str ="" 166 if _path: 167 path_str = "/".join([''] + _path) 168 if trailing_slash: 169 path_str = path_str + "/" 170 elif base_trailing_slash: 171 path_str = path_str + "/" 172 173 if path_str: 174 retval.append(path_str) 175 176 params_str = url_encode(kwargs, charset, encode_keys) 177 if params_str: 178 retval.extend(['?', params_str]) 179 180 return ''.join(retval)
181 182
183 -def rewrite_location(host_uri, location, prefix_path=None):
184 prefix_path = prefix_path or '' 185 url = urlparse.urlparse(location) 186 host_url = urlparse.urlparse(host_uri) 187 188 if not absolute_http_url_re.match(location): 189 # remote server doesn't follow rfc2616 190 proxy_uri = '%s%s' % (host_uri, prefix_path) 191 return urlparse.urljoin(proxy_uri, location) 192 elif url.scheme == host_url.scheme and url.netloc == host_url.netloc: 193 return urlparse.urlunparse((host_url.scheme, host_url.netloc, 194 prefix_path + url.path, url.params, url.query, url.fragment)) 195 196 return location
197
198 -def replace_header(name, value, headers):
199 idx = -1 200 for i, (k, v) in enumerate(headers): 201 if k.upper() == name.upper(): 202 idx = i 203 break 204 if idx >= 0: 205 headers[i] = (name.title(), value) 206 else: 207 headers.append((name.title(), value)) 208 return headers
209
210 -def replace_headers(new_headers, headers):
211 hdrs = {} 212 for (k, v) in new_headers: 213 hdrs[k.upper()] = v 214 215 found = [] 216 for i, (k, v) in enumerate(headers): 217 ku = k.upper() 218 if ku in hdrs: 219 headers[i] = (k.title(), hdrs[ku]) 220 found.append(ku) 221 if len(found) == len(new_headers): 222 return 223 224 for k, v in new_headers.items(): 225 if k not in found: 226 headers.append((k.title(), v)) 227 return headers
228 229 250 251
252 -class deprecated_property(object):
253 """ 254 Wraps a decorator, with a deprecation warning or error 255 """
256 - def __init__(self, decorator, attr, message, warning=True):
257 self.decorator = decorator 258 self.attr = attr 259 self.message = message 260 self.warning = warning
261
262 - def __get__(self, obj, type=None):
263 if obj is None: 264 return self 265 self.warn() 266 return self.decorator.__get__(obj, type)
267
268 - def __set__(self, obj, value):
269 self.warn() 270 self.decorator.__set__(obj, value)
271
272 - def __delete__(self, obj):
273 self.warn() 274 self.decorator.__delete__(obj)
275
276 - def __repr__(self):
277 return '<Deprecated attribute %s: %r>' % ( 278 self.attr, 279 self.decorator)
280
281 - def warn(self):
282 if not self.warning: 283 raise DeprecationWarning( 284 'The attribute %s is deprecated: %s' % (self.attr, self.message)) 285 else: 286 warnings.warn( 287 'The attribute %s is deprecated: %s' % (self.attr, self.message), 288 DeprecationWarning, 289 stacklevel=3)
290