Repository: cookiecutter/cookiecutter

Issue:
Choices in Context
Add support for choices in a context as suggested in #441.

I noticed that we are using custom methods for retrieving the user input and decided to let `click.prompt` handle the Python2/Python3 compatibility matters. This PR requires thorough reviews and testing before merging it as I touched some core functions and I want to be certain I didn't break anything :exclamation: 

The CI might not detect these errors as most of the `read_response` calls are still `monkeypatched`. I'm afraid we need to do some manual testing to be 100% positive that everyting is working as expected :sweat: 

I implemented several tests for the new functionality. :smiley: 

Please let me know your thoughts and I'll be happy to update this PR.



Discussion:

Resolving patch:
diff --git a/cookiecutter/compat.py b/cookiecutter/compat.py
--- a/cookiecutter/compat.py
+++ b/cookiecutter/compat.py
@@ -4,23 +4,13 @@
 PY3 = sys.version_info[0] == 3
 OLD_PY2 = sys.version_info[:2] < (2, 7)
 
+
 if PY3:  # pragma: no cover
     input_str = 'builtins.input'
     iteritems = lambda d: iter(d.items())
     from unittest.mock import patch
     from io import StringIO
 
-    def read_response(prompt=''):
-        """
-        Prompt the user for a response.
-
-        Prints the given prompt (which should be a Unicode string),
-        and returns the text entered by the user as a Unicode string.
-
-        :param prompt: A Unicode string that is presented to the user.
-        """
-        # The Python 3 input function does exactly what we want
-        return input(prompt)
 
 else:  # pragma: no cover
     from __builtin__ import raw_input
@@ -30,32 +20,6 @@ def read_response(prompt=''):
     from mock import patch
     from cStringIO import StringIO
 
-    def read_response(prompt=''):
-        """
-        Prompt the user for a response.
-
-        Prints the given prompt (which should be a Unicode string),
-        and returns the text entered by the user as a Unicode string.
-
-        :param prompt: A Unicode string that is presented to the user.
-        """
-        # For Python 2, raw_input takes a byte string argument for the prompt.
-        # This must be encoded using the encoding used by sys.stdout.
-        # The result is a byte string encoding using sys.stdin.encoding.
-        # However, if the program is not being run interactively, sys.stdout
-        # and sys.stdin may not have encoding attributes.
-        # In that case we don't print a prompt (stdin/out isn't interactive,
-        # so prompting is pointless), and we assume the returned data is
-        # encoded using sys.getdefaultencoding(). This may not be right,
-        # but it's likely the best we can do.
-        # Isn't Python 2 encoding support wonderful? :-)
-        if sys.stdout.encoding:
-            prompt = prompt.encode(sys.stdout.encoding)
-        else:
-            prompt = ''
-        enc = sys.stdin.encoding or sys.getdefaultencoding()
-        return raw_input(prompt).decode(enc)
-
 
 if PY3:  # Forced testing
 
diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py
--- a/cookiecutter/prompt.py
+++ b/cookiecutter/prompt.py
@@ -11,10 +11,29 @@
 from __future__ import unicode_literals
 import sys
 
-from .compat import iteritems, read_response, is_string
+import click
+
+from .compat import iteritems, is_string
 from jinja2.environment import Environment
 
 
+def read_response(prompt=''):
+    """Prompt the user and return the entered value or an empty string.
+
+    :param str prompt: Text to display to the user
+    """
+    # Please see http://click.pocoo.org/4/api/#click.prompt
+    # default: use an empty string if no input happens
+    # prompt_suffix: do not add a suffix to the prompt
+    # show_default: the prompt is expected to mention the default itself
+    return click.prompt(
+        prompt,
+        default='',
+        prompt_suffix='',
+        show_default=False,
+    )
+
+
 def prompt_for_config(context, no_input=False):
     """
     Prompts the user to enter new config, using context as a source for the


Test patch:
diff --git a/tests/test_read_response.py b/tests/test_read_response.py
new file mode 100755
--- /dev/null
+++ b/tests/test_read_response.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+test_read_response
+------------------
+"""
+
+from __future__ import unicode_literals
+
+from cookiecutter.prompt import read_response
+
+PROMPT = 'project_name (default is "Kivy Project")?'
+
+
+def _monkey_prompt(prompt, **kwargs):
+    expected_kwargs = {
+        'default': '',
+        'prompt_suffix': '',
+        'show_default': False
+    }
+    assert prompt == PROMPT
+    assert kwargs == expected_kwargs
+    return 'Hello World'
+
+
+def test_click_invocation(capsys, monkeypatch):
+    monkeypatch.setattr('click.prompt', _monkey_prompt)
+    assert read_response(PROMPT) == 'Hello World'