sookasa / box.py Goto Github PK
View Code? Open in Web Editor NEWPython client for Box
Python client for Box
Hi,
I should probably do a pull request for this one, but I haven't cloned this repository "properly" yet (new to the whole git thing). I've just been modifying a local copy of client.py as needed.
So, to the point: I think the upload_file function should have a content_modified_at argument, same as the overwrite_file function. This could be important in any bi-directional sync type scenario, where it is important to keep the remote file's "last modified" time the same as that of the one uploaded so that a decision about the sync direction could be made in the future.
I can do a proper pull request for this if necessary. Just let me know how :)
Thanks.
grequests can be dropped in for asynchronous API requests with gevent:
sprin/box.py@1cb1c30
You probably don't want to drag gevent/grequests in as a hard deps, but perhaps grequests can be imported conditionally?
This change enabled me do recursive operations almost two orders of magnitude faster, eventually running into rate-limiting. However, the pool can be used to limit the number of concurrent requests to avoid rate-limiting.
Here is recursive folder walking and folder creation done asynchronously.
Aside: If the those recursive functions are of interest to integrate into box.py, I'd be happy to make it more general and provide tests.
Especially for moving file to another directory and renaming, but other options (like description and tags) shouldn't hurt as well: http://developers.box.com/docs/#files-update-a-files-information
It almost like sharing a file, so shouldn't be hard to implement. Or I can try to send a patch (if we decided to use your library in our project instead of our own implementation). Thanks anyway.
I am having some troubles retrieving a file's thumbnail
the get_thumbnail function return the raw field of the server's response and I couldn't find a way to get its content. the read() method doesn't return anything even with a specified length and a call to the data field neither.
The only workaround I have found so far is to return the complete response object in get_thumbnail so I can get the thumbnail using the content or text fields.
Am I missing something about this function usage ?
Hi,
So, I'm unsure yet if this is actually an issue, but here goes. I'm kinda new to working with HTTP requests and downloading stuff etc. I was trying to figure out how to download large files in a "somewhat-non-blocking" fashion so that I can have a progress bar and I stumbled onto this page (http://www.python-requests.org/en/latest/user/quickstart/?highlight=iter_content). I was able to do what I needed by using the raw response example given, but the page suggests that using Response.iter_content on the "not-raw" response is better (I imagine it does error checking but I'm not sure).
The download_file function returns a raw, but I changed my local copy of client.py so that it doesn't and I can use the iter_content method for downloading files. Would it make sense to add an option to the function so that it can return either? Also, what are the advantages for using iter_content?
Thanks.
As I understand it, the v1 API is no longer available:
http://developers.blog.box.com/2013/12/06/one-week-until-the-deadline-for-deprecating-v1-of-the-api/
It would be very nice to drop the now-useless v1 functions, since this package requires lxml just for these functions.
The share_link() method is working when access=ShareAccess.OPEN. However when access=ShareAccess. COLLABORATORS, it is giving status 400
{"type":"error","status":400,"code":"bad_request","context_info":{"errors":[{"reason":"invalid_parameter","name":"shared_link_permissions","message":"Invalid value 'download => 1'."}]}
When I run the "upload" example from the README:
>>> from box import BoxClient
>>> from StringIO import StringIO
>>> client = BoxClient('<valid access token>')
>>> client.upload_file('hello.txt', StringIO('hello world'))
The following traceback is thrown:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/lib/python2.7/site-packages/box/client.py", line 531, in upload_file
result = self._request("post", "files/content", endpoint="upload", data=form, files={filename: fileobj})
File "/lib/python2.7/site-packages/box/client.py", line 304, in _request
response = requests.request(method, url, params=params, data=data, headers=headers, **kwargs)
File "/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/sessions.py", line 324, in request
prep = req.prepare()
File "/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 225, in prepare
p.prepare_body(self.data, self.files)
File "/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 385, in prepare_body
(body, content_type) = self._encode_files(files, data)
File "/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 99, in _encode_files
fields = to_key_val_list(data or {})
File "/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/utils.py", line 136, in to_key_val_list
raise ValueError('cannot encode objects that are not 2-tuples')
ValueError: cannot encode objects that are not 2-tuples
Using the example code provided here, I am attempting to test the long poll functionality. I keep getting the following error:
Traceback (most recent call last):
File "box_long_poll.py", line 5, in <module>
position = client.long_poll_for_events() # this will block until there are new events
File "/usr/local/lib/python2.7/dist-packages/box/client.py", line 694, in long_poll_for_events
stream_position = cursor['next_stream_position']
TypeError: 'Response' object has no attribute '__getitem__'
Here is a trace (upload_file executed via box.py) that fails with "status":400,"code":"invalid_request_parameters":
POST /api/2.0/files/content HTTP/1.1
Host: upload.box.com
Content-Length: 47237
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/2.2.1 CPython/2.7.5 Darwin/13.1.0
Content-Type: multipart/form-data; boundary=c5a8408bda51429ba5871377731fc678
Authorization: Bearer ACCESS_TOKEN
--c5a8408bda51429ba5871377731fc678
Content-Disposition: form-data; name="parent_id"
1673257278
--c5a8408bda51429ba5871377731fc678
Content-Disposition: form-data; name*=utf-8''S%C3%A9vigny.pdf; filename*=utf-8''S%C3%A9vigny.pdf
Here is a trace from an equivalent openration via curl:
0000: POST /api/2.0/files/content HTTP/1.1
0026: User-Agent: curl/7.30.0
003f: Host: upload.box.com
0055: Accept: */*
0062: Authorization: Bearer ACCESS_TOKEN
009a: Content-Length: 43177
00b1: Expect: 100-continue
00c7: Content-Type: multipart/form-data; boundary=--------------------
0107: --------37edc5e8d7c9
011d:
<= Recv header, 23 bytes (0x17)
0000: HTTP/1.1 100 Continue
=> Send data, 161 bytes (0xa1)
0000: ------------------------------37edc5e8d7c9
002c: Content-Disposition: form-data; name="filename"; filename="Se..v
006c: igny.pdf"
0077: Content-Type: application/octet-stream
009f:
=> Send data, 16384 bytes (0x4000)
Seems Box Content API is not liking RFC 2231-encoded file names. More related discussion on this. And a hack-around?
I'm not sure yet what to tell requests library to send filename unencoded.
I have an issue with authenticating the user using the 'finish_authenticate_v2' function. Specifically, 'request.REQUEST['code']' is not working. What library are you importing? Assuming the library is imported correctly, will the 'code' from the url redirection be transferred automatically to request.REQUEST['code']?
Currently, if I replace request.REQUEST['code'] with the actual code, I can get obtain my access token. However, I do not want to hardcode anything.
I am terribly new at this, sorry if this is such an easy problem.
I have an stackoverflow post as well: http://stackoverflow.com/questions/20339261/how-to-grab-the-authorization-code-from-url-to-get-token-in-box-using-python/20339480?noredirect=1#20339480
According to the documentation, deletion API will return a "empty 204 response", thus without raw=True
, response.json()
from client._request
raises exception.
JSONDecodeError: No JSON object could be decoded: line 1 column 0 (char 0)
The delete_folder
API does issue a raw=True
request, but delete_file
doesn't.
def delete_file(self, file_id, etag=None):
"""
Discards a file to the trash.
Args:
- etag: (optional) If specified, the file will only be deleted if
its etag matches the parameter
"""
headers = {}
if etag:
headers['If-Match'] = etag
self._request("delete", 'files/{}'.format(file_id), headers=headers)
I'd like to fix this, actually I've cloned this repo. But I want to do more. So I look into the test cases, found that mocked_response
might "mocked" too much, I mean it just assume we always can get a valid response from the API server, when there is no content available, we assume None
returned. But that's not the real case. Empty content is not accepted by both json or simplejson.
So I patched a little
diff --git a/tests/__init__.py b/tests/__init__.py
index eb87755..ab2f2ce 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,5 +1,9 @@
from StringIO import StringIO
from datetime import tzinfo, timedelta, datetime
+try:
+ import simplejson as json
+except:
+ import json as json
from flexmock import flexmock
@@ -45,4 +49,9 @@ utc = UTC()
def mocked_response(content=None, status_code=200, headers=None):
- return flexmock(ok=status_code < 400, status_code=status_code, json=lambda: content, raw=content, text=content, headers=headers)
+ if content is None:
+ content = ''
+ if not isinstance(content, basestring):
+ content = json.dumps(content)
+
+ return flexmock(ok=status_code < 400, status_code=status_code, json=lambda: json.loads(content), raw=content, text=content, headers=headers)
Of cause some cases are broken, and some of them should be. But some broken ones like
def test_get(self):
client = self.make_client("get", "foo", params={'arg': 'value'}, crap=1)
client._request('get', 'foo', {'arg': 'value'}, crap=1)
def test_post_dict(self):
expected_data = {'arg': 'value'}
client = self.make_client("post", "foo", data=expected_data, crap=1)
actual_response = client._request('post', 'foo', data=expected_data, crap=1)
self.assertEqual(None, actual_response)
def test_post_data(self):
expected_data = "mooooo"
client = self.make_client("post", "foo", data=expected_data, crap=1)
actual_response = client._request('post', 'foo', data=expected_data, crap=1)
self.assertEqual(None, actual_response)
def test_put_dict(self):
expected_data = {'arg': 'value'}
client = self.make_client("put", "foo", data=expected_data, crap=1)
actual_response = client._request('put', 'foo', data=expected_data, crap=1)
self.assertEqual(None, actual_response)
I just don't get why we need these cases, which issuing non-exist API path "foo". It won't be hard to just look through the source code and patch raw=True
if needed, but I think we better make these test cases more robust.
Which way should we take to fix this problem? Simply add raw=True
?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.