Templating#
Prept provides a simple yet flexible templating system that allows generating boilerplate files with values provided by user at generation time.
Terminologies#
There are a few terms that Prept uses related to templates:
Template Variables: variables whose values are provided by user at generation time
Template Provider: a middleware that processes template files and injects variable values.
Template Files: the files in which variable values are to be injected.
Basic Usage#
This small subsection quickly showcases how templating is performed. Check example shown on Getting Started page as well for more detailed understanding.
Defining Providers#
Boilerplates must define a template provider using the template_provider option in
configuration file as shown:
{
"name": "basic-boilerplate",
"template_provider": "stringsub"
}
This defines StringTemplateProvider to be used as template provider which uses dollar sign
syntax for variable substitutions.
Defining Variables#
Template variables are defined through the template_variables option in configuration file and their
values are provided by user at the generation time.
This option takes a mapping with key being the variable name and value representing the information about that variable.
For example, the following configuration defines a single template variable APP_NAME:
{
"name": "basic-boilerplate",
"template_provider": "stringsub",
"template_variables": {
"APP_NAME": {
"summary": "The name of application."
}
}
}
summary is the description of variable. It is not required to supply this option but is
recommended to be set as it is displayed at the time of generation and can contain useful information about the variable.
Defining Files#
template_files is an array of gitignore-like file patterns that define the files that are
regarded as “template.” These files are sent to template provider at generation time for variables injection.
For example:
{
"name": "basic-boilerplate",
"template_provider": "stringsub",
"template_variables": {
"APP_NAME": {
"summary": "The name of application.",
"required": true
}
},
"template_files": [
"core/*",
"main.py"
]
}
This defines all files in src directory as template along with the main.py file as well.
Generating Project#
With the configuration shown above, we can run prept new and we will be prompted to enter the
value of APP_NAME variable. Input value will be injected into the template files in generated project.
$ prept new basic-boilerplate -O my-app
INFO Generating project from boilerplate: basic-boilerplate
INFO No existing directory found. Creating project directory at 'D:\Projects\my-app'
INFO Successfully created project directory at D:\Projects\my-app
INFO Processing template variables
OPTION The name of application.
APP_NAME (required): Chat Application
INFO Creating project files at 'D:\Projects\my-app'
├── Creating my-app\main.py ... DONE
├── Applying template on my-app\main.py ... DONE
├── Creating my-app\routers\groups.py ... DONE
├── Creating my-app\routers\messages.py ... DONE
├── Creating my-app\routers\users.py ... DONE
├── Creating my-app\core\utils.py ... DONE
├── Applying template on my-app\core\utils.py ... DONE
SUCCESS Successfully generated project from 'basic-boilerplate' boilerplate at 'D:\Projects\my-app'
Alternatively, we can pass the value of variables through -V or --var
option which takes two values: the variable name and its value. For example:
$ prept new basic-boilerplate -O ./basic_project -V APP_NAME "Chat Application"
Template Providers#
Template provider is a simple middleware function (class) that is called by Prept and it processes the template file’s content, injecting the variable values into it.
Typically, variable values are injected into file content by template provider through some templating
language (like Jinja, as by Jinja2TemplateProvider).
Built-in Providers#
Prept provides two built-in template providers:
stringsub(StringTemplateProvider) based on $-substitutionsjinja2(Jinja2TemplateProvider) based on Jinja templates
Provider Name#
As shown in Defining Providers, template providers are defined
using the template_provider option. It takes the name of a template provider
in either of the following formats:
provider_nameprovider_classmodule:provider_namemodule:provider_class
provider_name is the name of template provider such as stringsub for StringTemplateProvider
and provider_class is the name of template provider class such as StringTemplateProvider. For example:
{
"name": "basic-boilerplate",
"template_provider": "stringsub"
}
module is simply the name of a Python package or module. When using third party or custom template providers,
they must referred by including the module name as well that provides the template provider separating the module
name and provider name/class with double colon ::.
For example:
{
"name": "basic-boilerplate",
"template_provider": "foobar::simpletemp"
}
will resolve to simpletemp template provider from foobar package or module.
Note
The provider name or class name is passed to package’s get_prept_template_provider() resolver
function which returns the template provider that is called by Prept.
More detail on defining custom template providers and this resolver function will be covered in a later section.
Template Variables#
Template variables are variables whose values (provided at generation time) are injected by template provider into template files.
Variable Name#
Variable names must pass the following set of rules:
Can only contain alphanumeric and underscores characters.
Must begin with letter or underscore.
Case sensitive
Variable Summary#
Defining Variables describes how variables are defined through the
template_variable option which takes a mapping whose values describe the variable.
Each variable can take an optional summary option which is the brief description
of variable. This description is shown at the time of generation and can contain useful information about
the variable.
{
"template_variables": {
"APP_NAME": {
"summary": "The name of application." // displayed at generation time
}
}
}
Required and Optional Variables#
By default, all template variables are required. That is, their values must be provided by user at generation time.
It is possible to declare optional variables whose values may be omitted. This is acheived at
through required option (true by default).
{
"template_variables": {
"APP_NAME": {
"required": false // optional variable
}
}
}
Optional variables without any default are given no value at generation time. More specifically,
their values are not present in the GenerationContext.variables mapping which is used
to inject variables into template files.
Default Values#
Optional variables can be given a “default” value which is assigned to variable if it is not provided. For example:
{
"template_variables": {
"APP_NAME": {
"default": "Web App"
}
}
}
Note that whenever a default is set, the value set for required is implicitly
determined as false regardless of the value set to it. Variable with defaults are always optional.
Arbitrary Variables#
By default, Prept forbids passing invalid variables through the prept new -V option. However, this
can be allowed by setting allow_extra_variables to true on boilerplate
configuration.
{
"template_variables": {
"APP_NAME": {
"summary": "The application name"
}
},
"allow_extra_variables": true // allows arbitrary variables through -V option
}
The extra variables’ values are added to the GenerationContext.variables mapping used
for injecting variable values into template files.
Variables Input#
There are two modes of providing variable while generating boilerplates: through the prept new -V option, or
through the input prompts in prept new command output.
By default, Prept will prompt the user to input variables that were not provided through the -V
option. This behaviour can be changed using the variable_input_mode setting. It can take the following values:
all(default)required_onlyoptional_onlynone
all is the default value and with this set, Prept will prompt the user to input all variables that
were not provided by -V option regardless of whether the variable is required or not.
With required_only and optional_only, the user is prompted to only input the required and optional
variables respectively. none completely disables variables input prompt.
In each case, the variables that are not taken through input should be provided through -V
option. Specifically, with optional_only and none setting, required variables must be provided through
-V otherwise an error is thrown.
Template Paths#
There are cases when you want to inject template variables into a file or directory name. For example, there may be a directory in your boilerplate that is named after the application’s name which is provided by user.
Like template_files, we also have template_paths which are path
(or roughly speaking file or directory names) that are treated as templates.
Consider the following boilerplate directory structure:
python-web-app
│
├── $APP_NAME
│ │
│ ├── routers
│ │ ├── users.py
│ │ ├── messages.py
│ │ └── groups.py
│ │
│ └── utils.py
│
└── main.py
Here, we are looking to substitute $APP_NAME variable’s value.
We define the following boilerplate configuration in preptconfig.json:
{
"name": "python-web-app",
"template_paths": [
"$APP_NAME"
],
"template_provider": "stringsub",
"template_variables": {
"APP_NAME": {
"summary": "The name of application."
}
}
}
When we run the prept new command, we are prompted to input APP_NAME and that
value is substituted into the directory name by string substitution template provider.
With prept new python-web-app -V APP_NAME chat-app command, the generated project has the
following structure:
python-web-app
│
├── chat-app
│ │
│ ├── routers
│ │ ├── users.py
│ │ ├── messages.py
│ │ └── groups.py
│ │
│ └── utils.py
│
└── main.py