]> jfr.im git - z_archive/twitter.git/blob - twitter/api.py
Add a NoAuth object
[z_archive/twitter.git] / twitter / api.py
1
2 import urllib2
3
4 from exceptions import Exception
5
6 from twitter.twitter_globals import POST_ACTIONS
7 from twitter.auth import UserPassAuth, NoAuth
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__(
27 self, auth, format, domain, uri="", agent=None,
28 encoded_args=None, secure=True):
29 self.auth = auth
30 self.format = format
31 self.domain = domain
32 self.uri = uri
33 self.agent = agent
34 self.encoded_args = encoded_args
35 self.secure = secure
36
37 def __getattr__(self, k):
38 try:
39 return object.__getattr__(self, k)
40 except AttributeError:
41 return TwitterCall(
42 self.auth, self.format, self.domain,
43 self.uri + "/" + k, self.agent, self.encoded_args, self.secure)
44
45 def __call__(self, **kwargs):
46 uri = self.uri.strip("/")
47 method = "GET"
48 for action in POST_ACTIONS:
49 if self.uri.endswith(action):
50 method = "POST"
51 if (self.agent):
52 kwargs["source"] = self.agent
53 break
54
55 secure_str = ''
56 if self.secure:
57 secure_str = 's'
58 uriBase = "http%s://%s/%s.%s" %(
59 secure_str, self.domain, uri, self.format)
60
61 if (not self.encoded_args):
62 if kwargs.has_key('id'):
63 uri += "/%s" %(kwargs['id'])
64
65 self.encoded_args = self.auth.encode_params(uriBase, method, kwargs)
66
67 argStr = ""
68 argData = None
69 if (method == "GET"):
70 if self.encoded_args:
71 argStr = "?%s" %(self.encoded_args)
72 else:
73 argData = self.encoded_args
74
75 headers = {}
76 if (self.agent):
77 headers["X-Twitter-Client"] = self.agent
78 if self.auth is not None:
79 headers.update(self.auth.generate_headers())
80
81 req = urllib2.Request(uriBase+argStr, argData, headers)
82
83 try:
84 handle = urllib2.urlopen(req)
85 if "json" == self.format:
86 return json.loads(handle.read())
87 else:
88 return handle.read()
89 except urllib2.HTTPError, e:
90 if (e.code == 304):
91 return []
92 else:
93 raise TwitterError(
94 "Twitter sent status %i for URL: %s.%s using parameters: (%s)\ndetails: %s" %(
95 e.code, uri, self.format, self.encoded_args, e.fp.read()))
96
97 class Twitter(TwitterCall):
98 """
99 The minimalist yet fully featured Twitter API class.
100
101 Get RESTful data by accessing members of this class. The result
102 is decoded python objects (lists and dicts).
103
104 The Twitter API is documented here:
105
106 http://apiwiki.twitter.com/
107 http://groups.google.com/group/twitter-development-talk/web/api-documentation
108
109 Examples::
110
111 twitter = Twitter("hello@foo.com", "password123")
112
113 # Get the public timeline
114 twitter.statuses.public_timeline()
115
116 # Get a particular friend's timeline
117 twitter.statuses.friends_timeline(id="billybob")
118
119 # Also supported (but totally weird)
120 twitter.statuses.friends_timeline.billybob()
121
122 # Send a direct message
123 twitter.direct_messages.new(
124 user="billybob",
125 text="I think yer swell!")
126
127 Searching Twitter::
128
129 twitter_search = Twitter(domain="search.twitter.com")
130
131 # Find the latest search trends
132 twitter_search.trends()
133
134 # Search for the latest News on #gaza
135 twitter_search.search(q="#gaza")
136
137 Using the data returned::
138
139 Twitter API calls return decoded JSON. This is converted into
140 a bunch of Python lists, dicts, ints, and strings. For example,
141
142 x = twitter.statuses.public_timeline()
143
144 # The first 'tweet' in the timeline
145 x[0]
146
147 # The screen name of the user who wrote the first 'tweet'
148 x[0]['user']['screen_name']
149
150 Getting raw XML data::
151
152 If you prefer to get your Twitter data in XML format, pass
153 format="xml" to the Twitter object when you instantiate it:
154
155 twitter = Twitter(format="xml")
156
157 The output will not be parsed in any way. It will be a raw string
158 of XML.
159 """
160 def __init__(
161 self, email=None, password=None, format="json", domain="twitter.com",
162 agent=None, secure=True, auth=None):
163 """
164 Create a new twitter API connector using the specified
165 credentials (email and password). Format specifies the output
166 format ("json" (default) or "xml").
167 """
168
169 if email is not None or password is not None:
170 if auth is not None:
171 raise ValueError, "can't specify 'email' or 'password' and 'auth' params"
172 auth = UserPassAuth(email, password)
173
174 if not auth:
175 auth = NoAuth()
176
177 if (format not in ("json", "xml")):
178 raise TwitterError("Unknown data format '%s'" %(format))
179 TwitterCall.__init__(
180 self, auth, format, domain, "", agent,
181 secure=secure)
182
183 __all__ = ["Twitter", "TwitterError"]