Skip to content

Frequently Asked Questions

How can I alter the context before rendering the project?

Similar questions:

  • How can I add/remove variables to/from the rendering context?
  • How to infer context variables based on the users answers, without prompting users?

Answer:

Use the ContextHook extension.

The ContextHook extension lets you modify the context used to render templates, so that you can add, change or remove variables.

In order for Copier to be able to load and use the extension when generating a project, it must be installed alongside Copier itself. More details in the jinja_extensions docs.

You can then configure your Jinja extensions in Copier's configuration file:

copier.yaml
_jinja_extensions:
    - copier_templates_extensions.TemplateExtensionLoader
    - extensions/context.py:ContextUpdater

Following this example, you are supposed to provide a context.py file in the extensions folder at the root of your template to modify the context. If for example your copier.yaml contains a multiple-choice variable like this:

copier.yaml
flavor:
    type: str
    choices:
        - Docker
        - Instances
        - Kubernetes
        - None

The context.py file contains your context hook which could look like:

extensions/context.py
from copier_templates_extensions import ContextHook


class ContextUpdater(ContextHook):
    def hook(self, context):
        flavor = context["flavor"]  # user's answer to the "flavor" question
        return {
            "isDocker": flavor == "docker"
            "isK8s": flavor == "kubernetes"
            "isInstances": flavor == "instances"
            "isLite": flavor == "none"
            "isNotDocker": flavor != "docker"
            "isNotK8s": flavor != "kubernetes"
            "isNotInstances": flavor != "instances"
            "isNotLite": flavor != "none"
            "hasContainers": flavor in {"docker", "kubernetes"}
        }

Before rendering each templated file/folder, the context will be updated with this new context object that you return from the hook. If you wish to update the context in-place rather than update it, set the update class attribute to false:

extensions/context.py
from copier_templates_extensions import ContextHook


class ContextUpdater(ContextHook):
    update = False

    def hook(self, context):
        flavor = context["flavor"]  # user's answer to the "flavor" question

        context["isDocker"] = flavor == "docker"
        context["isK8s"] = flavor == "kubernetes"
        context["isInstances"] = flavor == "instances"
        context["isLite"] = flavor == "none"

        context["isNotDocker"] = flavor != "docker"
        context["isNotK8s"] = flavor != "kubernetes"
        context["isNotInstances"] = flavor != "instances"
        context["isNotLite"] = flavor != "none"

        context["hasContainers"] = context["isDocker"] or context["isK8s"]

        # you can now actually remove items from the context
        del context["flavor"]

Now you can use these added variables in your Jinja templates, and in files and folders names!

Back to top