]> jfr.im git - z_archive/twitter.git/blob - twitter/api.py
Transition from httplib to urllib2.
[z_archive/twitter.git] / twitter / api.py
1
2 from base64 import b64encode
3 from urllib import urlencode
4
5 import urllib2
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 id = kwargs.pop('id', None)
57 if id:
58 uri += "/%s" %(id)
59
60 encoded_kwargs = urlencode(kwargs.items())
61 argStr = ""
62 argData = None
63 encoded_kwargs = urlencode(kwargs.items())
64 if kwargs:
65 if (method == "GET"):
66 argStr = "?%s" %(encoded_kwargs)
67 else:
68 argData = encoded_kwargs
69
70 headers = {}
71 if (self.agent):
72 headers["X-Twitter-Client"] = self.agent
73 if (self.username):
74 headers["Authorization"] = "Basic " + b64encode("%s:%s" %(
75 self.username, self.password))
76
77 req = urllib2.Request(
78 "http://%s/%s.%s%s" %(self.domain, self.uri, self.format, argStr),
79 argData, headers
80 )
81 try:
82 handle = urllib2.urlopen(req)
83 if "json" == self.format:
84 return json.loads(handle.read())
85 else:
86 return handle.read()
87 except urllib2.HTTPError, e:
88 if (e.code == 304):
89 return []
90 else:
91 raise TwitterError(
92 "Twitter sent status %i for URL: %s.%s using parameters: (%s)\ndetails: %s" %(
93 e.code, uri, self.format, encoded_kwargs, e,msg))
94
95 class Twitter(TwitterCall):
96 """
97 The minimalist yet fully featured Twitter API class.
98
99 Get RESTful data by accessing members of this class. The result
100 is decoded python objects (lists and dicts).
101
102 The Twitter API is documented here:
103
104 http://apiwiki.twitter.com/
105 http://groups.google.com/group/twitter-development-talk/web/api-documentation
106
107 Examples::
108
109 twitter = Twitter("hello@foo.com", "password123")
110
111 # Get the public timeline
112 twitter.statuses.public_timeline()
113
114 # Get a particular friend's timeline
115 twitter.statuses.friends_timeline(id="billybob")
116
117 # Also supported (but totally weird)
118 twitter.statuses.friends_timeline.billybob()
119
120 # Send a direct message
121 twitter.direct_messages.new(
122 user="billybob",
123 text="I think yer swell!")
124
125 Searching Twitter::
126
127 twitter_search = Twitter(domain="search.twitter.com")
128
129 # Find the latest search trends
130 twitter_search.trends()
131
132 # Search for the latest News on #gaza
133 twitter_search.search(q="#gaza")
134
135 Using the data returned::
136
137 Twitter API calls return decoded JSON. This is converted into
138 a bunch of Python lists, dicts, ints, and strings. For example,
139
140 x = twitter.statuses.public_timeline()
141
142 # The first 'tweet' in the timeline
143 x[0]
144
145 # The screen name of the user who wrote the first 'tweet'
146 x[0]['user']['screen_name']
147
148 Getting raw XML data::
149
150 If you prefer to get your Twitter data in XML format, pass
151 format="xml" to the Twitter object when you instantiate it:
152
153 twitter = Twitter(format="xml")
154
155 The output will not be parsed in any way. It will be a raw string
156 of XML.
157 """
158 def __init__(
159 self, email=None, password=None, format="json", domain="twitter.com",
160 agent=None):
161 """
162 Create a new twitter API connector using the specified
163 credentials (email and password). Format specifies the output
164 format ("json" (default) or "xml").
165 """
166 if (format not in ("json", "xml")):
167 raise TwitterError("Unknown data format '%s'" %(format))
168 TwitterCall.__init__(self, email, password, format, domain, "", agent)
169
170 __all__ = ["Twitter", "TwitterError"]