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

Issue:
Allow subprocess.Popen.stdout as file input
<!--
Thanks for reporting issues of python-telegram-bot!

Use this template to notify us if you found a bug, or if you want to request a new feature.
If you're looking for help with programming your bot using our library, feel free to ask your
questions in out telegram group at: https://t.me/pythontelegrambotgroup

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.

```python
@run_async
def pipe(bot, update):
  proc = subprocess.Popen(
    "cat image.jpg".split(),
    stdout=subprocess.PIPE
  )
  update.message.reply_voice(proc.stdout)
  while proc.returncode is None:
    proc.poll()
```

### Expected behaviour

Allow `subprocess.Popen.stdout` be treated as valid io stream, just like `open("image.jpg", "rb")` is.

### Actual behaviour

```
...
  File "/usr/lib/python3.6/site-packages/telegram/utils/request.py", line 262, in post
    data = InputFile(data)
  File "/usr/lib/python3.6/site-packages/telegram/files/inputfile.py", line 76, in __init__
    self.filename = os.path.basename(self.input_file.name)
  File "/usr/lib/python3.6/posixpath.py", line 144, in basename
    p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not int
```

### Configuration
**Operating System:**

`Linux xiaomi 4.15.9-1-ARCH #1 SMP PREEMPT Sun Mar 11 17:54:33 UTC 2018 x86_64 GNU/Linux`

**Version of Python, python-telegram-bot & dependencies:**

```
Python 3.6.4 (default, Jan  5 2018, 02:35:40) 
[GCC 7.2.1 20171224] on linux
```

### PROPOSED FIX

https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/files/inputfile.py#L76 should stringify `self.input_file.name` to look as:

```python
self.filename = os.path.basename(str(self.input_file.name))
```


Discussion:
@tsnoam @jh0ker @bomjacob thoughts?

Anyway we are looking for ways to change and improve the inputfiles so we'll take this into considderation

Resolving patch:
diff --git a/telegram/files/inputfile.py b/telegram/files/inputfile.py
--- a/telegram/files/inputfile.py
+++ b/telegram/files/inputfile.py
@@ -70,7 +70,9 @@ def __init__(self, data):
             self.input_file_content = self.input_file.read()
             if 'filename' in data:
                 self.filename = self.data.pop('filename')
-            elif hasattr(self.input_file, 'name'):
+            elif (hasattr(self.input_file, 'name') and
+                  not isinstance(self.input_file.name, int) and  # py3
+                  self.input_file.name != '<fdopen>'):  # py2
                 # on py2.7, pylint fails to understand this properly
                 # pylint: disable=E1101
                 self.filename = os.path.basename(self.input_file.name)


Test patch:
diff --git a/tests/test_inputfile.py b/tests/test_inputfile.py
new file mode 100644
--- /dev/null
+++ b/tests/test_inputfile.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2018
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+import os
+import subprocess
+import sys
+
+from telegram import InputFile
+
+
+class TestInputFile(object):
+    png = os.path.join('tests', 'data', 'game.png')
+
+    def test_subprocess_pipe(self):
+        if sys.platform == 'win32':
+            cmd = ['type', self.png]
+        else:
+            cmd = ['cat', self.png]
+
+        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=(sys.platform == 'win32'))
+        in_file = InputFile({'photo': proc.stdout})
+
+        assert in_file.input_file_content == open(self.png, 'rb').read()
+        assert in_file.mimetype == 'image/png'
+        assert in_file.filename == 'image.png'
+
+        proc.kill()