Я немного соврал (в том смысле, что готовых средств в питоне нет), но совсем немного:) Есть способ заэнкодить данные для аплоада файлов стандартными библиотеками, сам с этим сейчас начинаю работать, поэтому даже есть некоторый пример, который можно модифицировать под свои нужды (не идеал конечно, мне нужен был просто proof of concept для начала):
import os
from email import encoders
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
FILE = '/home/user/scripts/toonel.jar'
msg = MIMEMultipart(_subtype='form-data')
part = MIMEText('joCl96XEXhfW2AU54TrblablablaNieWixd7MfUpPgB1nZViA=')
part.add_header('Content-Disposition', 'form-data', name='authenticity_token')
msg.attach(part)
# attaching file to the message
name, file_name, stream = 'file', os.path.basename(FILE), open(FILE, 'rb')
part = MIMEBase('application', 'octet-stream')
part.add_header('Content-Disposition', 'form-data', name=name,
filename=file_name)
part.set_payload(stream.read())
encoders.encode_base64(part)
msg.attach(part)
# msg._write_headers is a headers writer handler, we don't want to output
# headers with the body, so we are doing None here
msg._write_headers = lambda self: None
# at first we should get the body of the message and only afterwards we are
# getting headers with "boundary" in Content-Type header. This header is
# generated after message body building from given parts.
body = '\r\n'.join(msg.as_string().splitlines()) + '\r\n'
headers = dict(msg)
import urllib2
request = urllib2.Request('http://localhost:8000/', body, headers)
urllib2.urlopen(request)