Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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)
Beispiel #5
0
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
Beispiel #6
0
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 }
Beispiel #7
0
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)
Beispiel #8
0
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}
Beispiel #9
0
    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
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
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)
Beispiel #13
0
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
Beispiel #14
0
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)
Beispiel #15
0
    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
Beispiel #16
0
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
Beispiel #17
0
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