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