def get_next_option(cc_context, user_inputs): """Parses the cookiecutter template and current context and determines the input to be requested.""" context = {} context["cookiecutter"] = cc_context env = StrictEnvironment(context=context) for key in context["cookiecutter"]: if key == "_variables": continue if key not in user_inputs: raw_value = context["cookiecutter"][key] if key.startswith("_") and not key.endswith("__"): user_inputs[key] = render_variable(env, raw_value, user_inputs) continue variable_info = render_variable( env, cc_context.get("_variables", {}).get(key, {}), user_inputs) if variable_info.get("skip", "False").lower() == "true": rendered_value = render_variable(env, raw_value, user_inputs) if isinstance(rendered_value, list): rendered_value = rendered_value[0] user_inputs[key] = rendered_value continue if not isinstance(raw_value, dict): rendered_value = render_variable(env, raw_value, user_inputs) return key, rendered_value or "", False return None, None, True
def _prompt_choice_and_subitems(cookiecutter_dict, env, key, options, no_input): result = {} # first, get the selection rendered_options = [ render_variable(env, list(raw.keys())[0], cookiecutter_dict) for raw in options ] if no_input: selected = rendered_options[0] selected = read_user_choice(key, rendered_options) selected_item = [list(c.values())[0] for c in options if list(c.keys())[0] == selected][0] result[selected] = {} # then, fill in the sub values for that item for subkey, raw in selected_item.items(): # We are dealing with a regular variable val = render_variable(env, raw, cookiecutter_dict) if not no_input: val = read_user_variable(subkey, val) result[selected][subkey] = val return result
def prompt_for_config(context, no_input=False): """ Prompts the user to enter new config, using context as a source for the field names and sample values. :param no_input: Prompt the user at command line for manual configuration? """ cookiecutter_dict = OrderedDict([]) env = StrictEnvironment(context=context) # First pass: Handle simple and raw variables, plus choices. # These must be done first because the dictionaries keys and # values might refer to them. for key, raw in iteritems(context[u'cookiecutter']): if key.startswith(u'_'): cookiecutter_dict[key] = raw continue try: if isinstance(raw, list): if isinstance(raw[0], dict): val = _prompt_choice_and_subitems( cookiecutter_dict, env, key, raw, no_input ) cookiecutter_dict[key] = val else: # We are dealing with a choice variable val = prompt_choice_for_config( cookiecutter_dict, env, key, raw, no_input ) cookiecutter_dict[key] = val elif not isinstance(raw, dict): # We are dealing with a regular variable val = render_variable(env, raw, cookiecutter_dict) if not no_input: val = read_user_variable(key, val) cookiecutter_dict[key] = val except UndefinedError as err: msg = "Unable to render variable '{}'".format(key) raise UndefinedVariableInTemplate(msg, err, context) # Second pass; handle the dictionaries. for key, raw in iteritems(context[u'cookiecutter']): try: if isinstance(raw, dict): # We are dealing with a dict variable val = render_variable(env, raw, cookiecutter_dict) if not no_input: val = read_user_dict(key, val) cookiecutter_dict[key] = val except UndefinedError as err: msg = "Unable to render variable '{}'".format(key) raise UndefinedVariableInTemplate(msg, err, context) return cookiecutter_dict
def render_obj(env, o, cookiecutter_dict): if isinstance(o, list): return render_list(env, o, cookiecutter_dict) elif isinstance(o, dict): return render_dict(env, o, cookiecutter_dict) else: return render_variable(env, o, cookiecutter_dict)
def _fetch_config_from_user_prompts( prompts: Dict[str, Any], cookiecutter_context: OrderedDict) -> Dict[str, str]: """Interactively obtains information from user prompts. Args: prompts: Prompts from prompts.yml. cookiecutter_context: Cookiecutter context generated from cookiecutter.json. Returns: Configuration for starting a new project. This is passed as ``extra_context`` to cookiecutter and will overwrite the cookiecutter.json defaults. """ # pylint: disable=import-outside-toplevel from cookiecutter.environment import StrictEnvironment from cookiecutter.prompt import read_user_variable, render_variable config: Dict[str, str] = dict() for variable_name, prompt_dict in prompts.items(): prompt = _Prompt(**prompt_dict) # render the variable on the command line cookiecutter_variable = render_variable( env=StrictEnvironment(context=cookiecutter_context), raw=cookiecutter_context[variable_name], cookiecutter_dict=config, ) # read the user's input for the variable user_input = read_user_variable(str(prompt), cookiecutter_variable) if user_input: prompt.validate(user_input) config[variable_name] = user_input return config
def render_context(context, output_folder_path): cookiecutter_dict = OrderedDict() # inject the output folder path at the beginning, so all variables can refer to it cookiecutter_dict['_output_folder_path'] = output_folder_path; env = StrictEnvironment(context=context) for key, raw in iteritems(context['cookiecutter']): if key.startswith('_'): # unlike cookiecutter's prompt_for_config, we render internal variables cookiecutter_dict[key] = render_obj(env, raw, cookiecutter_dict) continue try: if isinstance(raw, list): # We are dealing with a choice variable val = prompt_choice_for_config( cookiecutter_dict, env, key, raw, no_input=True ) else: # We are dealing with a regular variable val = render_variable(env, raw, cookiecutter_dict) except UndefinedError as err: msg = "Unable to render variable '{}'".format(key) raise UndefinedVariableInTemplate(msg, err, context) cookiecutter_dict[key] = val return { 'cookiecutter' : cookiecutter_dict }
def render_context(context, output_folder_path): cookiecutter_dict = OrderedDict() # inject the output folder path at the beginning, so all variables can refer to it cookiecutter_dict['_output_folder_path'] = output_folder_path env = StrictEnvironment(context=context) for key, raw in iteritems(context['cookiecutter']): if key.startswith('_'): # unlike cookiecutter's prompt_for_config, we render internal variables cookiecutter_dict[key] = render_obj(env, raw, cookiecutter_dict) continue try: if isinstance(raw, list): # We are dealing with a choice variable val = prompt_choice_for_config(cookiecutter_dict, env, key, raw, no_input=True) else: # We are dealing with a regular variable val = render_variable(env, raw, cookiecutter_dict) except UndefinedError as err: msg = "Unable to render variable '{}'".format(key) raise UndefinedVariableInTemplate(msg, err, context) cookiecutter_dict[key] = val return {'cookiecutter': cookiecutter_dict}
def test_convert_to_str_complex_variables(self, raw_var, rendered_var): """Verify tree items correctly rendered.""" env = environment.StrictEnvironment() context = {'project': 'foobar'} result = prompt.render_variable(env, raw_var, context) assert result == rendered_var
def get_next_option(cc_context, user_inputs): """Parses the cookiecutter template and current context and determines the input to be requested.""" context = {} context["cookiecutter"] = cc_context env = StrictEnvironment(context=context) for key in context["cookiecutter"]: if key not in user_inputs: rendered_value = render_variable(env, context["cookiecutter"][key], user_inputs) return key, rendered_value, False return None, None, True
def _prompt_user_for_config( # pylint: disable=too-many-locals template_path: Path, checkout: str = None, directory: str = None) -> Dict[str, str]: """Prompt user in the CLI to provide configuration values for cookiecutter variables in a starter, such as project_name, package_name, etc. """ # pylint: disable=import-outside-toplevel from cookiecutter.prompt import read_user_variable, render_variable from cookiecutter.repository import determine_repo_dir # for performance reasons with tempfile.TemporaryDirectory() as tmpdir: temp_dir_path = Path(tmpdir).resolve() cookiecutter_repo, _ = determine_repo_dir( template=str(template_path), abbreviations=dict(), clone_to_dir=temp_dir_path, checkout=checkout, no_input=True, directory=directory, ) cookiecutter_dir = temp_dir_path / cookiecutter_repo prompts_yml = cookiecutter_dir / "prompts.yml" # If there is no prompts.yml, no need to ask user for input. if not prompts_yml.is_file(): return {} with open(prompts_yml) as config_file: prompts_dict = yaml.safe_load(config_file) cookiecutter_env = _prepare_cookiecutter_env(cookiecutter_dir) config: Dict[str, str] = dict() config["output_dir"] = str(Path.cwd().resolve()) for variable_name, prompt_dict in prompts_dict.items(): prompt = _Prompt(**prompt_dict) # render the variable on the command line cookiecutter_variable = render_variable( env=cookiecutter_env.env, raw=cookiecutter_env.context[variable_name], cookiecutter_dict=config, ) # read the user's input for the variable user_input = read_user_variable(str(prompt), cookiecutter_variable) if user_input: prompt.validate(user_input) config[variable_name] = user_input return config
def test_convert_to_str(mocker, raw_var, rendered_var): env = Environment() from_string = mocker.patch('cookiecutter.prompt.Environment.from_string', wraps=env.from_string) context = {'project': 'foobar'} result = prompt.render_variable(env, raw_var, context) assert result == rendered_var # Make sure that non str variables are conerted beforehand if not isinstance(raw_var, basestring): raw_var = str(raw_var) from_string.assert_called_once_with(raw_var)
def test_convert_to_str(mocker, raw_var, rendered_var): env = Environment() from_string = mocker.patch("cookiecutter.prompt.Environment.from_string", wraps=env.from_string) context = {"project": "foobar"} result = prompt.render_variable(env, raw_var, context) assert result == rendered_var # Make sure that non None non str variables are conerted beforehand if raw_var is not None: if not isinstance(raw_var, basestring): raw_var = str(raw_var) from_string.assert_called_once_with(raw_var) else: assert not from_string.called
def test_convert_to_str(mocker, raw_var, rendered_var): env = Environment() from_string = mocker.patch( 'cookiecutter.prompt.Environment.from_string', wraps=env.from_string ) context = {'project': 'foobar'} result = prompt.render_variable(env, raw_var, context) assert result == rendered_var # Make sure that non str variables are conerted beforehand if not compat.is_string(raw_var): raw_var = str(raw_var) from_string.assert_called_once_with(raw_var)
def test_convert_to_str(self, mocker, raw_var, rendered_var): """Verify simple items correctly rendered to strings.""" env = environment.StrictEnvironment() from_string = mocker.patch( 'cookiecutter.prompt.StrictEnvironment.from_string', wraps=env.from_string) context = {'project': 'foobar'} result = prompt.render_variable(env, raw_var, context) assert result == rendered_var # Make sure that non None non str variables are converted beforehand if raw_var is not None: if not isinstance(raw_var, six.string_types): raw_var = str(raw_var) from_string.assert_called_once_with(raw_var) else: assert not from_string.called
def test_convert_to_str(mocker, raw_var, rendered_var): env = environment.StrictEnvironment() from_string = mocker.patch( "cookiecutter.prompt.StrictEnvironment.from_string", wraps=env.from_string, ) context = {"project": "foobar"} result = prompt.render_variable(env, raw_var, context) assert result == rendered_var # Make sure that non None non str variables are converted beforehand if raw_var is not None: if not isinstance(raw_var, six.string_types): raw_var = str(raw_var) from_string.assert_called_once_with(raw_var) else: assert not from_string.called
def _run_prompts_for_user_input(prompts: Dict[str, Dict[str, str]], cookiecutter_dir: Path) -> Dict[str, str]: # pylint: disable=import-outside-toplevel from cookiecutter.prompt import read_user_variable, render_variable cookiecutter_env = _prepare_cookiecutter_env(cookiecutter_dir) config: Dict[str, str] = dict() for variable_name, prompt_dict in prompts.items(): prompt = _Prompt(**prompt_dict) # render the variable on the command line cookiecutter_variable = render_variable( env=cookiecutter_env.env, raw=cookiecutter_env.context[variable_name], cookiecutter_dict=config, ) # read the user's input for the variable user_input = read_user_variable(str(prompt), cookiecutter_variable) if user_input: prompt.validate(user_input) config[variable_name] = user_input return config