Completed
Push — master ( 14c8ac...ce45ac )
by Michael
7s
created

prompt_for_config()   B

Complexity

Conditions 6

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 6
dl 0
loc 33
rs 7.5384
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
"""
5
cookiecutter.prompt
6
---------------------
7
8
Functions for prompting the user for project info.
9
"""
10
11
from collections import OrderedDict
12
13
import click
14
from past.builtins import basestring
15
16
from future.utils import iteritems
17
18
from jinja2.exceptions import UndefinedError
19
20
from .exceptions import UndefinedVariableInTemplate
21
from .environment import StrictEnvironment
22
23
24
def read_user_variable(var_name, default_value):
25
    """Prompt the user for the given variable and return the entered value
26
    or the given default.
27
28
    :param str var_name: Variable of the context to query the user
29
    :param default_value: Value that will be returned if no input happens
30
    """
31
    # Please see http://click.pocoo.org/4/api/#click.prompt
32
    return click.prompt(var_name, default=default_value)
33
34
35
def read_user_yes_no(question, default_value):
36
    """Prompt the user to reply with 'yes' or 'no' (or equivalent values).
37
38
    Note:
39
      Possible choices are 'true', '1', 'yes', 'y' or 'false', '0', 'no', 'n'
40
41
    :param str question: Question to the user
42
    :param default_value: Value that will be returned if no input happens
43
    """
44
    # Please see http://click.pocoo.org/4/api/#click.prompt
45
    return click.prompt(
46
        question,
47
        default=default_value,
48
        type=click.BOOL
49
    )
50
51
52
def read_user_choice(var_name, options):
53
    """Prompt the user to choose from several options for the given variable.
54
55
    The first item will be returned if no input happens.
56
57
    :param str var_name: Variable as specified in the context
58
    :param list options: Sequence of options that are available to select from
59
    :return: Exactly one item of ``options`` that has been chosen by the user
60
    """
61
    # Please see http://click.pocoo.org/4/api/#click.prompt
62
    if not isinstance(options, list):
63
        raise TypeError
64
65
    if not options:
66
        raise ValueError
67
68
    choice_map = OrderedDict(
69
        (u'{}'.format(i), value) for i, value in enumerate(options, 1)
70
    )
71
    choices = choice_map.keys()
72
    default = u'1'
73
74
    choice_lines = [u'{} - {}'.format(*c) for c in choice_map.items()]
75
    prompt = u'\n'.join((
76
        u'Select {}:'.format(var_name),
77
        u'\n'.join(choice_lines),
78
        u'Choose from {}'.format(u', '.join(choices))
79
    ))
80
81
    user_choice = click.prompt(
82
        prompt, type=click.Choice(choices), default=default
83
    )
84
    return choice_map[user_choice]
85
86
87
def render_variable(env, raw, cookiecutter_dict):
88
    if raw is None:
89
        return None
90
    if not isinstance(raw, basestring):
91
        raw = str(raw)
92
    template = env.from_string(raw)
93
94
    rendered_template = template.render(cookiecutter=cookiecutter_dict)
95
    return rendered_template
96
97
98
def prompt_choice_for_config(cookiecutter_dict, env, key, options, no_input):
99
    """Prompt the user which option to choose from the given. Each of the
100
    possible choices is rendered beforehand.
101
    """
102
    rendered_options = [
103
        render_variable(env, raw, cookiecutter_dict) for raw in options
104
    ]
105
106
    if no_input:
107
        return rendered_options[0]
108
    return read_user_choice(key, rendered_options)
109
110
111
def prompt_for_config(context, no_input=False):
112
    """
113
    Prompts the user to enter new config, using context as a source for the
114
    field names and sample values.
115
116
    :param no_input: Prompt the user at command line for manual configuration?
117
    """
118
    cookiecutter_dict = {}
119
    env = StrictEnvironment(context=context)
120
121
    for key, raw in iteritems(context[u'cookiecutter']):
122
        if key.startswith(u'_'):
123
            cookiecutter_dict[key] = raw
124
            continue
125
126
        try:
127
            if isinstance(raw, list):
128
                # We are dealing with a choice variable
129
                val = prompt_choice_for_config(
130
                    cookiecutter_dict, env, key, raw, no_input
131
                )
132
            else:
133
                # We are dealing with a regular variable
134
                val = render_variable(env, raw, cookiecutter_dict)
135
136
                if not no_input:
137
                    val = read_user_variable(key, val)
138
        except UndefinedError as err:
139
            msg = "Unable to render variable '{}'".format(key)
140
            raise UndefinedVariableInTemplate(msg, err, context)
141
142
        cookiecutter_dict[key] = val
143
    return cookiecutter_dict
144