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