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