]> jfr.im git - z_archive/twitter.git/blame - twitter/api.py
Remove spaces at eol.
[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
aec68959 6from twitter.auth import 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):
aec68959 64 # Build the uri.
1be4ce71 65 uriparts = []
b0dedfc0 66 for uripart in self.uriparts:
aec68959
MV
67 # If this part matches a keyword argument, use the
68 # supplied value otherwise, just use the part.
69 uriparts.append(kwargs.pop(uripart, uripart))
1be4ce71
MV
70 uri = '/'.join(uriparts)
71
7364ea65 72 method = "GET"
612ececa 73 for action in POST_ACTIONS:
b0dedfc0 74 if uri.endswith(action):
2dab41b1
MV
75 method = "POST"
76 break
612ececa 77
aec68959
MV
78 # If an id kwarg is present and there is no id to fill in in
79 # the list of uriparts, assume the id goes at the end.
da45d039
MV
80 id = kwargs.pop('id', None)
81 if id:
82 uri += "/%s" %(id)
4e9d6343 83
568331a9
MH
84 secure_str = ''
85 if self.secure:
86 secure_str = 's'
6c527e72 87 dot = ""
1be4ce71 88 if self.format:
6c527e72
MV
89 dot = "."
90 uriBase = "http%s://%s/%s%s%s" %(
91 secure_str, self.domain, uri, dot, self.format)
568331a9 92
5b8b1ead 93 headers = {}
1be4ce71 94 if self.auth:
568331a9 95 headers.update(self.auth.generate_headers())
1be4ce71
MV
96 arg_data = self.auth.encode_params(uriBase, method, kwargs)
97 if method == 'GET':
98 uriBase += '?' + arg_data
99 body = None
100 else:
101 body = arg_data
102
103 req = urllib2.Request(uriBase, body, headers)
102acdb1 104
7364ea65 105 try:
102acdb1 106 handle = urllib2.urlopen(req)
de072195
HN
107 if "json" == self.format:
108 return json.loads(handle.read())
109 else:
110 return handle.read()
111 except urllib2.HTTPError, e:
112 if (e.code == 304):
7364ea65 113 return []
de072195 114 else:
aec68959 115 raise TwitterHTTPError(e, uri, self.format, arg_data)
102acdb1 116
7364ea65 117class Twitter(TwitterCall):
118 """
119 The minimalist yet fully featured Twitter API class.
4e9d6343 120
7364ea65 121 Get RESTful data by accessing members of this class. The result
122 is decoded python objects (lists and dicts).
123
124 The Twitter API is documented here:
153dee29 125
aec68959
MV
126 http://dev.twitter.com/doc
127
4e9d6343 128
7364ea65 129 Examples::
4e9d6343 130
69e1f98e
MV
131 twitter = Twitter(
132 auth=OAuth(token, token_key, con_secret, con_secret_key)))
4e9d6343 133
7364ea65 134 # Get the public timeline
135 twitter.statuses.public_timeline()
4e9d6343 136
7364ea65 137 # Get a particular friend's timeline
138 twitter.statuses.friends_timeline(id="billybob")
4e9d6343 139
7364ea65 140 # Also supported (but totally weird)
141 twitter.statuses.friends_timeline.billybob()
4e9d6343 142
7364ea65 143 # Send a direct message
144 twitter.direct_messages.new(
145 user="billybob",
146 text="I think yer swell!")
147
b0dedfc0
MV
148 # Get the members of a particular list of a particular friend
149 twitter.user.listname.members(user="billybob", listname="billysbuds")
150
69e1f98e 151
153dee29 152 Searching Twitter::
4e9d6343 153
0b486eda 154 twitter_search = Twitter(domain="search.twitter.com")
153dee29 155
0b486eda
HN
156 # Find the latest search trends
157 twitter_search.trends()
153dee29 158
0b486eda
HN
159 # Search for the latest News on #gaza
160 twitter_search.search(q="#gaza")
153dee29 161
7364ea65 162
68b3e2ee
MV
163 Using the data returned
164 -----------------------
165
166 Twitter API calls return decoded JSON. This is converted into
167 a bunch of Python lists, dicts, ints, and strings. For example::
7364ea65 168
169 x = twitter.statuses.public_timeline()
170
171 # The first 'tweet' in the timeline
172 x[0]
173
174 # The screen name of the user who wrote the first 'tweet'
175 x[0]['user']['screen_name']
4e9d6343 176
4e9d6343 177
68b3e2ee
MV
178 Getting raw XML data
179 --------------------
180
181 If you prefer to get your Twitter data in XML format, pass
182 format="xml" to the Twitter object when you instantiate it::
4e9d6343 183
a55e6a11 184 twitter = Twitter(format="xml")
4e9d6343 185
a55e6a11 186 The output will not be parsed in any way. It will be a raw string
187 of XML.
68b3e2ee 188
7364ea65 189 """
45688301 190 def __init__(
aec68959
MV
191 self, format="json",
192 domain="twitter.com", secure=True, auth=None,
1cc9ab0b 193 api_version=''):
7364ea65 194 """
68b3e2ee
MV
195 Create a new twitter API connector.
196
197 Pass an `auth` parameter to use the credentials of a specific
198 user. Generally you'll want to pass an `OAuth`
69e1f98e
MV
199 instance::
200
201 twitter = Twitter(auth=OAuth(
202 token, token_secret, consumer_key, consumer_secret))
203
204
68b3e2ee
MV
205 `domain` lets you change the domain you are connecting. By
206 default it's twitter.com but `search.twitter.com` may be
207 useful too.
208
209 If `secure` is False you will connect with HTTP instead of
210 HTTPS.
211
212 The value of `agent` is sent in the `X-Twitter-Client`
213 header. This is deprecated. Instead Twitter determines the
214 application using the OAuth Client Key and Client Key Secret
215 parameters.
1cc9ab0b
MV
216
217 `api_version` is used to set the base uri. By default it's
218 nothing, but if you set it to '1' your URI will start with
219 '1/'.
7364ea65 220 """
d20da7f3
MV
221 if not auth:
222 auth = NoAuth()
223
6c527e72 224 if (format not in ("json", "xml", "")):
68b3e2ee
MV
225 raise ValueError("Unknown data format '%s'" %(format))
226
1be4ce71 227 uriparts = ()
68b3e2ee 228 if api_version:
1be4ce71 229 uriparts += (str(api_version),)
68b3e2ee 230
9a148ed1 231 TwitterCall.__init__(
aec68959 232 self, auth=auth, format=format, domain=domain,
1be4ce71 233 secure=secure, uriparts=uriparts)
7e43e2ed 234
7364ea65 235
64a8d213 236__all__ = ["Twitter", "TwitterError", "TwitterHTTPError"]