]> jfr.im git - z_archive/twitter.git/blob - twitter/api.py
Merge branch 'master' of git://github.com/sixohsix/twitter
[z_archive/twitter.git] / twitter / api.py
1
2 from base64 import b64encode
3 from urllib import urlencode
4
5 import httplib
6
7 from exceptions import Exception
8
9 def _py26OrGreater():
10 import sys
11 return sys.hexversion > 0x20600f0
12
13 if _py26OrGreater():
14 import json
15 else:
16 import simplejson as json
17
18 class TwitterError(Exception):
19 """
20 Exception thrown by the Twitter object when there is an
21 error interacting with twitter.com.
22 """
23 pass
24
25 # These actions require POST http requests instead of GET
26 _POST_ACTIONS = [
27 "create", "update", "destroy", "new", "follow", "leave",
28 ]
29
30 class TwitterCall(object):
31 def __init__(
32 self, username, password, format, domain, uri="", agent=None):
33 self.username = username
34 self.password = password
35 self.format = format
36 self.domain = domain
37 self.uri = uri
38 self.agent = agent
39 def __getattr__(self, k):
40 try:
41 return object.__getattr__(self, k)
42 except AttributeError:
43 return TwitterCall(
44 self.username, self.password, self.format, self.domain,
45 self.uri + "/" + k, self.agent)
46 def __call__(self, **kwargs):
47 uri = self.uri
48 method = "GET"
49 for action in _POST_ACTIONS:
50 if self.uri.endswith(action):
51 method = "POST"
52 if (self.agent):
53 kwargs["source"] = self.agent
54 break
55
56 if kwargs.has_key('id'):
57 uri += "/%s" %(kwargs['id'])
58
59 encoded_kwargs = urlencode(kwargs.items())
60 argStr = ""
61 if kwargs and (method == "GET"):
62 argStr = "?" + encoded_kwargs
63
64 headers = {}
65 if (self.agent):
66 headers["X-Twitter-Client"] = self.agent
67 if (self.username):
68 headers["Authorization"] = "Basic " + b64encode("%s:%s" %(
69 self.username, self.password))
70 if method == "POST":
71 headers["Content-type"] = "application/x-www-form-urlencoded"
72 headers["Content-length"] = len(encoded_kwargs)
73
74 c = httplib.HTTPConnection(self.domain)
75 try:
76 c.putrequest(method, "%s.%s%s" %(
77 uri, self.format, argStr))
78 for item in headers.iteritems():
79 c.putheader(*item)
80 c.endheaders()
81 if method == "POST":
82 c.send(encoded_kwargs)
83 r = c.getresponse()
84
85 if (r.status == 304):
86 return []
87 elif (r.status != 200):
88 raise TwitterError(
89 "Twitter sent status %i for URL: %s.%s using parameters: (%s)\ndetails: %s" %(
90 r.status, uri, self.format, encoded_kwargs, r.read()))
91 if "json" == self.format:
92 return json.loads(r.read())
93 else:
94 return r.read()
95 finally:
96 c.close()
97
98 class Twitter(TwitterCall):
99 """
100 The minimalist yet fully featured Twitter API class.
101
102 Get RESTful data by accessing members of this class. The result
103 is decoded python objects (lists and dicts).
104
105 The Twitter API is documented here:
106
107 http://apiwiki.twitter.com/
108 http://groups.google.com/group/twitter-development-talk/web/api-documentation
109
110 Examples::
111
112 twitter = Twitter("hello@foo.com", "password123")
113
114 # Get the public timeline
115 twitter.statuses.public_timeline()
116
117 # Get a particular friend's timeline
118 twitter.statuses.friends_timeline(id="billybob")
119
120 # Also supported (but totally weird)
121 twitter.statuses.friends_timeline.billybob()
122
123 # Send a direct message
124 twitter.direct_messages.new(
125 user="billybob",
126 text="I think yer swell!")
127
128 Searching Twitter::
129
130 twitter_search = Twitter(domain="search.twitter.com")
131
132 # Find the latest search trends
133 twitter_search.trends()
134
135 # Search for the latest News on #gaza
136 twitter_search.search(q="#gaza")
137
138 Using the data returned::
139
140 Twitter API calls return decoded JSON. This is converted into
141 a bunch of Python lists, dicts, ints, and strings. For example,
142
143 x = twitter.statuses.public_timeline()
144
145 # The first 'tweet' in the timeline
146 x[0]
147
148 # The screen name of the user who wrote the first 'tweet'
149 x[0]['user']['screen_name']
150
151 Getting raw XML data::
152
153 If you prefer to get your Twitter data in XML format, pass
154 format="xml" to the Twitter object when you instantiate it:
155
156 twitter = Twitter(format="xml")
157
158 The output will not be parsed in any way. It will be a raw string
159 of XML.
160 """
161 def __init__(
162 self, email=None, password=None, format="json", domain="twitter.com",
163 agent=None):
164 """
165 Create a new twitter API connector using the specified
166 credentials (email and password). Format specifies the output
167 format ("json" (default) or "xml").
168 """
169 if (format not in ("json", "xml")):
170 raise TwitterError("Unknown data format '%s'" %(format))
171 TwitterCall.__init__(self, email, password, format, domain, "", agent)
172
173 __all__ = ["Twitter", "TwitterError"]