]> jfr.im git - z_archive/twitter.git/blame - twitter/api.py
Update patch to work with new code.
[z_archive/twitter.git] / twitter / api.py
CommitLineData
de072195 1import urllib2
7364ea65 2
5251ea48 3from exceptions import Exception
4
612ececa 5from twitter.twitter_globals import POST_ACTIONS
d20da7f3 6from twitter.auth import UserPassAuth, NoAuth
4e9d6343 7
f1a8ed67 8def _py26OrGreater():
9 import sys
10 return sys.hexversion > 0x20600f0
11
12if _py26OrGreater():
13 import json
14else:
15 import simplejson as json
16
5251ea48 17class TwitterError(Exception):
21e3bd23 18 """
64a8d213
B
19 Base Exception thrown by the Twitter object when there is a
20 general error interacting with the API.
21e3bd23 21 """
5251ea48 22 pass
23
64a8d213
B
24class TwitterHTTPError(TwitterError):
25 """
26 Exception thrown by the Twitter object when there is an
27 HTTP error interacting with twitter.com.
28 """
1be4ce71 29 def __init__(self, e, uri, format, uriparts):
64a8d213
B
30 self.e = e
31 self.uri = uri
32 self.format = format
1be4ce71 33 self.uriparts = uriparts
64a8d213
B
34
35 def __str__(self):
68b3e2ee
MV
36 return (
37 "Twitter sent status %i for URL: %s.%s using parameters: "
38 "(%s)\ndetails: %s" %(
1be4ce71 39 self.e.code, self.uri, self.format, self.uriparts,
68b3e2ee 40 self.e.fp.read()))
64a8d213 41
7364ea65 42class TwitterCall(object):
c8d451e8 43 def __init__(
568331a9 44 self, auth, format, domain, uri="", agent=None,
7e43e2ed 45 uriparts=None, secure=True):
568331a9 46 self.auth = auth
a55e6a11 47 self.format = format
153dee29 48 self.domain = domain
7364ea65 49 self.uri = uri
4a6070c8 50 self.agent = agent
b0dedfc0 51 self.uriparts = uriparts
9a148ed1 52 self.secure = secure
fd2bc885 53
7364ea65 54 def __getattr__(self, k):
55 try:
56 return object.__getattr__(self, k)
57 except AttributeError:
58 return TwitterCall(
1be4ce71
MV
59 auth=self.auth, format=self.format, domain=self.domain,
60 agent=self.agent, uriparts=self.uriparts + (k,),
61 secure=self.secure)
fd2bc885 62
7364ea65 63 def __call__(self, **kwargs):
b0dedfc0 64 #build the uri
1be4ce71 65 uriparts = []
b0dedfc0
MV
66 for uripart in self.uriparts:
67 #if this part matches a keyword argument, use the supplied value
68 #otherwise, just use the part
1be4ce71
MV
69 uriparts.append(kwargs.pop(uripart,uripart))
70 uri = '/'.join(uriparts)
71
7364ea65 72 method = "GET"
612ececa 73 for action in POST_ACTIONS:
b0dedfc0 74 if uri.endswith(action):
2dab41b1 75 method = "POST"
4ad03f81
MV
76 if (self.agent):
77 kwargs["source"] = self.agent
2dab41b1 78 break
612ececa 79
b0dedfc0
MV
80 """This handles a special case. It isn't really needed anymore because now
81 we can insert an id value (or any other value) at the end of the
82 uri (or anywhere else).
83 However we can leave it for backward compatibility."""
da45d039
MV
84 id = kwargs.pop('id', None)
85 if id:
86 uri += "/%s" %(id)
4e9d6343 87
568331a9
MH
88 secure_str = ''
89 if self.secure:
90 secure_str = 's'
6c527e72 91 dot = ""
1be4ce71 92 if self.format:
6c527e72
MV
93 dot = "."
94 uriBase = "http%s://%s/%s%s%s" %(
95 secure_str, self.domain, uri, dot, self.format)
568331a9 96
5b8b1ead 97 headers = {}
4a6070c8
HN
98 if (self.agent):
99 headers["X-Twitter-Client"] = self.agent
1be4ce71 100 if self.auth:
568331a9 101 headers.update(self.auth.generate_headers())
1be4ce71
MV
102 arg_data = self.auth.encode_params(uriBase, method, kwargs)
103 if method == 'GET':
104 uriBase += '?' + arg_data
105 body = None
106 else:
107 body = arg_data
108
109 req = urllib2.Request(uriBase, body, headers)
102acdb1 110
7364ea65 111 try:
102acdb1 112 handle = urllib2.urlopen(req)
de072195
HN
113 if "json" == self.format:
114 return json.loads(handle.read())
115 else:
116 return handle.read()
117 except urllib2.HTTPError, e:
118 if (e.code == 304):
7364ea65 119 return []
de072195 120 else:
1be4ce71 121 raise TwitterHTTPError(e, uriBase, self.format, self.uriparts)
102acdb1 122
7364ea65 123class Twitter(TwitterCall):
124 """
125 The minimalist yet fully featured Twitter API class.
4e9d6343 126
7364ea65 127 Get RESTful data by accessing members of this class. The result
128 is decoded python objects (lists and dicts).
129
130 The Twitter API is documented here:
153dee29 131
0b486eda
HN
132 http://apiwiki.twitter.com/
133 http://groups.google.com/group/twitter-development-talk/web/api-documentation
4e9d6343 134
7364ea65 135 Examples::
4e9d6343 136
69e1f98e
MV
137 twitter = Twitter(
138 auth=OAuth(token, token_key, con_secret, con_secret_key)))
4e9d6343 139
7364ea65 140 # Get the public timeline
141 twitter.statuses.public_timeline()
4e9d6343 142
7364ea65 143 # Get a particular friend's timeline
144 twitter.statuses.friends_timeline(id="billybob")
4e9d6343 145
7364ea65 146 # Also supported (but totally weird)
147 twitter.statuses.friends_timeline.billybob()
4e9d6343 148
7364ea65 149 # Send a direct message
150 twitter.direct_messages.new(
151 user="billybob",
152 text="I think yer swell!")
153
b0dedfc0
MV
154 # Get the members of a particular list of a particular friend
155 twitter.user.listname.members(user="billybob", listname="billysbuds")
156
69e1f98e 157
153dee29 158 Searching Twitter::
4e9d6343 159
0b486eda 160 twitter_search = Twitter(domain="search.twitter.com")
153dee29 161
0b486eda
HN
162 # Find the latest search trends
163 twitter_search.trends()
153dee29 164
0b486eda
HN
165 # Search for the latest News on #gaza
166 twitter_search.search(q="#gaza")
153dee29 167
7364ea65 168
68b3e2ee
MV
169 Using the data returned
170 -----------------------
171
172 Twitter API calls return decoded JSON. This is converted into
173 a bunch of Python lists, dicts, ints, and strings. For example::
7364ea65 174
175 x = twitter.statuses.public_timeline()
176
177 # The first 'tweet' in the timeline
178 x[0]
179
180 # The screen name of the user who wrote the first 'tweet'
181 x[0]['user']['screen_name']
4e9d6343 182
4e9d6343 183
68b3e2ee
MV
184 Getting raw XML data
185 --------------------
186
187 If you prefer to get your Twitter data in XML format, pass
188 format="xml" to the Twitter object when you instantiate it::
4e9d6343 189
a55e6a11 190 twitter = Twitter(format="xml")
4e9d6343 191
a55e6a11 192 The output will not be parsed in any way. It will be a raw string
193 of XML.
68b3e2ee 194
7364ea65 195 """
45688301 196 def __init__(
68b3e2ee 197 self, email=None, password=None, format="json",
24baad0c 198 domain="twitter.com", agent=None, secure=True, auth=None,
1cc9ab0b 199 api_version=''):
7364ea65 200 """
68b3e2ee
MV
201 Create a new twitter API connector.
202
203 Pass an `auth` parameter to use the credentials of a specific
204 user. Generally you'll want to pass an `OAuth`
69e1f98e
MV
205 instance::
206
207 twitter = Twitter(auth=OAuth(
208 token, token_secret, consumer_key, consumer_secret))
209
210
211 Alternately you can pass `email` and `password` parameters but
212 this authentication mode will be deactive by Twitter very soon
213 and is not recommended::
214
215 twitter = Twitter(email="blah@blah.com", password="foobar")
216
68b3e2ee
MV
217
218 `domain` lets you change the domain you are connecting. By
219 default it's twitter.com but `search.twitter.com` may be
220 useful too.
221
222 If `secure` is False you will connect with HTTP instead of
223 HTTPS.
224
225 The value of `agent` is sent in the `X-Twitter-Client`
226 header. This is deprecated. Instead Twitter determines the
227 application using the OAuth Client Key and Client Key Secret
228 parameters.
1cc9ab0b
MV
229
230 `api_version` is used to set the base uri. By default it's
231 nothing, but if you set it to '1' your URI will start with
232 '1/'.
7364ea65 233 """
568331a9 234 if email is not None or password is not None:
68b3e2ee 235 if auth:
1cc9ab0b 236 raise ValueError(
68b3e2ee
MV
237 "Can't specify 'email'/'password' and 'auth' params"
238 " simultaneously.")
568331a9
MH
239 auth = UserPassAuth(email, password)
240
d20da7f3
MV
241 if not auth:
242 auth = NoAuth()
243
6c527e72 244 if (format not in ("json", "xml", "")):
68b3e2ee
MV
245 raise ValueError("Unknown data format '%s'" %(format))
246
1be4ce71 247 uriparts = ()
68b3e2ee 248 if api_version:
1be4ce71 249 uriparts += (str(api_version),)
68b3e2ee 250
9a148ed1 251 TwitterCall.__init__(
1be4ce71
MV
252 self, auth=auth, format=format, domain=domain, agent=agent,
253 secure=secure, uriparts=uriparts)
7e43e2ed 254
7364ea65 255
64a8d213 256__all__ = ["Twitter", "TwitterError", "TwitterHTTPError"]