Usage

The copie fixture will allow you to copy a template and run tests against it. It will also clean up the generated project after the tests have been run.

For these examples, let’s assume the current folder is a copier template. it should include a copier.yml file and a template folder containing jinja templates.

Note

The name of the templlate folder can be anything as long as it matches the _subdirectory key in the copier.yml file.

demo_template/
├── template
│   └── README.rst.jinja
├── tests/
│   └── test_template.py
└── copier.yaml

the copier.yaml file has the following content:

repo_name:
   type: str
   default: foobar
short_description:
   type: str
   default: Test Project
_subdirectory: template

And the readme template is:

{{ repo_name }}
===============

{{ short_description }}

default project

Use the following code in your test file to generate the project with all the default values:

def test_template(copie):
    result = copie.copy()

    assert result.exit_code == 0
    assert result.exception is None
    assert result.project_dir.is_dir()
    with open(result.project_dir / "README.rst") as f:
       assert f.readline() == "foobar\n"

It will generate a new repository based on your template, eg:

foobar/
└── README.rst

the Return object can then be used to access the process outputs:

  • result.project_dir

  • result.exception

  • result.exit_code

  • result.answers

The temp folder will be cleaned up after the test is run.

Custom answers

Use the extra_answers parameter to pass custom answers to the copier.yaml questions. The parameter is a dictionary with the question name as key and the answer as value.

def test_template_with_extra_answers(copie):
    result = copie.copy(extra_answers={"repo_name": "helloworld"})

    assert result.exit_code == 0
    assert result.exception is None
    assert result.project_dir.is_dir()
    with open(result.project_dir / "README.rst") as f:
       assert f.readline() == "helloworld\n"

Custom template

By default copy() looks for a copier template in the current directory. This can be overridden on the command line by passing a --template parameter to pytest:

pytest --template TEMPLATE

You can also customize the template directory from a test by passing in the optional template parameter:

@pytest.fixture
def custom_template(tmp_path) -> Path:
    # Create custom copier template directory
    (template := tmp_path / "copier-template").mkdir()
    questions = {"custom_name": {"type": "str", "default": "my_default_name"}}
    # Create custom subdirectory
    (repo_dir := template / "custom_template").mkdir()
    questions.update({"_subdirectory": "custom_template"})
    # Write the data to copier.yaml file
    (template /"copier.yaml").write_text(yaml.dump(questions, sort_keys=False))
    # Create custom template text files
    (repo_dir / "README.rst.jinja").write_text("{{custom_name}}\n")

    return template


def test_copie_custom_project(copie, custom_template):

    result = copie.copy(
      template_dir=custom_template, extra_answers={"custom_name": "tutu"}
   )

    assert result.project_dir.is_dir()
    with open(result.project_dir / "README.rst") as f:
       assert f.readline() == "tutu\n"

Important

The template parameter will override any --template parameter passed on the command line.

Keep output

By default copie fixture removes copied projects at the end of the test. However, you can pass the keep-copied-projects flag if you’d like to keep them in the temp directory.

Note

It won’t clutter as pytest only keeps the three newest temporary directories

pytest --keep-copied-projects