Generate
Introduction
The Generate Extension includes the Generate controller, and provides a mechanism for generating common content from template directories. An example use case would be the ability for application developers to easily generate new plugins for their application… similar in other applications such as Chef Software’s chef generate cookbook type utilities.
The Cement Developer Tools use this extension to generate projects, plugins, extensions, scripts, etc for developers building their applications on the framework.
Documentation References:
API References:
Requirements
pyYaml
A valid template handler must be defined at the application level via
App.Meta.template_handlersuch asjinja2,mustache, etc.
Cement 3.0.8+:
pip install cement[generate]
Applications using Cement <3.0.8 should continue to include pyYaml in their dependencies.
Configuration
Application Configuration Settings
This extension honors the following settings under the primary namespace (ex: [myapp]) of the application configuration:
Setting
Description
template_dir
Directory path of a local template directory.
Application Meta Options
This extension honors the following App.Meta options:
Option
Description
template_handler
A template handler to use as the backend for templating
template_dirs
A list of data directories to look for templates
template_module
A python module to look for templates
Usage
Examples
Generate Templates
The Generate Extension looks for a generate sub-directory in all defined template directory paths defined at the application level. If it finds a generate directory it treats all items within that directory as a generate template.
A Generate Template requires a single configuration YAML file called .generate.yml that looks something like:
Generate Template Configuration
The following configurations are supported in a generate template’s config:
ignore
A list of regular expressions to match files that you want to completely ignore
exclude
A list of regular expressions to match files that you want to copy only (not rendered as template)
variables
A list of variable definitions that support the following sub-keys:
Variable Definition Sub-Keys
Key
Description
name
The variable name exposed to the template context (required)
prompt
The prompt displayed to the user. Use prompt: false for a silent variable that takes its default without prompting (requires default)
default
Default value (used on empty input, and as the value for --defaults runs)
case
Optional case transform applied to the value: one of lower, upper, title
validate
Optional regular expression the value must match (generation aborts on mismatch)
type
Cement 3.0.16+ — one of string (default), boolean, choice. See Typed Variables below
extend
Cement 3.0.16+ — list of conditional-effect rules keyed on the resolved value. See extend:
requires
Cement 3.0.16+ — gate this variable on other top-level variables. See requires:
Typed Variables
Cement 3.0.16+
Typed variables let a generate template offer optional features — Y/N toggles and multi-choice pickers that conditionally prompt for extra variables, skip files, and gate on one another. Everything lives in the single variables: list of .generate.yml; each entry may carry a type: and optional extend: / requires: keys.
The mental model:
A
booleanorchoicevariable resolves to a real typed value at the top level of the template context — so{% if docker %}and
{% if web_framework == "flask" %}work directly.An
extend:rule fires when the resolved value matches itswhen:, contributing extravariables:(prompted in place),ignore:patterns (files skipped), andexclude:patterns (files copied verbatim).A
requires:key gates a variable on other variables — if the gate fails, the variable is silently resolved to itsdefaultand none of itsextend:rules fire.
type: string
type: stringThe classic variable — a plain {name, prompt, default} entry with optional case: / validate:. Omitting type: is equivalent to type: string, so existing templates are unaffected.
type: boolean
type: booleanA single y/N prompt rendered as <prompt> [(Y)es/(N)o] [<default>]:. With no prompt: key the label defaults to Enable <name>. Input y/yes maps to True, n/no to False, empty input to default. The resolved value is a real Python bool:
For full control of the wording and accepted tokens, give prompt: an object — accept: / reject: are case-insensitive token lists that map the answer to a bool (input matching neither aborts, like a failed validate:):
Quote bool-like tokens ("yes", "no", "on", "off") inside accept: / reject: — under YAML 1.1 they otherwise decode to a Python bool and the loader rejects them with a clear ValueError.
type: choice
type: choiceA numbered picker. Each option is either a bare scalar or an object with value: (required — the string the variable resolves to) and an optional prompt: label for the numbered list:
default: is required and must equal one of the option values (validated at config load). It is used on empty input and for --defaults runs.
extend: — conditional effects
extend: — conditional effectsEach variable may carry an extend: list. A rule fires when its when: matches the resolved value:
Match form
Example
Applies to
Scalar equality
when: true / when: "flask"
all types
In-list membership
when: ["flask", "fastapi"]
all types
Regular expression
when: "^3\\."
string variables only
A firing rule contributes:
Key
Effect
variables
Extra variables prompted in place, in declaration order (use prompt: false for silent values like versions)
ignore
Regex patterns for files to skip entirely
exclude
Regex patterns for files to copy verbatim (not rendered as templates)
Multiple matching rules compose. An explicit YAML null block (e.g. ignore: with no items) coalesces to an empty list — it does not error.
requires: — variable gating
requires: — variable gatingA variable may be gated on other top-level variables:
Three forms are supported:
Form
Example
Meaning
List
requires: [docker]
each named variable is truthy
Map
requires: {web_framework: flask}
equality
Map+list
requires: {web_framework: [flask, fastapi]}
in-list membership
Multiple entries are AND-ed and resolve order-independently — prerequisites are resolved (and prompted) before their dependents, regardless of declaration order. Interactive prompting is lazy: declining a prerequisite skips the dependent's prompt entirely.
Gated-out is not forced-off. When a requires: gate fails, the variable resolves to its (typed) default — it is not prompted, and none of its extend: rules fire. If the dependent's default is true, its files still render (only its when: false cleanup is skipped). If you want "declining the prerequisite drops the dependent's files too", put those ignore: patterns on the prerequisite's when: false rule.
A requires: gate can only reference other top-level variable names (nested extend.variables are not addressable), and a gated variable must have a default: — a missing default raises ValueError.
CLI Invocation
Using Values in Templates
Resolved values land at the top level of the template context — booleans as real bools, choices as strings, and any extend.variables injected by a firing rule as ordinary top-level variables:
A boolean rendered as text ({{ docker }}) interpolates the capitalized Python repr — True / False — not true/false. This applies to both the jinja2 and mustache handlers. Use conditionals ({% if docker %}, mustache {{#docker}} / {{^docker}}) to gate content; only direct text interpolation shows the repr.
Worked Example
The Cement source tree ships a complete working example under demo/generate-features/ — a webapp template combining a string variable (project_name), two booleans (docker, and docker_compose which requires: [docker]), and a choice (web_framework: none/flask/fastapi) with per-branch silent version variables.
Generated with --defaults (docker on, compose on, no framework):
Generated with web_framework=fastapi (everything else default):
Authoring Checklist
Start with your base
variables:(plain strings) and template files.Bucket the optional content — which files/variables belong to which toggle?
Add a
type: boolean(orchoice) variable per toggle.Add
when: false(or per-choice)ignore:rules for files to drop — remembering that a dependent's cleanup belongs on its prerequisite's decline branch if it must cascade.Add
extend.variablesfor follow-up prompts (or silentprompt: falsemetadata) on the enabling branch.Add
requires:for dependencies between toggles.Gate rendered content inside files with
{% if <name> %}.Test both paths:
--defaultsand an interactive run that declines each toggle.
Pitfalls & Validation
excludevsignore—excludestill copies the file (verbatim, no rendering);ignoredrops it entirely.Anchor your regexes loosely — patterns match against full paths, so use
'.*Dockerfile.*', not'Dockerfile'.Cyclic
requires(A requires B, B requires A) fails fast with a clearValueError— it will not hang or recurse.requiresreferences variable names only — top-levelvariables:entries, not arbitrary template variables or nestedextend.variables.Schema violations raise
ValueErrorat config load (they survivepython -O, unlike assertions): achoicewith empty/missingoptions, adefaultnot present inoptions, option objects withoutvalue:, bool-decoded tokens inaccept:/reject:, arequires:-gated variable without adefault, andrequires:naming an unknown variable.
Last updated