def test_env_should_raise_for_unknown_extension():
    context = {"cookiecutter": {"_extensions": ["foobar"]}}

    with pytest.raises(UnknownExtension) as err:
        StrictEnvironment(context=context, keep_trailing_newline=True)

    assert "Unable to load extension: " in str(err.value)
Example #2
0
def run_script_with_context(script_path, cwd, context):
    """Execute a script after rendering it with Jinja.

    :param script_path: Absolute path to the script to run.
    :param cwd: The directory to run the script from.
    :param context: Cookiecutter project template context.
    """
    _, extension = os.path.splitext(script_path)

    with io.open(script_path, 'r', encoding='utf-8') as file:
        contents = file.read()

    with tempfile.NamedTemporaryFile(
        delete=False,
        mode='wb',
        suffix=extension
    ) as temp:
        env = StrictEnvironment(
            context=context,
            keep_trailing_newline=True,
        )
        template = env.from_string(contents)
        output = template.render(**context)
        temp.write(output.encode('utf-8'))

    run_script(temp.name, cwd)
Example #3
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
Example #4
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}
Example #5
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
Example #6
0
def test_env_should_raise_for_unknown_extension():
    context = {'cookiecutter': {'_extensions': ['foobar']}}

    with pytest.raises(UnknownExtension) as err:
        StrictEnvironment(context=context, keep_trailing_newline=True)

    assert 'Unable to load extension: ' in str(err.value)
Example #7
0
def test_env_should_come_with_default_extensions():
    """Verify default extensions loaded with StrictEnvironment."""
    env = StrictEnvironment(keep_trailing_newline=True)
    assert 'jinja2_time.jinja2_time.TimeExtension' in env.extensions
    assert 'cookiecutter.extensions.JsonifyExtension' in env.extensions
    assert 'cookiecutter.extensions.RandomStringExtension' in env.extensions
    assert 'cookiecutter.extensions.SlugifyExtension' in env.extensions
Example #8
0
def prompt_for_config(context, no_input=False, custom_filters={}):
    """Prompt user to enter a new config.

    :param dict context: Source for field names and sample values.
    :param no_input: Prompt the user at command line for manual configuration?
    """
    cookiecutter_dict = OrderedDict([])
    env = StrictEnvironment(context=context)
    env.filters.update(custom_filters)

    # 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 context['cookiecutter'].items():
        if key.startswith('_') and not key.startswith('__'):
            cookiecutter_dict[key] = raw
            continue
        elif key.startswith('__'):
            cookiecutter_dict[key] = render_variable(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)
                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 context['cookiecutter'].items():
        # Skip private type dicts
        if key.startswith('_') and not key.startswith('__'):
            continue

        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
Example #9
0
def prompt_for_config(context,
                      no_input=False,
                      context_key=None,
                      existing_context=None):
    """
    Prompt user to enter values.

    Function sets the jinja environment and brings in extensions.

    :param dict context: Source for field names and sample values.
    :param no_input: Prompt the user at command line for manual configuration.
    :param context_key: The key to insert all the outputs under in the context dict.
    :param existing_context: A dictionary of values to use during rendering.
    """
    if not existing_context:
        cc_dict = OrderedDict([])
    else:
        cc_dict = OrderedDict(existing_context)
    env = StrictEnvironment(context=context)

    if not context_key:
        context_key = next(iter(context))

    if '_template' in context[context_key]:
        # Normal case where '_template' is set in the context in `main`
        with work_in(context[context_key]['_template']):
            return parse_context(context, env, cc_dict, context_key, no_input)
    else:
        # Case where prompt is being called directly as is the case with an operator
        return parse_context(context, env, cc_dict, context_key, no_input)
Example #10
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
Example #11
0
def test_local_extension_not_available(tmpdir, cli_runner):
    """Test handling of included but unavailable local extension."""
    context = {'cookiecutter': {'_extensions': ['foobar']}}

    with pytest.raises(UnknownExtension) as err:
        StrictEnvironment(context=context, keep_trailing_newline=True)

    assert 'Unable to load extension: ' in str(err.value)
Example #12
0
def render_file_template(template_path,
                         use_defaults=False,
                         extra_context=None):
    """Render a single-file template with Cookiecutter.

    Currently this function only renders a file using default values defined
    in a ``cookiecutter.json`` file.

    Parameters
    ----------
    template_path : `str`
        Path to the file template. There should be a
        ``cookecutter.json`` in the same directory as the template file.
        This JSON file is used to define a provide defaults for the template's
        variables.
    use_defaults : `bool`, optional
        Disables Sphinx from interactively prompting for context variables, if
        `True`.
    extra_context : `dict`, optional
        Optional dictionary of key-value pairs that override defaults in the
        ``cookiecutter.json`` file.

    Returns
    -------
    rendered_text : `str`
        Content rendered from the template and ``cookiecutter.json`` defaults.
    """
    logger = logging.getLogger(__name__)
    logger.debug('Rendering file template %s', template_path)

    # Get variables for rendering the template
    template_dir = os.path.dirname(template_path)
    context_file = os.path.join(template_dir, 'cookiecutter.json')
    context = generate_context(context_file=context_file)
    context['cookiecutter'] = prompt_for_config(context, use_defaults)

    if extra_context is not None:
        context['cookiecutter'].update(extra_context)

    # Jinja2 template rendering environment
    env = StrictEnvironment(
        context=context,
        keep_trailing_newline=True,
    )
    env.loader = FileSystemLoader(template_dir)

    try:
        tmpl = env.get_template(os.path.basename(template_path))
    except TemplateSyntaxError as exception:
        # Disable translated so that printed exception contains verbose
        # information about syntax error location
        exception.translated = False
        raise
    rendered_text = tmpl.render(**context)

    return rendered_text
Example #13
0
def recut():
    """
    Recreate setup.py so that we can edit keywords
    Remove unnecessary code examples
    """
    # template location
    try:
        # cutting cookie from directory with template
        temp_dir = find.find_template('..')
    except NonTemplatedInputDirException as e:
        # template coming from Github
        # Hooks are passed through jinja2. raw will
        # Make sure `cookiecutter.project` isn't replaced
        {% raw %}
        temp_dir = os.path.join(config['cookiecutters_dir'],
                                'cookiecutter-ckan-extension',
                                '{{cookiecutter.project}}')
        {% endraw %}

    # Location for resulting file
    destination = os.getcwd()
    # name of template
    setup_template = 'setup.py'

    # get context
    context = {{ cookiecutter | jsonify }}

    # Process keywords
    keywords = context['keywords'].strip().split()
    keywords = [keyword for keyword in keywords
                if keyword not in ('ckan', 'CKAN', 'A', 'space',
                                   'seperated', 'list', 'of', 'keywords')]
    keywords.insert(0, 'CKAN')
    keywords = u' '.join(keywords)
    context['keywords'] = keywords

    # Double check 'project_shortname' and 'plugin_class_name'
    short_name = context['project'][8:].replace('-','_')
    if context['project_shortname'] != short_name:
        context['project_shortname'] = short_name

    plugin_class_name = '{}Plugin'.format(context['project_shortname']
                        .title().replace('_', ''))
    if context['plugin_class_name'] != plugin_class_name:
        context['plugin_class_name'] = plugin_class_name
    # Recut cookie
    env = StrictEnvironment()
    env.loader = jinja2.FileSystemLoader(temp_dir)
    gen.generate_file(project_dir=destination,
                      infile=setup_template,
                      context={'cookiecutter': context},
                      env=env)
    if not asbool(context['include_examples']):
        remove_code_examples(os.path.join(destination, 'ckanext', short_name))
Example #14
0
File: api.py Project: f4hy/CookieS
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
Example #15
0
def _prepare_cookiecutter_env(cookiecutter_dir) -> _CookiecutterEnv:
    """Prepare the cookiecutter environment to render its default values
    when prompting user on the CLI for inputs.
    """
    # pylint: disable=import-outside-toplevel
    from cookiecutter.environment import StrictEnvironment
    from cookiecutter.generate import generate_context

    cookiecutter_json = cookiecutter_dir / "cookiecutter.json"
    cookiecutter_context = generate_context(
        context_file=cookiecutter_json).get("cookiecutter", {})
    cookiecutter_env = StrictEnvironment(context=cookiecutter_context)
    return _CookiecutterEnv(context=cookiecutter_context, env=cookiecutter_env)
Example #16
0
def test_passes_custom_arguments_from_context():
    context = {
        'cookiecutter': {
            '_environment': {
                'variable_start_string': '[[',
                'variable_end_string': ']]'
            }
        }
    }

    env = StrictEnvironment(context=context)

    assert env.variable_start_string == '[['
    assert env.variable_end_string == ']]'
Example #17
0
    def _execute(self):
        env = StrictEnvironment(context=self.context)

        env.loader = FileSystemLoader(self.file_system_loader)
        template = env.get_template(self.operator_dict['template_path'])

        jinja_context = (self.operator_dict['context']
                         if 'context' in self.operator_dict else {})

        if 'extra_context' in self.operator_dict:
            jinja_context.update(self.operator_dict['extra_context'])

        output_from_parsed_template = template.render(
            **{self.context_key: jinja_context})

        with open(self.operator_dict['output_path'], 'w') as fh:
            fh.write(output_from_parsed_template)

        return self.operator_dict['output_path']
    remove_folder('templatetags')
    for file in [
            'urls.py',
            'views.py',
            'hooks.py',
    ]:
        remove_file(file)

if '{{ cookiecutter.content_renderer_plugin }}' == 'Yes':
    context = {'content_kind': ''}
    while context['content_kind'] not in dict(content_kinds.choices):
        print('Choose a content kind that this plugin renders, choose from {}'.
              format(', '.join(dict(content_kinds.choices).keys())))
        context['content_kind'] = raw_input(
            'Select the content kind that this plugin renders: ')
        if context['content_kind'] not in dict(content_kinds.choices):
            print('Invalid kind.')
    context['file_extension'] = raw_input(
        'Please provide the file extension that this plugin renders: ')
    env = StrictEnvironment(
        context=context,
        keep_trailing_newline=True,
    )
    env.loader = FileSystemLoader('/')
    render_file('kolibri_plugin.py', context, env)
    render_file('assets/src/module.js', context, env)

if '{{ cookiecutter.has_own_page }}' == 'Yes' and '{{ cookiecutter.frontend_plugin }}' == 'Yes':
    shutil.move(location('assets/src/module.js'),
                location('assets/src/app.js'))
Example #19
0
def generate_files(
    repo_dir,
    context=None,
    output_dir='.',
    overwrite_if_exists=False,
    skip_if_file_exists=False,
    context_key=None,
    accept_hooks=True,
):
    """Render the templates and saves them to files.

    :param repo_dir: Project template input directory.
    :param context: Dict for populating the template's variables.
    :param output_dir: Where to output the generated project dir into.
    :param overwrite_if_exists: Overwrite the contents of the output directory
        if it exists.
    :param accept_hooks: Accept pre and post hooks if set to `True`.
    """
    if not context_key:
        context_key = next(iter(context))

    template_dir = find_template(repo_dir, context_key)
    if template_dir:
        envvars = context.get(context_key, {}).get('_jinja2_env_vars', {})

        unrendered_dir = os.path.split(template_dir)[1]
        ensure_dir_is_templated(unrendered_dir)
        env = StrictEnvironment(context=context,
                                keep_trailing_newline=True,
                                **envvars)
        try:
            project_dir, output_directory_created = render_and_create_dir(
                unrendered_dir, context, output_dir, env, overwrite_if_exists)
        except UndefinedError as err:
            msg = "Unable to create project directory '{}'".format(
                unrendered_dir)
            raise UndefinedVariableInTemplate(msg, err, context)

        # We want the Jinja path and the OS paths to match. Consequently, we'll:
        #   + CD to the template folder
        #   + Set Jinja's path to '.'
        #
        #  In order to build our files to the correct folder(s), we'll use an
        # absolute path for the target folder (project_dir)

        project_dir = os.path.abspath(project_dir)
        logger.debug('Project directory is %s', project_dir)

        # if we created the output directory, then it's ok to remove it
        # if rendering fails
        delete_project_on_failure = output_directory_created

        if accept_hooks:
            _run_hook_from_repo_dir(
                repo_dir,
                'pre_gen_project',
                project_dir,
                context,
                delete_project_on_failure,
            )

        with work_in(template_dir):
            env.loader = FileSystemLoader('.')

            for root, dirs, files in os.walk('.'):
                # We must separate the two types of dirs into different lists.
                # The reason is that we don't want ``os.walk`` to go through the
                # unrendered directories, since they will just be copied.
                copy_dirs = []
                render_dirs = []

                for d in dirs:
                    d_ = os.path.normpath(os.path.join(root, d))
                    # We check the full path, because that's how it can be
                    # specified in the ``_copy_without_render`` setting, but
                    # we store just the dir name
                    if is_copy_only_path(d_, context):
                        copy_dirs.append(d)
                    else:
                        render_dirs.append(d)

                for copy_dir in copy_dirs:
                    indir = os.path.normpath(os.path.join(root, copy_dir))
                    outdir = os.path.normpath(os.path.join(project_dir, indir))
                    outdir = env.from_string(outdir).render(**context)
                    logger.debug('Copying dir %s to %s without rendering',
                                 indir, outdir)
                    shutil.copytree(indir, outdir)

                # We mutate ``dirs``, because we only want to go through these dirs
                # recursively
                dirs[:] = render_dirs
                for d in dirs:
                    unrendered_dir = os.path.join(project_dir, root, d)
                    try:
                        render_and_create_dir(
                            unrendered_dir,
                            context,
                            output_dir,
                            env,
                            overwrite_if_exists,
                        )
                    except UndefinedError as err:
                        if delete_project_on_failure:
                            rmtree(project_dir)
                        _dir = os.path.relpath(unrendered_dir, output_dir)
                        msg = "Unable to create directory '{}'".format(_dir)
                        raise UndefinedVariableInTemplate(msg, err, context)

                for f in files:
                    infile = os.path.normpath(os.path.join(root, f))
                    if is_copy_only_path(infile, context):
                        outfile_tmpl = env.from_string(infile)
                        outfile_rendered = outfile_tmpl.render(**context)
                        outfile = os.path.join(project_dir, outfile_rendered)
                        logger.debug('Copying file %s to %s without rendering',
                                     infile, outfile)
                        shutil.copyfile(infile, outfile)
                        shutil.copymode(infile, outfile)
                        continue
                    try:
                        generate_file(
                            project_dir,
                            infile,
                            context,
                            env,
                            skip_if_file_exists,
                            context_key,
                        )
                    except UndefinedError as err:
                        if delete_project_on_failure:
                            rmtree(project_dir)
                        msg = "Unable to create file '{}'".format(infile)
                        raise UndefinedVariableInTemplate(msg, err, context)

        if accept_hooks:
            _run_hook_from_repo_dir(
                repo_dir,
                'post_gen_project',
                project_dir,
                context,
                delete_project_on_failure,
            )

            for o in post_gen_operator_list:
                o.execute()

            return project_dir
    else:
        if accept_hooks:
            _run_hook_from_repo_dir(
                repo_dir,
                'post_gen_project',
                '.',  # TODO: This needs context switching
                context,
                False,
            )

        for o in post_gen_operator_list:
            o.execute()
        return None
def env():
    environment = StrictEnvironment()
    environment.loader = FileSystemLoader('.')
    return environment
Example #21
0
def generate_files(repo_dir,
                   context=None,
                   output_dir='.',
                   overwrite_if_exists=False):
    """Render the templates and saves them to files.

    :param repo_dir: Project template input directory.
    :param context: Dict for populating the template's variables.
    :param output_dir: Where to output the generated project dir into.
    :param overwrite_if_exists: Overwrite the contents of the output directory
        if it exists.
    """
    template_dir = find_template(repo_dir)
    logging.debug('Generating project from {0}...'.format(template_dir))
    context = context or {}

    unrendered_dir = os.path.split(template_dir)[1]
    ensure_dir_is_templated(unrendered_dir)
    env = StrictEnvironment(
        context=context,
        keep_trailing_newline=True,
    )
    try:
        project_dir = render_and_create_dir(unrendered_dir, context,
                                            output_dir, env,
                                            overwrite_if_exists)
    except UndefinedError as err:
        msg = "Unable to create project directory '{}'".format(unrendered_dir)
        raise UndefinedVariableInTemplate(msg, err, context)

    # We want the Jinja path and the OS paths to match. Consequently, we'll:
    #   + CD to the template folder
    #   + Set Jinja's path to '.'
    #
    #  In order to build our files to the correct folder(s), we'll use an
    # absolute path for the target folder (project_dir)

    project_dir = os.path.abspath(project_dir)
    logging.debug('project_dir is {0}'.format(project_dir))

    _run_hook_from_repo_dir(repo_dir, 'pre_gen_project', project_dir, context)

    with work_in(template_dir):
        env.loader = FileSystemLoader('.')

        for root, dirs, files in os.walk('.'):
            # We must separate the two types of dirs into different lists.
            # The reason is that we don't want ``os.walk`` to go through the
            # unrendered directories, since they will just be copied.
            copy_dirs = []
            render_dirs = []

            for d in dirs:
                d_ = os.path.normpath(os.path.join(root, d))
                # We check the full path, because that's how it can be
                # specified in the ``_copy_without_render`` setting, but
                # we store just the dir name
                if copy_without_render(d_, context):
                    copy_dirs.append(d)
                else:
                    render_dirs.append(d)

            for copy_dir in copy_dirs:
                indir = os.path.normpath(os.path.join(root, copy_dir))
                outdir = os.path.normpath(os.path.join(project_dir, indir))
                logging.debug('Copying dir {0} to {1} without rendering'
                              ''.format(indir, outdir))
                shutil.copytree(indir, outdir)

            # We mutate ``dirs``, because we only want to go through these dirs
            # recursively
            dirs[:] = render_dirs
            for d in dirs:
                unrendered_dir = os.path.join(project_dir, root, d)
                try:
                    render_and_create_dir(unrendered_dir, context, output_dir,
                                          env, overwrite_if_exists)
                except UndefinedError as err:
                    rmtree(project_dir)
                    _dir = os.path.relpath(unrendered_dir, output_dir)
                    msg = "Unable to create directory '{}'".format(_dir)
                    raise UndefinedVariableInTemplate(msg, err, context)

            for f in files:
                infile = os.path.normpath(os.path.join(root, f))
                if copy_without_render(infile, context):
                    outfile_tmpl = env.from_string(infile)
                    outfile_rendered = outfile_tmpl.render(**context)
                    outfile = os.path.join(project_dir, outfile_rendered)
                    logging.debug('Copying file {0} to {1} without rendering'
                                  ''.format(infile, outfile))
                    shutil.copyfile(infile, outfile)
                    shutil.copymode(infile, outfile)
                    continue
                logging.debug('f is {0}'.format(f))
                try:
                    generate_file(project_dir, infile, context, env)
                except UndefinedError as err:
                    rmtree(project_dir)
                    msg = "Unable to create file '{}'".format(infile)
                    raise UndefinedVariableInTemplate(msg, err, context)

    _run_hook_from_repo_dir(repo_dir, 'post_gen_project', project_dir, context)

    return project_dir
Example #22
0
def parse_operator(
    context,
    key,
    cc_dict,
    append_key: bool = False,
    no_input: bool = False,
    context_key=None,
):
    """Parse input dict for loop and when logic and calls hooks.

    :return: cc_dict
    """
    global post_gen_operator_list
    if not context_key:
        context_key = next(iter(context))

    env = StrictEnvironment(context=context)
    logger.debug("Parsing context_key: %s and key: %s" % (context_key, key))
    operator_dict = context[context_key][key]

    when_condition = evaluate_when(operator_dict, env, cc_dict, context_key)

    if when_condition:
        # Extract loop
        if 'loop' in operator_dict:
            loop_targets = render_variable(
                env, operator_dict['loop'], cc_dict, context_key
            )
            operator_dict.pop('loop')

            loop_output = []
            for i, l in enumerate(loop_targets):
                loop_cookiecutter = cc_dict
                loop_cookiecutter.update({'index': i, 'item': l})
                loop_output += [
                    parse_operator(
                        context,
                        key,
                        loop_cookiecutter,
                        append_key=True,
                        no_input=no_input,
                    )
                ]

            cc_dict.pop('item')
            cc_dict.pop('index')
            cc_dict[key] = loop_output
            return cc_dict

        if 'block' not in operator_dict['type']:
            operator_dict = render_variable(env, operator_dict, cc_dict, context_key)

        # Run the operator
        if operator_dict['merge'] if 'merge' in operator_dict else False:
            to_merge, post_gen_operator = run_operator(
                operator_dict, context, no_input, context_key, cc_dict, env
            )
            cc_dict.update(to_merge)
        else:
            cc_dict[key], post_gen_operator = run_operator(
                operator_dict, context, no_input, context_key, cc_dict, env, key
            )
        if post_gen_operator:
            post_gen_operator_list.append(post_gen_operator)

        if append_key:
            return cc_dict[key]

    return cc_dict
Example #23
0
def env():
    """Fixture. Set Jinja2 environment settings for other tests."""
    environment = StrictEnvironment()
    environment.loader = FileSystemLoader('.')
    return environment
def test_env_should_come_with_jinja2_time_extension():
    env = StrictEnvironment(keep_trailing_newline=True)
    assert "jinja2_time.jinja2_time.TimeExtension" in env.extensions