Repository: pallets/click

Issue:
File option - prompting with pretty default?
Hello,
I'm developing simple script, but I have found horrible default when using a file option with prompting with default value...
I have this code:
```python
import click
import os.path
@click.command()
@click.option('-f', default=os.path.realpath("subdir/file.txt"), prompt="Please provide a file", type=click.File('rt'))
def func(f):
    pass
func()
```
But when I call it, it produces prompt like this:

    me@computer:~/directory$ python3 script.py
    Please provide a file [<_io.TextIOWrapper name='/home/me/directory/subdir/file.txt' mode='rt' encoding='UTF-8'>]:
Is this solved anywhere or how difficult would it be to fix it, so it would show `[/home/me/directory/subdir/file.txt]`?

`Ubuntu 16.04 LTS 32-bit, Python 3.5.2, click 6.7`

Please excuse any imperfections of this issue, I'm quite new to GitHub and haven't written any issues yet...


Discussion:
Can't reproduce on Mac - Python 3.6.2, Click 6.7...
```
(tmp-314aa1dbdcce094) ✔ ~/.venvs/tmp-314aa1dbdcce094
21:17 $ pip install click
Collecting click
  Using cached click-6.7-py2.py3-none-any.whl
Installing collected packages: click
Successfully installed click-6.7
(tmp-314aa1dbdcce094) ✔ ~/.venvs/tmp-314aa1dbdcce094
21:17 $ python test.py --help
Usage: test.py [OPTIONS]

Options:
  -f FILENAME
  --help       Show this message and exit.
(tmp-314aa1dbdcce094) ✔ ~/.venvs/tmp-314aa1dbdcce094
21:17 $ cat test.py
import click
import os.path
@click.command()
@click.option('-f', default=os.path.realpath("subdir/file.txt"), prompt="Please provide a file", type=click.File('rt'))
def func(f):
    pass
func()
(tmp-314aa1dbdcce094) ✔ ~/.venvs/tmp-314aa1dbdcce094
21:17 $ python test.py
Usage: test.py [OPTIONS]

Error: Invalid value for "-f": Could not open file: /Users/tomgoren/.venvs/tmp-314aa1dbdcce094/subdir/file.txt: No such file or directory
(tmp-314aa1dbdcce094) ✘-2 ~/.venvs/tmp-314aa1dbdcce094
21:17 $ pip freeze
-f file:///Users/tomgoren/.cache/pip/wheelhouse
click==6.7
(tmp-314aa1dbdcce094) ✔ ~/.venvs/tmp-314aa1dbdcce094
21:17 $ python --version
Python 3.6.2
```
Oh, @tomgoren, this isn't meant to be reproduced as is. If you want to:
```
mkdir subdir
touch subdir/file.txt
```
_Sorry for late reply and writing bad issues..._
Okay - I see it now @mvolfik.

The problem seems to be [here](https://github.com/pallets/click/blob/master/click/types.py#L373).

There is only one value returned, `f`. If we were to return `f.name` for instance, then what we would get back would only be a string, and not the actual file handler.

So, while the output would be as expected, it would produce the wrong result if you were to try something like `f.read()`. Test case using your example (I changed `click/types.py` locally):
```
22:21 $ python test.py 
Please provide a file [/home/tomgoren/.venvs/tmp-d5c5119e57bcfc5/subdir/file.txt]: 
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    func()
  File "/home/tomgoren/.venvs/tmp-d5c5119e57bcfc5/lib/python3.6/site-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/home/tomgoren/.venvs/tmp-d5c5119e57bcfc5/lib/python3.6/site-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/home/tomgoren/.venvs/tmp-d5c5119e57bcfc5/lib/python3.6/site-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/tomgoren/.venvs/tmp-d5c5119e57bcfc5/lib/python3.6/site-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "test.py", line 7, in func
    print(f.read())
AttributeError: 'str' object has no attribute 'read'
```

After digging a bit deeper, there seems to be a whole song and dance between [`convert`](https://github.com/pallets/click/blob/master/click/types.py#L346), [`convert_type`](https://github.com/pallets/click/blob/master/click/types.py#L518), [`prompt`](https://github.com/pallets/click/blob/master/click/termui.py#L36), and a [few other bits and pieces](https://github.com/pallets/click/blob/master/click/core.py#L1341).

The long and the short of it is that I got a bit lost, and I'm sorry I wasn't able to help more, but it seems like an actual bug, and a tricky one at that. I'm very curious to see how this is solved either way.

Good luck!
Starting to work on it

Resolving patch:
diff --git a/click/termui.py b/click/termui.py
--- a/click/termui.py
+++ b/click/termui.py
@@ -1,3 +1,4 @@
+import io
 import os
 import sys
 import struct
@@ -5,11 +6,12 @@
 import itertools
 
 from ._compat import raw_input, text_type, string_types, \
-     isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN
+    isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN
 from .utils import echo
 from .exceptions import Abort, UsageError
 from .types import convert_type, Choice, Path
 from .globals import resolve_color_default
+from .utils import LazyFile
 
 
 # The prompt functions to use.  The doc tools currently override these
@@ -48,10 +50,17 @@ def _build_prompt(text, suffix, show_default=False, default=None, show_choices=T
     if type is not None and show_choices and isinstance(type, Choice):
         prompt += ' (' + ", ".join(map(str, type.choices)) + ')'
     if default is not None and show_default:
-        prompt = '%s [%s]' % (prompt, default)
+        prompt = '%s [%s]' % (prompt, _format_default(default))
     return prompt + suffix
 
 
+def _format_default(default):
+    if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"):
+        return default.name
+
+    return default
+
+
 def prompt(text, default=None, hide_input=False, confirmation_prompt=False,
            type=None, value_proc=None, prompt_suffix=': ', show_default=True,
            err=False, show_choices=True):


Test patch:
diff --git a/tests/test_termui.py b/tests/test_termui.py
--- a/tests/test_termui.py
+++ b/tests/test_termui.py
@@ -225,6 +225,24 @@ def cli_without_choices(g):
     assert '(none, day, week, month)' not in result.output
 
 
+@pytest.mark.parametrize(
+    "file_kwargs",
+    [
+        {"mode": "rt"},
+        {"mode": "rb"},
+        {"lazy": True},
+    ]
+)
+def test_file_prompt_default_format(runner, file_kwargs):
+    @click.command()
+    @click.option("-f", default=__file__, prompt="file", type=click.File(**file_kwargs))
+    def cli(f):
+        click.echo(f.name)
+
+    result = runner.invoke(cli)
+    assert result.output == "file [{0}]: \n{0}\n".format(__file__)
+
+
 def test_secho(runner):
     with runner.isolation() as outstreams:
         click.secho(None, nl=False)