]> jfr.im git - z_archive/twitter.git/blob - twitter/api.py
0.4.3 - fix for broken POST requests
[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 class TwitterCall(object):
26 def __init__(self, username, password, format, uri=""):
27 self.username = username
28 self.password = password
29 self.format = format
30 self.uri = uri
31 def __getattr__(self, k):
32 try:
33 return object.__getattr__(self, k)
34 except AttributeError:
35 return TwitterCall(
36 self.username, self.password, self.format,
37 self.uri + "/" + k)
38 def __call__(self, **kwargs):
39 method = "GET"
40 if (self.uri.endswith('new')
41 or self.uri.endswith('update')
42 or self.uri.endswith('create')
43 or self.uri.endswith('destroy')):
44 method = "POST"
45
46 encoded_kwargs = urlencode(kwargs.items())
47 argStr = ""
48 if kwargs and (method == "GET"):
49 argStr = "?" + encoded_kwargs
50
51 headers = {}
52 if (self.username):
53 headers["Authorization"] = "Basic " + b64encode("%s:%s" %(
54 self.username, self.password))
55 if method == "POST":
56 headers["Content-type"] = "application/x-www-form-urlencoded"
57 headers["Content-length"] = len(encoded_kwargs)
58
59 c = httplib.HTTPConnection("twitter.com")
60 try:
61 c.putrequest(method, "%s.%s%s" %(
62 self.uri, self.format, argStr))
63 for item in headers.iteritems():
64 c.putheader(*item)
65 c.endheaders()
66 if method == "POST":
67 c.send(encoded_kwargs)
68 r = c.getresponse()
69
70 if (r.status == 304):
71 return []
72 elif (r.status != 200):
73 raise TwitterError("Twitter sent status %i: %s" %(
74 r.status, r.read()))
75 if "json" == self.format:
76 return json.loads(r.read())
77 else:
78 return r.read()
79 finally:
80 c.close()
81
82 class Twitter(TwitterCall):
83 """
84 The minimalist yet fully featured Twitter API class.
85
86 Get RESTful data by accessing members of this class. The result
87 is decoded python objects (lists and dicts).
88
89 The Twitter API is documented here:
90 http://groups.google.com/group/twitter-development-talk/web/api-documentation
91
92 Examples::
93
94 twitter = Twitter("hello@foo.com", "password123")
95
96 # Get the public timeline
97 twitter.statuses.public_timeline()
98
99 # Get a particular friend's timeline
100 twitter.statuses.friends_timeline(id="billybob")
101
102 # Also supported (but totally weird)
103 twitter.statuses.friends_timeline.billybob()
104
105 # Send a direct message
106 twitter.direct_messages.new(
107 user="billybob",
108 text="I think yer swell!")
109
110 Using the data returned::
111
112 Twitter API calls return decoded JSON. This is converted into
113 a bunch of Python lists, dicts, ints, and strings. For example,
114
115 x = twitter.statuses.public_timeline()
116
117 # The first 'tweet' in the timeline
118 x[0]
119
120 # The screen name of the user who wrote the first 'tweet'
121 x[0]['user']['screen_name']
122
123 Getting raw XML data::
124
125 If you prefer to get your Twitter data in XML format, pass
126 format="xml" to the Twitter object when you instantiate it:
127
128 twitter = Twitter(format="xml")
129
130 The output will not be parsed in any way. It will be a raw string
131 of XML.
132 """
133 def __init__(self, email=None, password=None, format="json"):
134 """
135 Create a new twitter API connector using the specified
136 credentials (email and password). Format specifies the output
137 format ("json" (default) or "xml").
138 """
139 if (format not in ("json", "xml")):
140 raise TwitterError("Unknown data format '%s'" %(format))
141 TwitterCall.__init__(self, email, password, format)
142
143 __all__ = ["Twitter", "TwitterError"]