Skip to content

Commit

Permalink
Breaking change: file upload argument must be a bytes type.
Browse files Browse the repository at this point in the history
- File-like objs are no longer accepted.
- Updated to latest Stone.
  • Loading branch information
braincore committed Oct 27, 2016
1 parent 56f2f33 commit e7ebb14
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 10 deletions.
12 changes: 6 additions & 6 deletions dropbox/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def files_alpha_upload(self,
larger than 150 MB. Instead, create an upload session with
:meth:`files_upload_session_start`.
:param f: A string or file-like obj of data.
:param bytes f: Contents to upload.
:param Nullable property_groups: List of custom properties to add to
file.
:rtype: :class:`dropbox.files.FileMetadata`
Expand Down Expand Up @@ -1190,7 +1190,7 @@ def files_upload(self,
this to upload a file larger than 150 MB. Instead, create an upload
session with :meth:`files_upload_session_start`.
:param f: A string or file-like obj of data.
:param bytes f: Contents to upload.
:param str path: Path in the user's Dropbox to save the file.
:param mode: Selects what to do if the file already exists.
:type mode: :class:`dropbox.files.WriteMode`
Expand Down Expand Up @@ -1234,7 +1234,7 @@ def files_upload_session_append(self,
Append more data to an upload session. A single request should not
upload more than 150 MB of file contents.
:param f: A string or file-like obj of data.
:param bytes f: Contents to upload.
:param str session_id: The upload session ID (returned by
:meth:`files_upload_session_start`).
:param long offset: The amount of data that has been uploaded so far. We
Expand Down Expand Up @@ -1269,7 +1269,7 @@ def files_upload_session_append_v2(self,
this call will close the session. A single request should not upload
more than 150 MB of file contents.
:param f: A string or file-like obj of data.
:param bytes f: Contents to upload.
:param cursor: Contains the upload session ID and the offset.
:type cursor: :class:`dropbox.files.UploadSessionCursor`
:param bool close: If true, the current session will be closed, at which
Expand Down Expand Up @@ -1301,7 +1301,7 @@ def files_upload_session_finish(self,
path. A single request should not upload more than 150 MB of file
contents.
:param f: A string or file-like obj of data.
:param bytes f: Contents to upload.
:param cursor: Contains the upload session ID and the offset.
:type cursor: :class:`dropbox.files.UploadSessionCursor`
:param commit: Contains the path and other optional modifiers for the
Expand Down Expand Up @@ -1390,7 +1390,7 @@ def files_upload_session_start(self,
Dropbox. A single request should not upload more than 150 MB of file
contents.
:param f: A string or file-like obj of data.
:param bytes f: Contents to upload.
:param bool close: If true, the current session will be closed, at which
point you won't be able to call
:meth:`files_upload_session_append_v2` anymore with the current
Expand Down
10 changes: 9 additions & 1 deletion dropbox/dropbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def request_json_object(self,
:param route_style: The style of the route.
:param str request_arg: A JSON-serializable Python object representing
the argument for the route.
:param request_binary: String or file pointer representing the binary
:param Optional[bytes] request_binary: Bytes representing the binary
payload. Use None if there is no binary payload.
:param Optional[float] timeout: Maximum duration in seconds
that client will wait for any single packet from the
Expand Down Expand Up @@ -376,6 +376,14 @@ def request_json_string(self,
if host not in self._host_map:
raise ValueError('Unknown value for host: %r' % host)

if not isinstance(request_binary, (six.binary_type, type(None))):
# Disallow streams and file-like objects even though the underlying
# requests library supports them. This is to prevent incorrect
# behavior when a non-rewindable stream is read from, but the
# request fails and needs to be re-tried at a later time.
raise TypeError('expected request_binary as binary type, got %s' %
type(request_binary))

# Fully qualified hostname
fq_hostname = self._host_map[host]
url = self._get_route_url(fq_hostname, func_name)
Expand Down
14 changes: 14 additions & 0 deletions dropbox/stone_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ def __init__(self, tag, value=None):
self._tag = tag
self._value = value

def __eq__(self, other):
# Also need to check if one class is a subclass of another. If one union extends another,
# the common fields should be able to be compared to each other.
return (
isinstance(other, Union) and
(isinstance(self, other.__class__) or isinstance(other, self.__class__)) and
self._tag == other._tag and self._value == other._value
)

def __ne__(self, other):
return not self == other

def __hash__(self):
return hash((self._tag, self._value))

class Route(object):

Expand Down
15 changes: 13 additions & 2 deletions test/test_dropbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
import sys
import unittest

try:
from StringIO import StringIO as BytesIO
except ImportError:
from io import BytesIO

from dropbox import (
Dropbox,
DropboxTeam,
Expand Down Expand Up @@ -45,6 +50,8 @@ def inner(*args, **kwargs):
MALFORMED_TOKEN = 'asdf'
INVALID_TOKEN = 'z' * 62

# Need bytes type for Python3
DUMMY_PAYLOAD = string.ascii_letters.encode('ascii')

class TestDropbox(unittest.TestCase):

Expand Down Expand Up @@ -80,16 +87,20 @@ def test_upload_download(self):
timestamp = str(datetime.datetime.utcnow())
random_filename = ''.join(random.sample(string.ascii_letters, 15))
random_path = '/Test/%s/%s' % (timestamp, random_filename)
test_contents = string.ascii_letters
test_contents = DUMMY_PAYLOAD
self.dbx.files_upload(test_contents, random_path)

# Download file
metadata, resp = self.dbx.files_download(random_path)
self.assertEqual(string.ascii_letters, resp.text)
self.assertEqual(DUMMY_PAYLOAD, resp.content)

# Cleanup folder
self.dbx.files_delete('/Test/%s' % timestamp)

def test_bad_upload_types(self):
with self.assertRaises(TypeError):
self.dbx.files_upload(BytesIO(b'test'), '/Test')

@require_team_token
def test_team(self, token):
dbxt = DropboxTeam(token)
Expand Down

0 comments on commit e7ebb14

Please sign in to comment.