Cookiecutter Template Dependency Management

211 Views Asked by At

I'm developing a cookiecutter template. My template has some dependencies. For example, in hooks/post_gen_project.py I want to show a message using rich.print. How can I satisfy such a requirement?

Also, I've seen many cookiecutter templates with either setup.py, pyproject.toml, or setup.cfg files included in their root directory. What is the point of that?! At first, I thought that might be a way to add dependencies to my template but that didn't work and wondering about the whole idea behind that. Unfortunately, cookiecutter has a weak documentation describing all these concepts and details!

Thanks.

1

There are 1 best solutions below

0
Sadra On

Solution 1

A practice would be installing the dependencies within the pre_gen_project.py hook file.

try:
    import rich
except ModuleNotFoundError:
    import subprocess

    subprocess.run(
        [
            "pip",
            "install",
            "--disable-pip-version-check",
            "--no-python-version-warning",
            "-q",
            "rich",
        ]
    )

This way, right before when post_gen_project gets triggered, it installs rich so that you can use rich.print in post_gen_project.py with no issues.

Solution 2

Another solution would be to keep a cc_requirements.txt file within your {{cookiecutter.project_slug}}/ (or wherever you keep the template files) and put all your dependencies there.

rich==<desired-version>

Then, in post_gen_project.py file, use the following instruction to..

  • firstly, install the dependencies.
  • secondly, remove the cc_requirements.txt file.

Here would be the content of post_gen_project.py file.

import os

# ...

PROJECT_DIRECTORY = os.path.realpath(os.path.curdir)

def remove_file(filepath: str) -> None:
    """removes a file

    Args:
        filepath (str): path to file
    """
    os.remove(os.path.join(PROJECT_DIRECTORY, filepath))


def install_requirements():
    requirements_file = os.path.join(PROJECT_DIRECTORY, "cc_requirements.txt")
    subprocess.check_call(
        [
            "pip",
            "install",
            "--disable-pip-version-check",
            "--no-python-version-warning",
            "-qUr",
            requirements_file,
        ]
    )
    remove_file(requirements_file)

# ...

if __name__ == "__main__":
    ...
    install_requirements()
    import rich
    # ...

setup.py, setup.cfg, pyproject.toml

These files are often there for the sake of managing the metadata corresponding to the template. Some specific metadata keywords are just needed from those files such as version and not all of them. For instance, if you look around the packages keyword in those files, they are empty most of the time meaning when someone tries installing them, ultimately, nothing (functional) actually gets shipped!