]> jfr.im git - z_archive/twitter.git/blobdiff - twitter/api.py
make cmd client understand any language
[z_archive/twitter.git] / twitter / api.py
index 5d75f871df300836ec3483da9f3dd67711d0d053..b7ba19857e3939586b14eb5b85f521f7f20507ac 100644 (file)
@@ -39,6 +39,55 @@ class TwitterHTTPError(TwitterError):
                 self.e.code, self.uri, self.format, self.uriparts,
                 self.e.fp.read()))
 
+class TwitterResponse(object):
+    """
+    Response from a twitter request. Behaves like a list or a string
+    (depending on requested format) but it has a few other interesting
+    attributes.
+
+    `headers` gives you access to the response headers as an
+    httplib.HTTPHeaders instance. You can do
+    `response.headers.getheader('h')` to retrieve a header.
+    """
+    def __init__(self, headers):
+        self.headers = headers
+
+    @property
+    def rate_limit_remaining(self):
+        """
+        Remaining requests in the current rate-limit.
+        """
+        return int(self.headers.getheader('X-RateLimit-Remaining'))
+
+    @property
+    def rate_limit_reset(self):
+        """
+        Time in UTC epoch seconds when the rate limit will reset.
+        """
+        return int(self.headers.getheader('X-RateLimit-Reset'))
+
+
+# Multiple inheritance makes my inner Java nerd cry. Why can't I just
+# add arbitrary attributes to list or str objects?! Guido, we need to
+# talk.
+class TwitterJsonListResponse(TwitterResponse, list):
+    __doc__ = """Twitter JSON Response
+    """ + TwitterResponse.__doc__
+    def __init__(self, lst, headers):
+        TwitterResponse.__init__(self, headers)
+        list.__init__(self, lst)
+class TwitterJsonDictResponse(TwitterResponse, dict):
+    __doc__ = """Twitter JSON Response
+    """ + TwitterResponse.__doc__
+    def __init__(self, d, headers):
+        TwitterResponse.__init__(self, headers)
+        dict.__init__(self, d)
+
+class TwitterXmlResponse(TwitterResponse, str):
+    __doc__ = """Twitter XML Response
+    """ + TwitterResponse.__doc__
+
+
 class TwitterCall(object):
     def __init__(
         self, auth, format, domain, uri="", agent=None,
@@ -66,8 +115,8 @@ class TwitterCall(object):
         for uripart in self.uriparts:
             # If this part matches a keyword argument, use the
             # supplied value otherwise, just use the part.
-            uriparts.append(kwargs.pop(uripart, uripart))
-        uri = '/'.join(uriparts)
+            uriparts.append(unicode(kwargs.pop(uripart, uripart)))
+        uri = u'/'.join(uriparts)
 
         method = "GET"
         for action in POST_ACTIONS:
@@ -105,9 +154,15 @@ class TwitterCall(object):
         try:
             handle = urllib2.urlopen(req)
             if "json" == self.format:
-                return json.loads(handle.read())
+                res = json.loads(handle.read())
+                response_cls = (
+                    TwitterJsonListResponse if type(res) is list
+                    else TwitterJsonDictResponse)
+                return response_cls(res, handle.headers)
             else:
-                return handle.read()
+                r = TwitterXmlResponse(handle.read())
+                r.headers = handle.headers
+                return r
         except urllib2.HTTPError, e:
             if (e.code == 304):
                 return []
@@ -233,4 +288,6 @@ class Twitter(TwitterCall):
             secure=secure, uriparts=uriparts)
 
 
-__all__ = ["Twitter", "TwitterError", "TwitterHTTPError"]
+__all__ = ["Twitter", "TwitterError", "TwitterHTTPError",
+           "TwitterJsonListResponse", "TwitterJsonDictResponse",
+           "TwitterXmlResponse"]