]> jfr.im git - z_archive/twitter.git/blob - twitter/api.py
Deal with the encoding problem
[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 from twitter.twitter_globals import POST_ACTIONS
10
11 def _py26OrGreater():
12 import sys
13 return sys.hexversion > 0x20600f0
14
15 if _py26OrGreater():
16 import json
17 else:
18 import simplejson as json
19
20 class TwitterError(Exception):
21 """
22 Exception thrown by the Twitter object when there is an
23 error interacting with twitter.com.
24 """
25 pass
26
27 class TwitterCall(object):
28 def __init__(
29 self, username, password, format, domain, uri="", agent=None, encoded_args=None):
30 self.username = username
31 self.password = password
32 self.format = format
33 self.domain = domain
34 self.uri = uri
35 self.agent = agent
36 self.encoded_args = encoded_args
37
38 def __getattr__(self, k):
39 try:
40 return object.__getattr__(self, k)
41 except AttributeError:
42 return TwitterCall(
43 self.username, self.password, self.format, self.domain,
44 self.uri + "/" + k, self.agent, self.encoded_args)
45
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 (not self.encoded_args):
57 if kwargs.has_key('id'):
58 uri += "/%s" %(kwargs['id'])
59
60 self.encoded_args = urlencode(kwargs.items())
61
62 argStr = ""
63 argData = None
64 if (method == "GET"):
65 if self.encoded_args:
66 argStr = "?%s" %(self.encoded_args)
67 else:
68 argData = self.encoded_args
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, 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.fp.read()))
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"]