1
- from netrc import netrc
2
1
import os
3
2
import re
3
+ import shutil
4
4
import time
5
5
import urllib
6
+
7
+ from netrc import netrc
6
8
try :
7
9
import urlparse
8
10
# Fixed pyflakes warning...
9
11
urlparse
10
12
except ImportError :
11
13
from urllib import parse as urlparse
12
14
13
-
14
15
import requests
15
16
from requests .exceptions import RequestException
16
17
@@ -54,7 +55,8 @@ def _do_request(self, request, url, **kwargs):
54
55
else :
55
56
if response .status_code >= 400 :
56
57
raise ResponseError (response )
57
- # Try to return the response in the most useful fashion given it's type.
58
+ # Try to return the response in the most useful fashion given it's
59
+ # type.
58
60
if response .headers .get ('content-type' ) == 'application/json' :
59
61
try :
60
62
# Try to decode as JSON
@@ -94,18 +96,21 @@ def _request(self, method, endpoint, id=None, **kwargs):
94
96
path = path .replace ('//' , '/' )
95
97
url = self .url + path
96
98
# Add our user agent.
97
- kwargs .setdefault ('headers' , {}).setdefault ('User-Agent' , HTTP_USER_AGENT )
99
+ kwargs .setdefault ('headers' , {}).setdefault ('User-Agent' ,
100
+ HTTP_USER_AGENT )
98
101
# Now try the request, if we get throttled, sleep and try again.
99
102
trys , retrys = 0 , 3
100
103
while True :
101
104
if trys == retrys :
102
- raise RequestError ('Could not complete request after %s trys.' % trys )
105
+ raise RequestError ('Could not complete request after %s trys.'
106
+ % trys )
103
107
trys += 1
104
108
try :
105
109
return self ._do_request (request , url , ** kwargs )
106
110
except ResponseError as e :
107
111
if self .throttle_wait and e .status_code == 503 :
108
- m = THROTTLE_PATTERN .match (e .response .headers .get ('x-throttle' , '' ))
112
+ m = THROTTLE_PATTERN .match (
113
+ e .response .headers .get ('x-throttle' , '' ))
109
114
if m :
110
115
time .sleep (float (m .group (1 )))
111
116
continue
@@ -127,6 +132,42 @@ def post(self, endpoint, id=None, **kwargs):
127
132
def delete (self , endpoint , id = None , ** kwargs ):
128
133
return self ._request ('delete' , endpoint , id = id , data = kwargs )
129
134
135
+ def remove (self , deletefile ):
136
+ try :
137
+ return self .post ('/path/oper/remove' , path = deletefile )
138
+ except KeyError :
139
+ raise Exception ("Destination file does not exist" )
140
+
141
+ def upload (self , filename , fileobj ):
142
+ if filename .endswith ('/' ):
143
+ filename = filename [:- 1 ]
144
+ arg = (filename , fileobj )
145
+ return self .post ('/path/data/' , file = arg )
146
+
147
+ def download (self , file_to_be_downloaded ):
148
+ """ file_to_be_downloaded is a file-like object that has already
149
+ been uploaded, you cannot download folders """
150
+ # download uses shutil.copyfileobj to download, which copies
151
+ # the data in chunks
152
+ o = open (file_to_be_downloaded , 'wb' )
153
+ return shutil .copyfileobj (self .get ('/path/data/' ,
154
+ file_to_be_downloaded ), o )
155
+
156
+ def move (self , src_path , dst_path ):
157
+ # check destination folder for / at end
158
+ if not src_path .endswith ("/" ):
159
+ src_path = src_path + "/"
160
+ # check destination folder for / at begining
161
+ if not src_path .startswith ("/" ):
162
+ src_path = "/" + src_path
163
+ # check destination folder for / at end
164
+ if not dst_path .endswith ("/" ):
165
+ dst_path = dst_path + "/"
166
+ # check destination folder for / at begining
167
+ if not dst_path .startswith ("/" ):
168
+ dst_path = "/" + dst_path
169
+ return self .post ('/path/oper/move/' , src = src_path , dst = dst_path )
170
+
130
171
131
172
class BasicClient (Client ):
132
173
"""API client that uses a key and password. Layers a simple form of
@@ -193,10 +234,11 @@ def is_valid(self):
193
234
return False
194
235
195
236
class OAuthClient (Client ):
196
- """API client that uses OAuth tokens. Layers a more complex form of
197
- authentication useful for 3rd party access on top of the base Client."""
198
- def __init__ (self , client_token = None , client_secret = None , access_token = None ,
199
- access_secret = None , ** kwargs ):
237
+ """API client that uses OAuth tokens. Layers a more complex
238
+ form of authentication useful for 3rd party access on top of
239
+ the base Client."""
240
+ def __init__ (self , client_token = None , client_secret = None ,
241
+ access_token = None , access_secret = None , ** kwargs ):
200
242
if client_token is None :
201
243
client_token = os .environ .get ('SMARTFILE_CLIENT_TOKEN' )
202
244
if client_secret is None :
@@ -207,15 +249,15 @@ def __init__(self, client_token=None, client_secret=None, access_token=None,
207
249
access_secret = os .environ .get ('SMARTFILE_ACCESS_SECRET' )
208
250
self ._client = OAuthToken (client_token , client_secret )
209
251
if not self ._client .is_valid ():
210
- raise APIError ('You must provide a client_token and client_secret '
211
- 'for OAuth.' )
252
+ raise APIError ('You must provide a client_token'
253
+ 'and client_secret for OAuth.' )
212
254
self ._access = OAuthToken (access_token , access_secret )
213
255
super (OAuthClient , self ).__init__ (** kwargs )
214
256
215
257
def _do_request (self , * args , ** kwargs ):
216
258
if not self ._access .is_valid ():
217
- raise APIError ('You must obtain an access token before making API '
218
- 'calls.' )
259
+ raise APIError ('You must obtain an access token'
260
+ 'before making API calls.' )
219
261
# Add the OAuth parameters.
220
262
kwargs ['auth' ] = OAuth1 (self ._client .token ,
221
263
client_secret = self ._client .secret ,
@@ -230,26 +272,29 @@ def get_request_token(self, callback=None):
230
272
client_secret = self ._client .secret ,
231
273
callback_uri = callback ,
232
274
signature_method = SIGNATURE_PLAINTEXT )
233
- r = requests .post (urlparse .urljoin (self .url , 'oauth/request_token/' ), auth = oauth )
275
+ r = requests .post (urlparse .urljoin (
276
+ self .url , 'oauth/request_token/' ), auth = oauth )
234
277
credentials = urlparse .parse_qs (r .text )
235
278
self .__request = OAuthToken (credentials .get ('oauth_token' )[0 ],
236
- credentials .get ('oauth_token_secret' )[0 ])
279
+ credentials .get (
280
+ 'oauth_token_secret' )[0 ])
237
281
return self .__request
238
282
239
283
def get_authorization_url (self , request = None ):
240
284
"The second step of the OAuth workflow."
241
285
if request is None :
242
286
if not self .__request .is_valid ():
243
- raise APIError ('You must obtain a request token to request '
244
- 'and access token. Use get_request_token() '
245
- 'first.' )
287
+ raise APIError ('You must obtain a request token to'
288
+ 'request and access token. Use'
289
+ 'get_request_token() first.' )
246
290
request = self .__request
247
291
url = urlparse .urljoin (self .url , 'oauth/authorize/' )
248
- return url + '?' + urllib .urlencode (dict (oauth_token = request .token ))
292
+ return url + '?' + urllib .urlencode (
293
+ dict (oauth_token = request .token ))
249
294
250
295
def get_access_token (self , request = None , verifier = None ):
251
- """The final step of the OAuth workflow. After this the client can make
252
- API calls."""
296
+ """The final step of the OAuth workflow. After this the client
297
+ can make API calls."""
253
298
if request is None :
254
299
if not self .__request .is_valid ():
255
300
raise APIError ('You must obtain a request token to request '
@@ -262,7 +307,8 @@ def get_access_token(self, request=None, verifier=None):
262
307
resource_owner_secret = request .secret ,
263
308
verifier = verifier ,
264
309
signature_method = SIGNATURE_PLAINTEXT )
265
- r = requests .post (urlparse .urljoin (self .url , 'oauth/access_token/' ), auth = oauth )
310
+ r = requests .post (urlparse .urljoin (
311
+ self .url , 'oauth/access_token/' ), auth = oauth )
266
312
credentials = urlparse .parse_qs (r .text )
267
313
self ._access = OAuthToken (credentials .get ('oauth_token' )[0 ],
268
314
credentials .get ('oauth_token_secret' )[0 ])
0 commit comments