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