Where is mimetools.choose_boundary function in Python3?
Question: I currently want to use the following piece of code in Python3, but found the
function `mimetools.choose_boundary` to be deprecated, how to change the code
and make it works?

    
    
    import re
    from urllib.request import urlopen, Request
    import os 
    import mimetypes 
    import mimetools 
    
    def get_content_type(filepath): 
        return mimetypes.guess_type(filepath)[0] or 'application/octet-stream' 
    
    def encode_multipart_formdata(fields, files=[]): 
        """
        fields is a sequence of (name, value) elements for regular form fields.
        files is a sequence of (name, filepath) elements for data to be uploaded as files
        Return (content_type, body) ready for httplib.HTTP instance
        """ 
        BOUNDARY = mimetools.choose_boundary() 
        CRLF = '\r\n' 
        L = [] 
        for (key, value) in fields: 
            L.append('--' + BOUNDARY) 
            L.append('Content-Disposition: form-data; name="%s"' % key) 
            L.append('') 
            L.append(value) 
        for (key, filepath) in files: 
            L.append('--' + BOUNDARY) 
            L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, os.path.basename(filepath))) 
            L.append('Content-Type: %s' % get_content_type(filepath)) 
            L.append('') 
            L.append(open(filepath, 'rb').read()) 
        L.append('--' + BOUNDARY + '--') 
        L.append('') 
        body = CRLF.join(L) 
        content_type = 'multipart/form-data; boundary=%s' % BOUNDARY 
        return content_type, body 
    


Answer: Well, I answer my question since no other available answer here.

Yes, I got the result finally, for more info about my work around the
question, the below information may help.

* * *

### 1\. What does `boundary` do in an `multipart/form-data` request?

In fact, to separate the different parts of data is such a request, we use a
separator, here we call `boundary`, to divide the form data.

These parts may be field value _(plain text)_ , or uploading file contents.

### 2\. First we put the boundary string in the request header.

To claim a request to be accepted as a `mulitipart/form-data` format, we first
choose a special string, called `boundary`, and put it in the request header:

    
    
    Content-Type: multipart/form-data; boundary=FORM-BOUNDARY
    

Seeing that we choose the boundary string to be `FORM-BOUNDARY` here, in fact
we can choose any string we want.

Most time we may choose a long, randomly string, to prevent collision.

### 3\. Use the chosen boundary in the request body.

In the request body _(payload)_ , we separate the data with the `boundary`
separator, for example:

    
    
    --FORM-BOUNDARY
    Content-Disposition: form-data; name="template"; filename=".xls"
    Content-Type: application/vnd.ms-excel
    
    A654ADE5^%^#%@%$@ (BINARY DATA IN THIS SECTION)
    --FORM-BOUNDARY
    Content-Disposition: form-data; name="username"
    
    admin
    --FORM-BOUNDARY
    Content-Disposition: form-data; name="password"
    
    admin_password
    --FORM-BOUNDARY--
    

Seeing that, we start one form-part with a separator, with the `boundary`
after a single `--` symbol.

Then in that form-part, we export the header to claim the content type and the
name of that posted field.

Then a single blank line is required.

Then we export the value(data) of that form-part.

After all form-parts, we ended the request body with a separator, with the
`boundary` between two `--` symbol.

### 4\. So what does `mimetools.choose_boundary` do then?

In fact, this function (deprecated since py3) generate a random boundary, with
a specified format, see:
<https://docs.python.org/2.7/library/mimetools.html?highlight=choose_boundary#mimetools.choose_boundary>

The format is:

    
    
    'hostipaddr.uid.pid.timestamp.random'
    

Just that simple.

If we insist on getting the same result,

  1. we can write the functional by ourselves.
  2. Or call the `email.generator` module's `_make_boundary()` function.

> But in fact, to make it work, no need to do that, just generate a random
> string to replace it!

