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

Issue:
timeout argument does not work
### Steps to reproduce
1.
Run code:
```
from telegram import Bot

bot = Bot(token='YOUR TOKEN API')
bot.get_chat_administrators(SOME_CHAT_ID_KNOWN_TO_BOT, timeout=60)
```

You can reproduce it only when telegram API server does not respond in 5 seconds. It happens quite often for me :-/

### Expected behaviour
If telegram server accepts connection but does not responses for a long time the code should fail in 60 seconds.

### Actual behaviour
Code fails in 5 seconds (default library timeout). See traceback below.

### Configuration
**Operating System:**
OS Debian Stretch

**Version of Python, python-telegram-bot & dependencies:**

```
p$ python -m telegram
python-telegram-bot 11.1.0
certifi 2018.11.29
future 0.17.1
Python 3.5.3 (default, Jan 19 2017, 14:11:04)  [GCC 6.3.0 20170118]
```

### Logs
Error traceback:
```
Traceback (most recent call last):
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 402, in _make_request
    six.raise_from(e, None)
  File "<string>", line 2, in raise_from
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 398, in _make_request
    httplib_response = conn.getresponse()
  File "/usr/lib/python3.5/http/client.py", line 1198, in getresponse
    response.begin()
  File "/usr/lib/python3.5/http/client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python3.5/http/client.py", line 258, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/usr/lib/python3.5/socket.py", line 576, in readinto
    return self._sock.recv_into(b)
  File "/usr/lib/python3.5/ssl.py", line 937, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/lib/python3.5/ssl.py", line 799, in read
    return self._sslobj.read(len, buffer)
  File "/usr/lib/python3.5/ssl.py", line 583, in read
    v = self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmp/z10/lib/python3.5/site-packages/telegram/utils/request.py", line 203, in _request_wrapper
    resp = self._con_pool.request(*args, **kwargs)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py", line 70, in request
    **urlopen_kw)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py", line 148, in request_encode_body
    return self.urlopen(method, url, **extra_kw)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py", line 244, in urlopen
    response = conn.urlopen(method, u.request_uri, **kw)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 666, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py", line 347, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py", line 686, in reraise
    raise value
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 617, in urlopen
    chunked=chunked)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 405, in _make_request
    exc_cls=ReadTimeoutError)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 321, in _raise_timeout
    raise exc_cls(*args)
telegram.vendor.ptb_urllib3.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='api.telegram.org', port=443): Read timed out. (read timeout=5.0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    bot.get_chat_administrators(-1001071177546, timeout=60)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/bot.py", line 65, in decorator
    result = func(self, *args, **kwargs)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/bot.py", line 2187, in get_chat_administrators
    result = self._request.post(url, data, timeout=timeout)
  File "/tmp/z10/lib/python3.5/site-packages/telegram/utils/request.py", line 309, in post
    headers={'Content-Type': 'application/json'})
  File "/tmp/z10/lib/python3.5/site-packages/telegram/utils/request.py", line 205, in _request_wrapper
    raise TimedOut()
telegram.error.TimedOut: Timed out
```


Discussion:
I seem to recall a fix for this maybe landing in master. Could you try using the master version instead? This can be done by uninstalling ptb and then installing it from github using the instructions in the readme.
I've tried ptb master from repo. Same result. Fails in 5 seconds, even if timeout is set to 60 seconds.
Tested on  PTB from repo

Does not work:
```
bot = Bot(token=TOKEN)
bot.get_chat_administrators(CHAT_ID, timeout=60)
```

Works but it sets global timeout and I need extended timeout only for subset of methods:
```
bot = Bot(token=TOKEN, request=Request(read_timeout=60))
bot.get_chat_administrators(CHAT_ID)
```
As I can see, error is here: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/utils/request.py#L324 Timeout parameter is passed to underlying network library only in case of files uploading.
Looking at it it would seem you're right. I was under the impression that we were testing for it, but it seems like the test case (https://github.com/python-telegram-bot/python-telegram-bot/blob/master/tests/test_bot.py#L620) doesn't go further than Request.post.

If you'd like to submit a PR for this that would be great, otherwise we will probably get around to it sometime :)

Resolving patch:
diff --git a/telegram/utils/request.py b/telegram/utils/request.py
--- a/telegram/utils/request.py
+++ b/telegram/utils/request.py
@@ -323,7 +323,8 @@ def post(self, url, data, timeout=None):
         else:
             result = self._request_wrapper('POST', url,
                                            body=json.dumps(data).encode('utf-8'),
-                                           headers={'Content-Type': 'application/json'})
+                                           headers={'Content-Type': 'application/json'},
+                                           **urlopen_kwargs)
 
         return self._parse(result)
 


Test patch:
diff --git a/tests/test_bot.py b/tests/test_bot.py
--- a/tests/test_bot.py
+++ b/tests/test_bot.py
@@ -618,16 +618,27 @@ def test_error_pin_unpin_message(self, bot, message):
     # test_sticker module.
 
     def test_timeout_propagation(self, monkeypatch, bot, chat_id):
+
+        from telegram.vendor.ptb_urllib3.urllib3.util.timeout import Timeout
+
         class OkException(Exception):
             pass
 
-        timeout = 500
+        TIMEOUT = 500
 
-        def post(*args, **kwargs):
-            if kwargs.get('timeout') == 500:
+        def request_wrapper(*args, **kwargs):
+            obj = kwargs.get('timeout')
+            if isinstance(obj, Timeout) and obj._read == TIMEOUT:
                 raise OkException
 
-        monkeypatch.setattr('telegram.utils.request.Request.post', post)
+            return b'{"ok": true, "result": []}'
+
+        monkeypatch.setattr('telegram.utils.request.Request._request_wrapper', request_wrapper)
+
+        # Test file uploading
+        with pytest.raises(OkException):
+            bot.send_photo(chat_id, open('tests/data/telegram.jpg', 'rb'), timeout=TIMEOUT)
 
+        # Test JSON submition
         with pytest.raises(OkException):
-            bot.send_photo(chat_id, open('tests/data/telegram.jpg', 'rb'), timeout=timeout)
+            bot.get_chat_administrators(chat_id, timeout=TIMEOUT)