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

Issue:
Show conflicting bot id in error when bot token is used multiple times
Tell which of the bots causes conflict:
```Telegram NetworkError : Conflict: terminated by other getUpdates request; make sure that only one bot instance is running (409)```
This is essential when you run more than one bot in an app, how to know what bot token is used twice.

### Steps to reproduce
1. Run 2 (or more) bot with the same token in different python-telegram-bot app instances
2. Shortly you get the message: ```Telegram NetworkError : Conflict: terminated by other getUpdates request; make sure that only one bot instance is running  (409)```

### Expected behaviour
Add bot id to this message:
```Telegram NetworkError : Conflict: terminated by other getUpdates request; make sure that only one bot instance is running **(bot: 12345456)** (409)```

### Actual behaviour
```Telegram NetworkError : Conflict: terminated by other getUpdates request; make sure that only one bot instance is running (409)```



Discussion:
Hmm, this seems like it would be a good change to me. The question is whether telegram gives the bot id back when it returns the error, or if we'll have to get it from the request url or similar.

Is this something you wanna send a pr for @povesma?
This error raises in [telegram/utils/request.py:225](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/utils/request.py#L225) and data returned from Telegram API didn't contains info about bot id:

```json
{
  "ok":false,
  "error_code":409,
  "description":"Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"
}
```

Also there is only one place in `_request_wrapper()` method where info about bot id is placed — second argument of `*args`.

Maybe it is better to catch this exception somewhere inside bootsrap?

Resolving patch:
diff --git a/telegram/error.py b/telegram/error.py
--- a/telegram/error.py
+++ b/telegram/error.py
@@ -57,7 +57,6 @@ class Unauthorized(TelegramError):
 
 
 class InvalidToken(TelegramError):
-
     def __init__(self):
         super(InvalidToken, self).__init__('Invalid token')
 
@@ -71,7 +70,6 @@ class BadRequest(NetworkError):
 
 
 class TimedOut(NetworkError):
-
     def __init__(self):
         super(TimedOut, self).__init__('Timed out')
 
@@ -100,3 +98,16 @@ def __init__(self, retry_after):
         super(RetryAfter,
               self).__init__('Flood control exceeded. Retry in {} seconds'.format(retry_after))
         self.retry_after = float(retry_after)
+
+
+class Conflict(TelegramError):
+    """
+        Raised when a long poll or webhook conflicts with another one.
+
+        Args:
+            msg (:obj:`str`): The message from telegrams server.
+
+    """
+
+    def __init__(self, msg):
+        super(Conflict, self).__init__(msg)
diff --git a/telegram/utils/request.py b/telegram/utils/request.py
--- a/telegram/utils/request.py
+++ b/telegram/utils/request.py
@@ -43,7 +43,7 @@
 
 from telegram import (InputFile, TelegramError, InputMedia)
 from telegram.error import (Unauthorized, NetworkError, TimedOut, BadRequest, ChatMigrated,
-                            RetryAfter, InvalidToken)
+                            RetryAfter, InvalidToken, Conflict)
 
 logging.getLogger('urllib3').setLevel(logging.WARNING)
 
@@ -223,6 +223,8 @@ def _request_wrapper(self, *args, **kwargs):
             raise BadRequest(message)
         elif resp.status == 404:
             raise InvalidToken()
+        elif resp.status == 409:
+            raise Conflict(message)
         elif resp.status == 413:
             raise NetworkError('File too large. Check telegram api limits '
                                'https://core.telegram.org/bots/api#senddocument')


Test patch:
diff --git a/tests/test_error.py b/tests/test_error.py
--- a/tests/test_error.py
+++ b/tests/test_error.py
@@ -20,7 +20,7 @@
 
 from telegram import TelegramError
 from telegram.error import Unauthorized, InvalidToken, NetworkError, BadRequest, TimedOut, \
-    ChatMigrated, RetryAfter
+    ChatMigrated, RetryAfter, Conflict
 
 
 class TestErrors(object):
@@ -83,3 +83,7 @@ def test_chat_migrated(self):
     def test_retry_after(self):
         with pytest.raises(RetryAfter, match="Flood control exceeded. Retry in 12 seconds"):
             raise RetryAfter(12)
+
+    def test_conflict(self):
+        with pytest.raises(Conflict, match='Something something.'):
+            raise Conflict('Something something.')