Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

requests - how to stream upload - partial file

My goal is to do a PUT of part of a file using requests and stream the file (i.e., not load it into memory and then do the PUT).

This page explains how you would do that for an entire file:

Requests supports streaming uploads, which allow you to send large streams or files without reading them into memory. To stream and upload, simply provide a file-like object for your body:

with open('massive-body', 'rb') as f:
    requests.post('http://some.url/streamed', data=f)

However in my case I want to only send one chunk of the file. Is there a way to accomplish this?

In concept, something like:

with open('massive-body', 'rb') as f:
    requests.post('http://some.url/streamed', data=f.read(chunksize))
like image 812
Greg Avatar asked Apr 21 '15 14:04

Greg


People also ask

How do I send a file through http request?

If you want to send the file as the only content then you can directly add it as the request body and you set the Content-Type header to the MIME type of the file you are sending. The file name can be added in the Content-Disposition header.

How do you upload multiple files in Python?

Run the Application by running “python multiplefilesupload.py”. Go to browser and type “http://localhost:5000”, you will see “upload files” in browser.

How do you upload a file in Python?

Method 1: Using the Python's os Module: Also, the enctype attribute with "multi-part/form-data" value will help the HTML form to upload a file. Lastly, we need the input tag with the filename attribute to upload the file we want. Lastly, we need the input tag with the filename attribute to upload the file we want.


1 Answers

Based off Greg's answers to my questions I think the following will work best:

First you'll need something to wrap your open file so that it limits how much data can be read:

class FileLimiter(object):
    def __init__(self, file_obj, read_limit):
        self.read_limit = read_limit
        self.amount_seen = 0
        self.file_obj = file_obj

        # So that requests doesn't try to chunk the upload but will instead stream it:
        self.len = read_limit

    def read(self, amount=-1):
        if self.amount_seen >= self.read_limit:
            return b''
        remaining_amount = self.read_limit - self.amount_seen
        data = self.file_obj.read(min(amount, remaining_amount))
        self.amount_seen += len(data)
        return data

This should roughly work as a good wrapper object. Then you would use it like so:

 with open('my_large_file', 'rb') as file_obj:
     file_obj.seek(my_offset)
     upload = FileLimiter(file_obj, my_chunk_limit)
     r = requests.post(url, data=upload, headers={'Content-Type': 'application/octet-stream'})

The headers are obviously optional, but when streaming data to a server, it's a good idea to be a considerate user and tell the server what the type of the content is that you're sending.

like image 160
Ian Stapleton Cordasco Avatar answered Oct 12 '22 12:10

Ian Stapleton Cordasco