Skip to content

Commit

Permalink
Add documentation for the MultipartEncoderMonitor
Browse files Browse the repository at this point in the history
Add the classmethod `from_fields` to simplify the typical pattern
  • Loading branch information
sigmavirus24 committed May 18, 2014
1 parent 13608d1 commit 4f624df
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
61 changes: 61 additions & 0 deletions docs/user.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,69 @@ This method renders the multipart body into a string. This is useful when
developing your code, allowing you to confirm that the multipart body has the
form you expect before you send it on.

The ``toolbelt`` also provides a way to monitor your streaming uploads with
the ``MultipartEncoderMonitor``.

.. _support for multipart uploads: http://docs.python-requests.org/en/latest/user/quickstart/#post-a-multipart-encoded-file

Monitoring Your Streaming Upload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you need to stream your ``multipart/form-data`` upload then you're probably
in the situation where it might take a while to upload the content. In these
cases, it might make sense to be able to monitor the progress of the upload.
For this reason, the toolbelt provides the ``MultipartEncoderMonitor``. The
monitor wraps an instance of a ``MultipartEncoder`` and is used exactly like
the encoder. It provides a similar API with some additions:

- The monitor accepts a function as a callback. The function is called every
time ``requests`` calls ``read`` on the monitor and passes in the monitor as
an argument.

- The monitor tracks how many bytes have been read in the course of the
upload.

You might use the monitor to create a progress bar for the upload. Here is `an
example using clint`_ which displays the progress bar.

To use the monitor you would follow a pattern like this::

from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
import requests

def my_callback(monitor):
# Your callback function
pass

e = MultipartEncoder(
fields={'field0': 'value', 'field1': 'value',
'field2': ('filename', open('file.py', 'rb'), 'text/plain')}
)
m = MultipartEncoderMonitor(e, my_callback)

r = requests.post('http://httpbin.org/post', data=m,
headers={'Content-Type': m.content_type})

If you have a very simple use case you can also do::

from requests_toolbelt import MultipartEncoderMonitor
import requests

def my_callback(monitor):
# Your callback function
pass

m = MultipartEncoderMonitor.from_fields(
fields={'field0': 'value', 'field1': 'value',
'field2': ('filename', open('file.py', 'rb'), 'text/plain')},
callback=my_callback
)

r = requests.post('http://httpbin.org/post', data=m,
headers={'Content-Type': m.content_type})


.. _example using clint: https://gitlab.com/sigmavirus24/toolbelt/blob/master/examples/monitor/progress_bar.py

User-Agent Constructor
----------------------
Expand Down
25 changes: 25 additions & 0 deletions requests_toolbelt/multipart/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,25 @@ def callback(encoder, bytes_read):
r = requests.post('https://httpbin.org/post', data=monitor,
headers=headers)
Alternatively, if your use case is very simple, you can use the following
pattern.
.. code-block:: python
from requests_toolbelt import MultipartEncoderMonitor
import requests
def callback(encoder, bytes_read):
# Do something with this information
pass
monitor = MultipartEncoderMonitor.from_fields(
fields={'field0': 'value0'}, callback
)
headers = {'Content-Type': montior.content_type}
r = requests.post('https://httpbin.org/post', data=monitor,
headers=headers)
"""

def __init__(self, encoder, callback=None):
Expand All @@ -272,6 +291,12 @@ def __init__(self, encoder, callback=None):
def __len__(self):
return len(self.encoder)

@classmethod
def from_fields(cls, fields, boundary=None, encoding='utf-8',
callback=None):
encoder = MultipartEncoder(fields, boundary, encoding)
return cls(encoder, callback)

@property
def content_type(self):
return self.encoder.content_type
Expand Down
8 changes: 8 additions & 0 deletions tests/test_multipart_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ def test_default_callable_is_the_identity(self):
assert self.monitor.callback == IDENTITY
assert IDENTITY(1) == 1

def test_from_fields(self):
monitor = MultipartEncoderMonitor.from_fields(
self.fields, self.boundary
)
assert isinstance(monitor, MultipartEncoderMonitor)
assert isinstance(monitor.encoder, MultipartEncoder)
assert monitor.encoder.boundary_value == self.boundary


class Callback(object):
def __init__(self, monitor):
Expand Down

0 comments on commit 4f624df

Please sign in to comment.