]>
jfr.im git - z_archive/twitter.git/blob - twitter/api.py
3 from exceptions
import Exception
5 from twitter
.twitter_globals
import POST_ACTIONS
6 from twitter
.auth
import NoAuth
10 return sys
.hexversion
> 0x20600f0
15 import simplejson
as json
17 class TwitterError(Exception):
19 Base Exception thrown by the Twitter object when there is a
20 general error interacting with the API.
24 class TwitterHTTPError(TwitterError
):
26 Exception thrown by the Twitter object when there is an
27 HTTP error interacting with twitter.com.
29 def __init__(self
, e
, uri
, format
, uriparts
):
33 self
.uriparts
= uriparts
37 "Twitter sent status %i for URL: %s.%s using parameters: "
38 "(%s)\ndetails: %s" %(
39 self
.e
.code
, self
.uri
, self
.format
, self
.uriparts
,
42 class TwitterResponse(object):
44 Response from a twitter request. Behaves like a list or a string
45 (depending on requested format) but it has a few other interesting
48 `headers` gives you access to the response headers as an
49 httplib.HTTPHeaders instance. You can do
50 `response.headers.getheader('h')` to retrieve a header.
52 def __init__(self
, headers
):
53 self
.headers
= headers
56 def rate_limit_remaining(self
):
58 Remaining requests in the current rate-limit.
60 return int(self
.headers
.getheader('X-RateLimit-Remaining'))
63 def rate_limit_reset(self
):
65 Time in UTC epoch seconds when the rate limit will reset.
67 return int(self
.headers
.getheader('X-RateLimit-Reset'))
70 # Multiple inheritance makes my inner Java nerd cry. Why can't I just
71 # add arbitrary attributes to list or str objects?! Guido, we need to
73 class TwitterJsonListResponse(TwitterResponse
, list):
74 __doc__
= """Twitter JSON Response
75 """ + TwitterResponse
.__doc
__
76 def __init__(self
, lst
, headers
):
77 TwitterResponse
.__init
__(self
, headers
)
78 list.__init
__(self
, lst
)
79 class TwitterJsonDictResponse(TwitterResponse
, dict):
80 __doc__
= """Twitter JSON Response
81 """ + TwitterResponse
.__doc
__
82 def __init__(self
, d
, headers
):
83 TwitterResponse
.__init
__(self
, headers
)
84 dict.__init
__(self
, d
)
86 class TwitterXmlResponse(TwitterResponse
, str):
87 __doc__
= """Twitter XML Response
88 """ + TwitterResponse
.__doc
__
91 class TwitterCall(object):
93 self
, auth
, format
, domain
, uri
="", agent
=None,
94 uriparts
=None, secure
=True):
100 self
.uriparts
= uriparts
103 def __getattr__(self
, k
):
105 return object.__getattr
__(self
, k
)
106 except AttributeError:
108 auth
=self
.auth
, format
=self
.format
, domain
=self
.domain
,
109 agent
=self
.agent
, uriparts
=self
.uriparts
+ (k
,),
112 def __call__(self
, **kwargs
):
115 for uripart
in self
.uriparts
:
116 # If this part matches a keyword argument, use the
117 # supplied value otherwise, just use the part.
118 uriparts
.append(unicode(kwargs
.pop(uripart
, uripart
)))
119 uri
= u
'/'.join(uriparts
)
122 for action
in POST_ACTIONS
:
123 if uri
.endswith(action
):
127 # If an id kwarg is present and there is no id to fill in in
128 # the list of uriparts, assume the id goes at the end.
129 id = kwargs
.pop('id', None)
139 uriBase
= "http%s://%s/%s%s%s" %(
140 secure_str
, self
.domain
, uri
, dot
, self
.format
)
144 headers
.update(self
.auth
.generate_headers())
145 arg_data
= self
.auth
.encode_params(uriBase
, method
, kwargs
)
147 uriBase
+= '?' + arg_data
152 req
= urllib2
.Request(uriBase
, body
, headers
)
155 handle
= urllib2
.urlopen(req
)
156 if "json" == self
.format
:
157 res
= json
.loads(handle
.read())
159 TwitterJsonListResponse
if type(res
) is list
160 else TwitterJsonDictResponse
)
161 return response_cls(res
, handle
.headers
)
163 r
= TwitterXmlResponse(handle
.read())
164 r
.headers
= handle
.headers
166 except urllib2
.HTTPError
, e
:
170 raise TwitterHTTPError(e
, uri
, self
.format
, arg_data
)
172 class Twitter(TwitterCall
):
174 The minimalist yet fully featured Twitter API class.
176 Get RESTful data by accessing members of this class. The result
177 is decoded python objects (lists and dicts).
179 The Twitter API is documented here:
181 http://dev.twitter.com/doc
187 auth=OAuth(token, token_key, con_secret, con_secret_key)))
189 # Get the public timeline
190 twitter.statuses.public_timeline()
192 # Get a particular friend's timeline
193 twitter.statuses.friends_timeline(id="billybob")
195 # Also supported (but totally weird)
196 twitter.statuses.friends_timeline.billybob()
198 # Send a direct message
199 twitter.direct_messages.new(
201 text="I think yer swell!")
203 # Get the members of a particular list of a particular friend
204 twitter.user.listname.members(user="billybob", listname="billysbuds")
209 twitter_search = Twitter(domain="search.twitter.com")
211 # Find the latest search trends
212 twitter_search.trends()
214 # Search for the latest News on #gaza
215 twitter_search.search(q="#gaza")
218 Using the data returned
219 -----------------------
221 Twitter API calls return decoded JSON. This is converted into
222 a bunch of Python lists, dicts, ints, and strings. For example::
224 x = twitter.statuses.public_timeline()
226 # The first 'tweet' in the timeline
229 # The screen name of the user who wrote the first 'tweet'
230 x[0]['user']['screen_name']
236 If you prefer to get your Twitter data in XML format, pass
237 format="xml" to the Twitter object when you instantiate it::
239 twitter = Twitter(format="xml")
241 The output will not be parsed in any way. It will be a raw string
247 domain
="twitter.com", secure
=True, auth
=None,
250 Create a new twitter API connector.
252 Pass an `auth` parameter to use the credentials of a specific
253 user. Generally you'll want to pass an `OAuth`
256 twitter = Twitter(auth=OAuth(
257 token, token_secret, consumer_key, consumer_secret))
260 `domain` lets you change the domain you are connecting. By
261 default it's twitter.com but `search.twitter.com` may be
264 If `secure` is False you will connect with HTTP instead of
267 The value of `agent` is sent in the `X-Twitter-Client`
268 header. This is deprecated. Instead Twitter determines the
269 application using the OAuth Client Key and Client Key Secret
272 `api_version` is used to set the base uri. By default it's
273 nothing, but if you set it to '1' your URI will start with
279 if (format
not in ("json", "xml", "")):
280 raise ValueError("Unknown data format '%s'" %(format))
284 uriparts
+= (str(api_version
),)
286 TwitterCall
.__init
__(
287 self
, auth
=auth
, format
=format
, domain
=domain
,
288 secure
=secure
, uriparts
=uriparts
)
291 __all__
= ["Twitter", "TwitterError", "TwitterHTTPError",
292 "TwitterJsonListResponse", "TwitterJsonDictResponse",
293 "TwitterXmlResponse"]