Quickstart tutorial

Let’s discover piecutter with simple stories!

Install piecutter

pip install piecutter

See Install for details and alternatives.

Import piecutter

>>> import piecutter

This single import should be enough in most cases.

Hello world!

Let’s produce the traditional Hello world! with minimal code:

>>> render = piecutter.Cutter()
>>> template = u'Hello {who}!'
>>> data = {u'who': u'world'}
>>> output = render(template, data)
>>> print(output.read())
Hello world!

Notes about this example:

  • text datatype is recognized as a template
  • the template engine is Python’s format() [1] by default
  • data is a mapping
  • output is a file-like object
  • piecutter.Cutter encapsulates full rendering pipeline.

Setup a template engine

piecutter uses Engines to render the templates against data.

piecutter has builtin support for the following template engines: Python’s format() [1], Jinja2 [2] and Django [3]. Additional engines could be supported, including non-Python ones!

Learn more about template engines at Engines.

Jinja2

Let’s produce Hello world! using Jinja2 [2]:

>>> template = u'Hello {{ who }}!'
>>> render = piecutter.Cutter(engine=piecutter.Jinja2Engine())
>>> output = render(template, data)
>>> print(output.read())
Hello world!

Django

We can do the same using Django [3]:

>>> template = u'Hello {{ who }}!'
>>> render = piecutter.Cutter(engine=piecutter.DjangoEngine())
>>> output = render(template, data)
>>> print(output.read())
Hello world!

Load templates from various locations

piecutter uses Loaders to fetch templates from various locations and to distinguish files from directories.

See loaders for details.

File-like objects

If you pass a file-like object to piecutter‘s default loader, it will automatically use it as a template.

As an example, let’s render an in-memory file:

>>> from StringIO import StringIO
>>> render = piecutter.Cutter()
>>> template = StringIO(u'Hello {who}!')
>>> output = render(template, data)
>>> print(output.read())
Hello world!

Of course, we can render an opened file object:

>>> render = piecutter.Cutter()
>>> with open('demo/simple/hello.txt') as template:
...     output = render(template, data)
...     print(output.read())
Hello world!

Templates on local filesystem

Use file:// (or file:/// for absolute paths) to tell piecutter‘s default loader to read templates on local filesystem:

>>> template = u'file://demo/simple/hello.txt'
>>> output = render(template, data)
>>> print(output.read())
Hello world!

Templates over HTTP

Use http:// or https:// to tell piecutter‘s default loader to fetch templates from remote HTTP server:

>>> template = u'https://raw.github.com/diecutter/piecutter/cutter-api-reloaded/demo/simple/hello.txt'
>>> output = render(template, data)
>>> print(output.read())
Hello world!

Additional loaders

Feel free to write custom loaders in order to support additional locations!

Basically, if you can determine template type (file or directory), fetch file contents and list directory items, you can implement a loader.

Render directories

Collections of templates, a.ka. directories, are also supported. By default, they are rendered as generator of rendered items.

Given the following directory:

demo/simple/
├── hello.txt  # Contains "Hello {who}!\n"
└── {who}.txt  # Contains "Whatever the content.\n"

When we render the directory, we can iterate generated items and use their attributes and methods:

>>> for item in render(u'file://demo/simple', data):
...     print('Name: {}'.format(item.name))
...     print('Content: {}'.format(item.read()))
Name: hello.txt
Content: Hello world!

Name: world.txt
Content: Whatever the content.

Write generated files to disk

piecutter uses writers to post-process generated content.

As an example, piecutter.FileWriter writes generated files to disk.

Let’s setup some output directory and check it does not exist yet.

>>> import os
>>> output_directory = os.path.join(temp_dir, 'directory')
>>> os.path.exists(output_directory)
False

Now generate files in output directory:

>>> render = piecutter.Cutter(
...     writer=piecutter.FileWriter(target=output_directory),
... )
>>> written_files = render('file://demo/simple/', data)

... and inspect the results:

>>> sorted(os.listdir(output_directory))
['simple']
>>> sorted(os.listdir(os.path.join(output_directory, 'simple')))
['hello.txt', 'world.txt']
>>> print(open(os.path.join(output_directory, 'simple', 'hello.txt'), 'rb').read())
Hello world!

>>> written_files  # Contains absolute path to generated files.
['/.../directory/simple/hello.txt', '/.../directory/simple/world.txt']

Learn more at Writers.

Notes & references

[1](1, 2) https://docs.python.org/2.7/library/string.html#formatstrings
[2](1, 2) http://jinja.pocoo.org/
[3](1, 2) https://docs.djangoproject.com/en/1.8/topics/templates/