2
2
# -*- coding: utf-8 -*-
3
3
'''
4
4
AppEngine-Twitter
5
-
5
+
6
6
Twitter API wrapper for applications on Google App Engine
7
-
7
+
8
8
See: http://0-oo.net/sbox/python-box/appengine-twitter
9
9
License: http://0-oo.net/pryn/MIT_license.txt (The MIT license)
10
-
10
+
11
11
See also:
12
12
http://apiwiki.twitter.com/Twitter-API-Documentation
13
13
http://code.google.com/intl/ja/appengine/docs/python/urlfetch/
14
14
'''
15
-
15
+
16
16
17
17
__version__ = '0.1.0'
18
-
19
-
18
+
19
+
20
20
import base64
21
21
import urllib
22
22
from appengine_oauth import AppEngineOAuth
23
23
from django .utils import simplejson
24
24
from google .appengine .api import urlfetch
25
-
26
-
25
+
26
+
27
27
class AppEngineTwitter (object ):
28
-
28
+
29
29
def __init__ (self , tw_name = '' , tw_pswd = '' ):
30
30
'''
31
31
Note: Some actions require password or OAuth.
32
32
'''
33
33
self ._api_url = 'https://twitter.com'
34
34
self ._search_url = 'http://search.twitter.com'
35
-
35
+
36
36
self .tw_name = tw_name
37
37
self ._oauth = None
38
-
38
+
39
39
self ._headers = {}
40
40
if tw_pswd != '' :
41
41
auth = base64 .encodestring (tw_name + ':' + tw_pswd )[:- 1 ]
42
42
self ._headers ['Authorization' ] = 'Basic ' + auth
43
-
44
-
43
+
44
+
45
45
def update (self , message ):
46
46
'''
47
47
Post a tweet
48
48
Sucess => Retrun 200 / Fialed => Return other HTTP status
49
49
'''
50
50
return self ._post ('/statuses/update.json' , {'status' : message })
51
-
52
-
51
+
52
+ # ref : https://dev.twitter.com/docs/api/1/post/statuses/retweet/%3Aid
53
+ def retweet (self , id ):
54
+ '''
55
+ Post a tweet
56
+ Sucess => Retrun 200 / Fialed => Return other HTTP status
57
+ '''
58
+ return self ._post ('/statuses/retweet/' + id + '.json' , {})
59
+
60
+
53
61
def follow (self , target_name ):
54
62
'''
55
63
Sucess => Return 200 / Already following => Return 403 /
56
64
Fialed => Return other HTTP status
57
65
'''
58
66
return self ._post ('/friendships/create.json' , {'screen_name' : target_name })
59
-
60
-
67
+
68
+
61
69
def is_following (self , target_name ):
62
70
'''
63
71
Yes => Return True / No => Return False /
@@ -68,61 +76,61 @@ def is_following(self, target_name):
68
76
self .verify ()
69
77
user_info = simplejson .loads (self .last_response .content )
70
78
self .tw_name = user_info ['screen_name' ]
71
-
79
+
72
80
status = self ._get ('/friendships/exists.json' ,
73
81
{'user_a' : self .tw_name , 'user_b' : target_name })
74
82
if status == 200 :
75
83
return (self .last_response .content == 'true' )
76
84
else :
77
85
return status
78
-
79
-
86
+
87
+
80
88
def verify (self ):
81
89
'''
82
90
Verify user_name and password, and get user info
83
91
Sucess => Return 200 / Fialed => Return other HTTP status
84
92
'''
85
93
return self ._get ('/account/verify_credentials.json' , {})
86
-
87
-
94
+
95
+
88
96
def search (self , keyword , params = {}):
89
97
'''
90
98
Sucess => Return Array of dict / Fialed => Return HTTP status except 200
91
99
'''
92
100
params ['q' ] = keyword
93
101
return self ._search ('/search.json' , params )
94
-
95
-
102
+
103
+
96
104
# OAuth methods
97
105
# (See http://0-oo.net/sbox/python-box/appengine-oauth )
98
-
106
+
99
107
def set_oauth (self , key , secret , acs_token = '' , acs_token_secret = '' ):
100
108
'''
101
109
Set OAuth parameters
102
110
'''
103
111
self ._oauth = AppEngineOAuth (key , secret , acs_token , acs_token_secret )
104
-
105
-
112
+
113
+
106
114
def prepare_oauth_login (self ):
107
115
'''
108
116
Get request token, request token secret and login URL
109
117
'''
110
118
dic = self ._oauth .prepare_login (self ._api_url + '/oauth/request_token/' )
111
119
dic ['url' ] = self ._api_url + '/oauth/authorize?' + dic ['params' ]
112
120
return dic
113
-
114
-
121
+
122
+
115
123
def exchange_oauth_tokens (self , req_token , req_token_secret ):
116
124
'''
117
125
Exchange request token for access token
118
126
'''
119
127
return self ._oauth .exchange_tokens (self ._api_url + '/oauth/access_token/' ,
120
128
req_token ,
121
129
req_token_secret )
122
-
123
-
130
+
131
+
124
132
# Private methods
125
-
133
+
126
134
def _post (self , path , params ):
127
135
url = self ._api_url + path
128
136
if self ._oauth != None :
@@ -133,8 +141,8 @@ def _post(self, path, params):
133
141
headers = self ._headers )
134
142
self .last_response = res
135
143
return res .status_code
136
-
137
-
144
+
145
+
138
146
def _get (self , path , params ):
139
147
url = self ._api_url + path
140
148
if self ._oauth != None :
@@ -143,21 +151,20 @@ def _get(self, path, params):
143
151
res = urlfetch .fetch (url = url , method = 'GET' , headers = self ._headers )
144
152
self .last_response = res
145
153
return res .status_code
146
-
147
-
154
+
155
+
148
156
def _search (self , path , params ):
149
157
'''
150
158
FYI http://apiwiki.twitter.com/Rate-limiting (Especially 503 error)
151
159
'''
152
160
url = url = self ._search_url + path + '?' + urllib .urlencode (params )
153
161
res = urlfetch .fetch (url = url , method = 'GET' )
154
162
self .last_response = res
155
-
163
+
156
164
if res .status_code == 200 :
157
165
return simplejson .loads (res .content )['results' ]
158
166
elif res .status_code == 503 :
159
167
err_msg = 'Rate Limiting: Retry After ' + res .headers ['Retry-After' ]
160
168
else :
161
169
err_msg = 'Error: HTTP Status is ' + str (res .status_code )
162
-
163
170
raise Exception ('Twitter Search API ' + err_msg )
0 commit comments