1. Benoit Chesneau
  2. py-restclient

Commits

ben...@pollen.nymphormation.net  committed aecdbbb

Sometimes you don't want to encode utls at all. This change allow you
to define which characters need to be encoded or not in url too.

  • Participants
  • Parent commits dc30738
  • Branches default

Comments (0)

Files changed (2)

File docs/resource.txt

View file
 RestClient class
 ----------------
 
-RestClient represent a simple HTTP client.
+RestClient represent a simple HTTP client. **New in 1.1** By default all urls are utf8
+encoded. But you could change default charset, safe characters and
+decide that keys don't need to be encoded.
 
 .. autoclass:: restclient.rest.RestClient
 
 
     **Properties**
 
-    .. attribute:: httpclient
+    .. attribute:: transport
 
         Any http instance of object based on 
         `restclient.http.HTTPTransportBase`. By default it will use 
         own depending of the option you need to access to the serve
         (authentification, proxy, ....).
 
+    .. describe:: charset
+        
+        By default it's 'utf-8', it define charset of urls.
+
+    .. describe:: encode_keys
+
+        By default True. Encode params keys
+
+    .. describe:: safe
+
+        By default is ":/", define which charaters are safe in url and
+        don't need to be encoded.
+
 
     **Methods**
 

File restclient/rest.py

View file
     >>> res.get('/5rOqE9XTz7lccLgZoQS4IP',headers={'Accept': 'application/json'}).http_code
     200
 """
-from urllib import quote, urlencode
+import urllib
 
 from restclient.transport import getDefaultHTTPTransport, HTTPTransportBase 
 
         '{"snippet": "testing API.", "title": "", "id": "3XDqQ8G83LlzVWgCeWdwru", "language": "text", "revision": "363934613139"}'
     """
 
+    charset = 'utf-8'
+    encode_keys = True
+    safe = "/:"
+
     def __init__(self, transport=None):
         """Constructor for a `RestClient` object.
 
             if not 'Content-Length' in headers:
                 raise RequestError("'Content-Lenght' should be specified when body is a File like instance") 
 
-        resp, data = self.transport.request(make_uri(uri, path, **params), 
+        resp, data = self.transport.request(self.make_uri(uri, path, **params), 
                 method=method, body=body, headers=headers)
 
         status_code = int(resp.status)
         return ResourceResult(data, status_code, resp)
 
 
-def make_uri(base, *path, **query):
-    """Assemble a uri based on a base, any number of path segments, and query
-    string parameters.
+    def make_uri(self, base, *path, **query):
+        """Assemble a uri based on a base, any number of path segments, and query
+        string parameters.
 
-    >>> make_uri('http://example.org/', '/_all_dbs')
-    'http://example.org/_all_dbs'
-    """
+        """
+        if base and base.endswith("/"):
+            base = base[:-1]
+        retval = [base]
 
-    if base and base.endswith("/"):
-        base = base[:-1]
-    retval = [base]
+        # build the path
+        path = "/".join([''] +
+                        [url_quote(s.strip('/'), self.charset, self.safe) for s in path
+                         if s is not None])
 
-    # build the path
-    path_ = ''
-    for p in path:
-        if p is not None:
-            path_ += "/".join([unicode_quote(s) for s in p.split('/')
-                if s is not None])
+        if path:
+            retval.append(path)
     
-    if path_:
-        retval.append(path_)
-    
-    params = []
-    for k, v in query.items():
-        if type(v) in (list, tuple):
-            params.extend([(name, i) for i in v if i is not None])
-        elif v is not None:
-            params.append((k,v))
-    if params:
-        retval.extend(['?', unicode_urlencode(params)])
-    return ''.join(retval)
+        params = []
+        for k, v in query.items():
+            if type(v) in (list, tuple):
+                params.extend([(name, i) for i in v if i is not None])
+            elif v is not None:
+                params.append((k,v))
+        if params:
+            retval.extend(['?', url_encode(params, self.charset, self.encode_keys)])
 
-def unicode_quote(string, safe=''):
-    if isinstance(string, unicode):
-        string = string.encode('utf-8')
-    return quote(string, safe)
+        return ''.join(retval)
 
-def unicode_urlencode(data):
-    if isinstance(data, dict):
-        data = data.items()
-    params = []
-    for name, value in data:
-        if isinstance(value, unicode):
-            value = value.encode('utf-8')
-        params.append((name, value))
-    return urlencode(params)
 
+# code borrowed to Wekzeug with minor changes
+
+def url_quote(s, charset='utf-8', safe='/:'):
+    """URL encode a single string with a given encoding."""
+    if isinstance(s, unicode):
+        s = s.encode(charset)
+    elif not isinstance(s, str):
+        s = str(s)
+    return urllib.quote(s, safe=safe)
+
+def url_encode(obj, charset="utf8", encode_keys=False):
+    if isinstance(obj, dict):
+        for k, v in obj.iteritems():
+            if not isinstance(v, (tuple, list)):
+                v = [v]
+            items.append((k, v))
+    else:
+        items = obj or ()
+
+    tmp = []
+    for key, value in items:
+        if encode_keys and isinstance(key, unicode):
+            key = key.encode(charset)
+        else:
+            key = str(key)
+        tmp.append('%s=%s' % (urllib.quote(key),
+            urllib.quote_plus(value)))
+
+    return '&'.join(tmp)
+