Repository: python-telegram-bot/python-telegram-bot

Issue:
Encode error when downloading files with non-ASCII filenames.
<!--
Thanks for reporting issues of python-telegram-bot!
To make it easier for us to help you please enter detailed information below.

Please note, we only support the latest version of python-telegram-bot and
master branch. Please make sure to upgrade & recreate the issue on the latest
version prior to opening an issue.
-->
### Steps to reproduce
1. `head /dev/random > 凵冂工匚口わ巨` and send the file to a bot.
2. 
```python
import telegram
b = telegram.Bot(TOKEN)
file_id = b.getUpdates()[0].message.document.file_id
b.getFile(file_id).download("./storage")
```
### Expected behaviour
Tell us what should happen

Download the file to specified directory.

### Actual behaviour
Tell us what happens instead

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/telegram/file.py", line 106, in download
    self.bot.request.download(url, filename, timeout=timeout)
  File "/usr/local/lib/python3.6/site-packages/telegram/utils/request.py", line 284, in download
    buf = self.retrieve(url, timeout=timeout)
  File "/usr/local/lib/python3.6/site-packages/telegram/utils/request.py", line 270, in retrieve
    return self._request_wrapper('GET', url, **urlopen_kwargs)
  File "/usr/local/lib/python3.6/site-packages/telegram/utils/request.py", line 174, in _request_wrapper
    resp = self._con_pool.request(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py", line 66, in request
    **urlopen_kw)
  File "/usr/local/lib/python3.6/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py", line 87, in request_encode_url
    return self.urlopen(method, url, **extra_kw)
  File "/usr/local/lib/python3.6/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py", line 244, in urlopen
    response = conn.urlopen(method, u.request_uri, **kw)
  File "/usr/local/lib/python3.6/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 617, in urlopen
    chunked=chunked)
  File "/usr/local/lib/python3.6/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 390, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1250, in _send_request
    self.putrequest(method, url, **skips)
  File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1117, in putrequest
    self._output(request.encode('ascii'))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 69-75: ordinal not in range(128)
'ascii' codec can't encode characters in position 69-75: ordinal not in range(128)
```

### Configuration
**Operating System:**
Tested on:
- Mac OS X 10.11
- Ubuntu 16.04

**Version of Python, python-telegram-bot & dependencies:**

``$ python -m telegram``

```
python-telegram-bot 6.0.3
urllib3 1.21.1
certifi 2017.04.17
future 0.16.0
Python 3.6.1 (default, Mar 23 2017, 16:49:01)  [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]
```

### Possible Solution
URL escape the "download path" given by `getFile`, then download.


Discussion:
I have the same issue
@blueset 
Thank you for reporting the problem. I can see it too.

Fixing is going to be tricky. Once I removed the `str()` call from line 50 of `telegram/file.py` then other excpetions are thrown from inside the stdlib of python.
In py2.7 it will be from ssl.py, in py3.5 it's from http/client.py (which is wrapped by urllib3).

Resolving patch:
diff --git a/telegram/files/file.py b/telegram/files/file.py
--- a/telegram/files/file.py
+++ b/telegram/files/file.py
@@ -17,9 +17,10 @@
 # You should have received a copy of the GNU Lesser Public License
 # along with this program.  If not, see [http://www.gnu.org/licenses/].
 """This module contains an object that represents a Telegram File."""
-
 from os.path import basename
 
+from future.backports.urllib import parse as urllib_parse
+
 from telegram import TelegramObject
 
 
@@ -46,8 +47,7 @@ def __init__(self, file_id, bot, file_size=None, file_path=None, **kwargs):
 
         # Optionals
         self.file_size = file_size
-        if file_path:
-            self.file_path = str(file_path)
+        self.file_path = file_path
 
         self.bot = bot
 
@@ -91,7 +91,10 @@ def download(self, custom_path=None, out=None, timeout=None):
         if custom_path is not None and out is not None:
             raise ValueError('custom_path and out are mutually exclusive')
 
-        url = self.file_path
+        # Convert any UTF-8 char into a url encoded ASCII string.
+        sres = urllib_parse.urlsplit(self.file_path)
+        url = urllib_parse.urlunsplit(urllib_parse.SplitResult(
+            sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment))
 
         if out:
             buf = self.bot.request.retrieve(url)
@@ -101,6 +104,6 @@ def download(self, custom_path=None, out=None, timeout=None):
             if custom_path:
                 filename = custom_path
             else:
-                filename = basename(url)
+                filename = basename(self.file_path)
 
             self.bot.request.download(url, filename, timeout=timeout)


Test patch: