Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added: Templates inheritance #1485

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cookiecutter/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def generate_files(
)

with work_in(template_dir):
env.loader = FileSystemLoader('.')
env.loader = FileSystemLoader(['.', '../templates'])
simobasso marked this conversation as resolved.
Show resolved Hide resolved

for root, dirs, files in os.walk('.'):
# We must separate the two types of dirs into different lists.
Expand Down
1 change: 1 addition & 0 deletions docs/advanced/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Various advanced topics regarding cookiecutter usage.
replay
choice_variables
dict_variables
templates
template_extensions
directories
new_line_characters
Expand Down
34 changes: 34 additions & 0 deletions docs/advanced/templates.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.. _templates:

Templates inheritance (2.2+)
---------------------------------------------------

*New in Cookiecutter 2.2+*

Sometimes you need to extend a base template with a different
configuration to avoid nested blocks.

Cookiecutter introduces the ability to use common templates
using the power of jinja: `extends`, `include` and `super`.

Here's an example repository::

https://github.com/user/repo-name.git
├── {{cookiecutter.project_slug}}/
| └── file.txt
├── templates/
| └── base.txt
└── cookiecutter.json

every file in the `templates` directory will become referable inside the project itself,
and the path should be relative from the `templates` folder like ::

# file.txt
{% extends "base.txt" %}

... or ...

# file.txt
{% include "base.txt" %}

see more on https://jinja.palletsprojects.com/en/2.11.x/templates/
5 changes: 5 additions & 0 deletions tests/test-templates/extends/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"project_slug": "foobar",
"command_line_interface": "click",
"use_pytest": "y"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pip==19.2.3
{% if cookiecutter.command_line_interface|lower == 'click' -%}
{% include 'click-requirements.jinja' %}{% endif %}
{% if cookiecutter.use_pytest == 'y' -%}
{% include 'pytest-requirements.jinja' %}{% endif %}
{% block dependencies %}{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Click==7.0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest==4.6.5
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% extends "base-requirements.jinja" %}
5 changes: 5 additions & 0 deletions tests/test-templates/include/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"project_slug": "foobar",
"command_line_interface": "click",
"use_pytest": "y"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Click==7.0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest==4.6.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pip==19.2.3
{% if cookiecutter.command_line_interface|lower == 'click' -%}
{% include 'click-requirements.jinja' %}{% endif %}
{% if cookiecutter.use_pytest == 'y' -%}
{% include 'pytest-requirements.jinja' %}{% endif %}
5 changes: 5 additions & 0 deletions tests/test-templates/no-templates/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"project_slug": "foobar",
"command_line_interface": "click",
"use_pytest": "y"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pip==19.2.3
{% if cookiecutter.command_line_interface|lower == 'click' -%}
Click==7.0{% endif %}
{% if cookiecutter.use_pytest == 'y' -%}
pytest==4.6.5{% endif %}
5 changes: 5 additions & 0 deletions tests/test-templates/super/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"project_slug": "foobar",
"command_line_interface": "click",
"use_pytest": "y"
}
7 changes: 7 additions & 0 deletions tests/test-templates/super/templates/base-requirements.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pip==19.2.3
{% if cookiecutter.command_line_interface|lower == 'click' -%}
{% include 'click-requirements.jinja' %}{% endif %}
{%- block dev_dependencies %}
{% if cookiecutter.use_pytest == 'y' -%}{% include 'pytest-requirements.jinja' %}{% endif %}
{%- endblock %}
{% block dependencies %}{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Click==7.0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest==4.6.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% extends "base-requirements.jinja" %}
{% block dev_dependencies %}{{ super() }}{% endblock %}
43 changes: 43 additions & 0 deletions tests/test_templates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
test_custom_extension_in_hooks.

Tests to ensure custom cookiecutter extensions are properly made available to
pre- and post-gen hooks.
"""
import codecs
import os

import pytest

from cookiecutter import main


@pytest.fixture
def output_dir(tmpdir):
"""Fixture. Create and return custom temp directory for test."""
return str(tmpdir.mkdir('templates'))


@pytest.mark.parametrize("template", ["include", "no-templates", "extends", "super"])
def test_build_templates(template, output_dir):
"""
Verify Templates Design keywords.

no-templates is a compatibility tests for repo without `templates` directory
"""
project_dir = main.cookiecutter(
f'tests/test-templates/{template}',
no_input=True,
output_dir=output_dir,
)

readme_file = os.path.join(project_dir, 'requirements.txt')

with codecs.open(readme_file, encoding='utf8') as f:
readme = f.read().splitlines()

assert readme == [
"pip==19.2.3",
"Click==7.0",
"pytest==4.6.5",
]