<p dir="auto">After merge of <a href="https://github.com/kennethreitz/requests/pull/2379">https://github.com/kennethreitz/requests/pull/2379</a>, to allow filenames to be <code class="notranslate">int</code> types, unicode filenames are no longer recognized under Python 2.</p>
<p dir="auto">This checks that the filename is a <code class="notranslate">builtin</code> <code class="notranslate">str</code>, which has different behaviour on Python 2 and Python 3:<br>
<code class="notranslate">requests/utils.py:118:    if name and isinstance(name, builtin_str) and name[0] != '&lt;' and name[-1] != '&gt;':</code></p>
<p dir="auto">In <code class="notranslate">requests/compat.py</code>, <code class="notranslate">builtin_str</code> is defines as <code class="notranslate">str</code>, which is non-unicode <code class="notranslate">bytes</code> in Python 2 and unicode in Python 3. Perhaps the check should be against basestring, or is this change in behaviour intended?</p>
<p dir="auto">Starting from 2.0 requests does not send <code class="notranslate">filename</code> attribute of <code class="notranslate">Content-Disposition</code> header for multipart files with unicode names. Instead of this attribute with name <code class="notranslate">filename*</code> is sent.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# requests 1.2.3
&gt;&gt;&gt; requests.post('http://ya.ru', files={'file': (u'файл', '123')}).request.body
'--db7a9522a6344e26a4ca2933aecad887\r\nContent-Disposition: form-data; name=&quot;file&quot;; filename=&quot;\xd1\x84\xd0\xb0\xd0\xb9\xd0\xbb&quot;\r\nContent-Type: application/octet-stream\r\n\r\n123\r\n--db7a9522a6344e26a4ca2933aecad887--\r\n'

# requests 2.0
&gt;&gt;&gt; requests.post('http://ya.ru', files={'file': (u'файл', '123')}).request.body
'--a9f0de2871da46df86140bc5b72fc722\r\nContent-Disposition: form-data; name=&quot;file&quot;; filename*=utf-8\'\'%D1%84%D0%B0%D0%B9%D0%BB\r\n\r\n123\r\n--a9f0de2871da46df86140bc5b72fc722--\r\n'"><pre class="notranslate"><code class="notranslate"># requests 1.2.3
&gt;&gt;&gt; requests.post('http://ya.ru', files={'file': (u'файл', '123')}).request.body
'--db7a9522a6344e26a4ca2933aecad887\r\nContent-Disposition: form-data; name="file"; filename="\xd1\x84\xd0\xb0\xd0\xb9\xd0\xbb"\r\nContent-Type: application/octet-stream\r\n\r\n123\r\n--db7a9522a6344e26a4ca2933aecad887--\r\n'

# requests 2.0
&gt;&gt;&gt; requests.post('http://ya.ru', files={'file': (u'файл', '123')}).request.body
'--a9f0de2871da46df86140bc5b72fc722\r\nContent-Disposition: form-data; name="file"; filename*=utf-8\'\'%D1%84%D0%B0%D0%B9%D0%BB\r\n\r\n123\r\n--a9f0de2871da46df86140bc5b72fc722--\r\n'
</code></pre></div>
<p dir="auto">And this is a big problem, because looks like some systems does not recognize such fields as files. At least we encountered a problem with Django. Django places entire file's content in <code class="notranslate">request.POST</code> instead of <code class="notranslate">request.FILES</code>. It is clear from sources:<br>
<a href="https://github.com/django/django/blob/1.7c1/django/http/multipartparser.py#L599-L601">https://github.com/django/django/blob/1.7c1/django/http/multipartparser.py#L599-L601</a></p>