Quick Start¶
cookiecutter_maker is a tool that converts existing projects into reusable cookiecutter templates. This is the reverse of the traditional cookiecutter workflow - instead of starting with a template, you start with a concrete project and transform it into a template.
Example: Creating a Template from an Existing Project¶
Let’s say we’ve found a project with a well-organized folder structure that we want to follow. Suppose we want to build our own open-source project using python requests as a starting point.
Step 1. Clone the repository:
git clone --branch v2.32.3 --depth 1 https://github.com/psf/requests
Step 2. Create and run a script to generate the template:
Create a Python script like the one below to convert the project into a cookiecutter template:
1# -*- coding: utf-8 -*-
2
3"""
4Convert a seed repo into a project template.
5
6This script demonstrates how to use
7`cookiecutter_maker <https://github.com/MacHu-GWU/cookiecutter_maker-project>`_
8to convert an existing project (in this case, the 'requests' library)
9into a cookiecutter template. The template can then be used to generate
10new projects with the same structure but customized parameters.
11"""
12
13import shutil
14from pathlib import Path
15from cookiecutter_maker.api import Parameter, Maker
16
17# Get the current directory and create a temporary directory for output
18dir_here: Path = Path(__file__).absolute().parent
19dir_tmp = dir_here.joinpath("tmp")
20
21# Clean up any existing temporary directory
22if dir_tmp.exists():
23 shutil.rmtree(dir_tmp)
24
25# Create a Maker instance to convert the project into a template
26maker = Maker(
27 # The input concrete project directory - the seed project you want to templatize
28 # In this case, we're using the 'requests' library as our seed
29 dir_input=dir_here.joinpath("requests"),
30
31 # The output template directory - where the generated template will be placed
32 dir_output=dir_tmp,
33
34 # Define parameters that will be customizable in the generated template
35 # Each Parameter defines:
36 # - selector: The concrete string in the original project to be replaced
37 # - name: The parameter name in the cookiecutter template
38 # - default: The default value that will appear in cookiecutter.json,
39 # if you set "default", then don't set "choice".
40 # - choice: Optional list of choices for the user to select from,
41 # if you set "choice", then don't set "default".
42 parameters=[
43 # Replace all occurrences of "requests" with the parameter "package_name"
44 Parameter(
45 selector=["requests"],
46 name="package_name",
47 default="your_package_name",
48 ),
49 # Replace the version number
50 Parameter(
51 selector=["2.32.3"],
52 name="package_version",
53 default="0.1.1",
54 ),
55 # Replace the author name
56 Parameter(
57 selector=["Kenneth Reitz"],
58 name="author",
59 default="Firstname Lastname",
60 ),
61 # Replace the author email
62 Parameter(
63 selector=["me@kennethreitz.org"],
64 name="author_email",
65 default="firstname.lastname@email.com",
66 ),
67 # You can add more parameters as needed for your template
68 # Examples:
69 # - GitHub username
70 # - Project description
71 # - License type (with choices)
72 # - Python version requirement
73 ],
74 # Define which files/directories to include in the template
75 # Empty list means include everything not explicitly excluded
76 # You can use patterns like "**/*.py" to include all Python files
77 # The rule is 'explicit exclude' > 'explicit include' > 'default include'
78 include=[],
79 # Define which files/directories to exclude from the template
80 # These files/directories will not be copied to the template
81 exclude=[
82 # Common directories to exclude
83 ".git", # Git repository data
84 ".venv", # Virtual environment
85 "__pycache__", # Python cache files
86 "*.pyc", # Compiled Python files
87 "build", # Build artifacts
88 "dist", # Distribution packages
89 ".pytest_cache", # Test cache
90 ".tox", # Tox testing environments
91 ".coverage", # Coverage data
92 "htmlcov", # HTML coverage reports
93 ],
94 # Files that should be copied without rendering (processing)
95 # Useful for files that contain syntax that conflicts with Jinja2
96 # For example, template files that already use {{ }} syntax
97 no_render=[
98 "*.jinja", # Jinja template files
99 "*.j2", # Alternative Jinja extension
100 "*.html", # HTML files with {{ }} syntax
101 ],
102 # Print detailed information during processing
103 verbose=True,
104)
105
106# Execute the template generation process
107maker.make_template()
108
109print("\n" + "="*80)
110print("Template generation complete!")
111print(f"The template is available at: {dir_tmp}")
112print("\nTo create a new project from this template, run:")
113print(f" cookiecutter {dir_tmp}")
114print("="*80 + "\n")
Console Logs
---------- parameters ----------
- 'requests' -> '{{ cookiecutter.package_name }}'
- '2.32.3' -> '{{ cookiecutter.package_version }}'
- 'Kenneth Reitz' -> '{{ cookiecutter.author }}'
- 'me@kennethreitz.org' -> '{{ cookiecutter.author_email }}'
---------- make template ----------
from: .
to: {{ cookiecutter.package_name }}
from: .git-blame-ignore-revs
to: {{ cookiecutter.package_name }}/.git-blame-ignore-revs
from: LICENSE
to: {{ cookiecutter.package_name }}/LICENSE
from: .pre-commit-config.yaml
to: {{ cookiecutter.package_name }}/.pre-commit-config.yaml
from: Makefile
to: {{ cookiecutter.package_name }}/Makefile
from: HISTORY.md
to: {{ cookiecutter.package_name }}/HISTORY.md
from: ext
to: {{ cookiecutter.package_name }}/ext
from: ext/requests-logo.png
to: {{ cookiecutter.package_name }}/ext/{{ cookiecutter.package_name }}-logo.png
from: ext/requests-logo.ai
to: {{ cookiecutter.package_name }}/ext/{{ cookiecutter.package_name }}-logo.ai
from: ext/psf.png
to: {{ cookiecutter.package_name }}/ext/psf.png
from: ext/kr-compressed.png
to: {{ cookiecutter.package_name }}/ext/kr-compressed.png
from: ext/LICENSE
to: {{ cookiecutter.package_name }}/ext/LICENSE
from: ext/kr.png
to: {{ cookiecutter.package_name }}/ext/kr.png
from: ext/requests-logo.svg
to: {{ cookiecutter.package_name }}/ext/{{ cookiecutter.package_name }}-logo.svg
from: ext/flower-of-life.jpg
to: {{ cookiecutter.package_name }}/ext/flower-of-life.jpg
from: ext/ss.png
to: {{ cookiecutter.package_name }}/ext/ss.png
from: ext/ss-compressed.png
to: {{ cookiecutter.package_name }}/ext/ss-compressed.png
from: ext/psf-compressed.png
to: {{ cookiecutter.package_name }}/ext/psf-compressed.png
from: ext/requests-logo-compressed.png
to: {{ cookiecutter.package_name }}/ext/{{ cookiecutter.package_name }}-logo-compressed.png
from: pyproject.toml
to: {{ cookiecutter.package_name }}/pyproject.toml
from: tests
to: {{ cookiecutter.package_name }}/tests
from: tests/test_utils.py
to: {{ cookiecutter.package_name }}/tests/test_utils.py
from: tests/conftest.py
to: {{ cookiecutter.package_name }}/tests/conftest.py
from: tests/test_structures.py
to: {{ cookiecutter.package_name }}/tests/test_structures.py
from: tests/test_packages.py
to: {{ cookiecutter.package_name }}/tests/test_packages.py
from: tests/testserver
to: {{ cookiecutter.package_name }}/tests/testserver
from: tests/testserver/server.py
to: {{ cookiecutter.package_name }}/tests/testserver/server.py
from: tests/testserver/__init__.py
to: {{ cookiecutter.package_name }}/tests/testserver/__init__.py
from: tests/test_testserver.py
to: {{ cookiecutter.package_name }}/tests/test_testserver.py
from: tests/compat.py
to: {{ cookiecutter.package_name }}/tests/compat.py
from: tests/__init__.py
to: {{ cookiecutter.package_name }}/tests/__init__.py
from: tests/test_hooks.py
to: {{ cookiecutter.package_name }}/tests/test_hooks.py
from: tests/certs
to: {{ cookiecutter.package_name }}/tests/certs
from: tests/certs/valid
to: {{ cookiecutter.package_name }}/tests/certs/valid
from: tests/certs/valid/ca
to: {{ cookiecutter.package_name }}/tests/certs/valid/ca
from: tests/certs/valid/ca/ca.cnf
to: {{ cookiecutter.package_name }}/tests/certs/valid/ca/ca.cnf
from: tests/certs/valid/ca/ca-private.key
to: {{ cookiecutter.package_name }}/tests/certs/valid/ca/ca-private.key
from: tests/certs/valid/ca/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/valid/ca/Makefile
from: tests/certs/valid/ca/ca.crt
to: {{ cookiecutter.package_name }}/tests/certs/valid/ca/ca.crt
from: tests/certs/valid/ca/ca.srl
to: {{ cookiecutter.package_name }}/tests/certs/valid/ca/ca.srl
from: tests/certs/valid/server
to: {{ cookiecutter.package_name }}/tests/certs/valid/server
from: tests/certs/valid/server/server.key
to: {{ cookiecutter.package_name }}/tests/certs/valid/server/server.key
from: tests/certs/valid/server/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/valid/server/Makefile
from: tests/certs/valid/server/server.pem
to: {{ cookiecutter.package_name }}/tests/certs/valid/server/server.pem
from: tests/certs/valid/server/server.csr
to: {{ cookiecutter.package_name }}/tests/certs/valid/server/server.csr
from: tests/certs/valid/server/cert.cnf
to: {{ cookiecutter.package_name }}/tests/certs/valid/server/cert.cnf
from: tests/certs/mtls
to: {{ cookiecutter.package_name }}/tests/certs/mtls
from: tests/certs/mtls/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/mtls/Makefile
from: tests/certs/mtls/README.md
to: {{ cookiecutter.package_name }}/tests/certs/mtls/README.md
from: tests/certs/mtls/client
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client
from: tests/certs/mtls/client/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/Makefile
from: tests/certs/mtls/client/ca
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/ca
from: tests/certs/mtls/client/ca/ca.cnf
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/ca/ca.cnf
from: tests/certs/mtls/client/ca/ca-private.key
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/ca/ca-private.key
from: tests/certs/mtls/client/ca/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/ca/Makefile
from: tests/certs/mtls/client/ca/ca.crt
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/ca/ca.crt
from: tests/certs/mtls/client/ca/ca.srl
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/ca/ca.srl
from: tests/certs/mtls/client/client.pem
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/client.pem
from: tests/certs/mtls/client/client.csr
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/client.csr
from: tests/certs/mtls/client/cert.cnf
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/cert.cnf
from: tests/certs/mtls/client/client.key
to: {{ cookiecutter.package_name }}/tests/certs/mtls/client/client.key
from: tests/certs/README.md
to: {{ cookiecutter.package_name }}/tests/certs/README.md
from: tests/certs/expired
to: {{ cookiecutter.package_name }}/tests/certs/expired
from: tests/certs/expired/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/expired/Makefile
from: tests/certs/expired/ca
to: {{ cookiecutter.package_name }}/tests/certs/expired/ca
from: tests/certs/expired/ca/ca.cnf
to: {{ cookiecutter.package_name }}/tests/certs/expired/ca/ca.cnf
from: tests/certs/expired/ca/ca-private.key
to: {{ cookiecutter.package_name }}/tests/certs/expired/ca/ca-private.key
from: tests/certs/expired/ca/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/expired/ca/Makefile
from: tests/certs/expired/ca/ca.crt
to: {{ cookiecutter.package_name }}/tests/certs/expired/ca/ca.crt
from: tests/certs/expired/ca/ca.srl
to: {{ cookiecutter.package_name }}/tests/certs/expired/ca/ca.srl
from: tests/certs/expired/server
to: {{ cookiecutter.package_name }}/tests/certs/expired/server
from: tests/certs/expired/server/server.key
to: {{ cookiecutter.package_name }}/tests/certs/expired/server/server.key
from: tests/certs/expired/server/Makefile
to: {{ cookiecutter.package_name }}/tests/certs/expired/server/Makefile
from: tests/certs/expired/server/server.pem
to: {{ cookiecutter.package_name }}/tests/certs/expired/server/server.pem
from: tests/certs/expired/server/server.csr
to: {{ cookiecutter.package_name }}/tests/certs/expired/server/server.csr
from: tests/certs/expired/server/cert.cnf
to: {{ cookiecutter.package_name }}/tests/certs/expired/server/cert.cnf
from: tests/certs/expired/README.md
to: {{ cookiecutter.package_name }}/tests/certs/expired/README.md
from: tests/test_requests.py
to: {{ cookiecutter.package_name }}/tests/test_{{ cookiecutter.package_name }}.py
from: tests/utils.py
to: {{ cookiecutter.package_name }}/tests/utils.py
from: tests/test_adapters.py
to: {{ cookiecutter.package_name }}/tests/test_adapters.py
from: tests/test_help.py
to: {{ cookiecutter.package_name }}/tests/test_help.py
from: tests/test_lowlevel.py
to: {{ cookiecutter.package_name }}/tests/test_lowlevel.py
from: MANIFEST.in
to: {{ cookiecutter.package_name }}/MANIFEST.in
from: .coveragerc
to: {{ cookiecutter.package_name }}/.coveragerc
from: docs
to: {{ cookiecutter.package_name }}/docs
from: docs/index.rst
to: {{ cookiecutter.package_name }}/docs/index.rst
from: docs/_themes
to: {{ cookiecutter.package_name }}/docs/_themes
from: docs/_themes/LICENSE
to: {{ cookiecutter.package_name }}/docs/_themes/LICENSE
from: docs/_themes/flask_theme_support.py
to: {{ cookiecutter.package_name }}/docs/_themes/flask_theme_support.py
from: docs/_themes/.gitignore
to: {{ cookiecutter.package_name }}/docs/_themes/.gitignore
from: docs/requirements.txt
to: {{ cookiecutter.package_name }}/docs/requirements.txt
from: docs/_templates
to: {{ cookiecutter.package_name }}/docs/_templates
from: docs/_templates/sidebarintro.html
to: {{ cookiecutter.package_name }}/docs/_templates/sidebarintro.html
from: docs/_templates/sidebarlogo.html
to: {{ cookiecutter.package_name }}/docs/_templates/sidebarlogo.html
from: docs/_templates/hacks.html
to: {{ cookiecutter.package_name }}/docs/_templates/hacks.html
from: docs/Makefile
to: {{ cookiecutter.package_name }}/docs/Makefile
from: docs/conf.py
to: {{ cookiecutter.package_name }}/docs/conf.py
from: docs/_static
to: {{ cookiecutter.package_name }}/docs/_static
from: docs/_static/custom.css
to: {{ cookiecutter.package_name }}/docs/_static/custom.css
from: docs/_static/requests-sidebar.png
to: {{ cookiecutter.package_name }}/docs/_static/{{ cookiecutter.package_name }}-sidebar.png
from: docs/user
to: {{ cookiecutter.package_name }}/docs/user
from: docs/user/install.rst
to: {{ cookiecutter.package_name }}/docs/user/install.rst
from: docs/user/authentication.rst
to: {{ cookiecutter.package_name }}/docs/user/authentication.rst
from: docs/user/quickstart.rst
to: {{ cookiecutter.package_name }}/docs/user/quickstart.rst
from: docs/user/advanced.rst
to: {{ cookiecutter.package_name }}/docs/user/advanced.rst
from: docs/.nojekyll
to: {{ cookiecutter.package_name }}/docs/.nojekyll
from: docs/make.bat
to: {{ cookiecutter.package_name }}/docs/make.bat
from: docs/dev
to: {{ cookiecutter.package_name }}/docs/dev
from: docs/dev/contributing.rst
to: {{ cookiecutter.package_name }}/docs/dev/contributing.rst
from: docs/dev/authors.rst
to: {{ cookiecutter.package_name }}/docs/dev/authors.rst
from: docs/community
to: {{ cookiecutter.package_name }}/docs/community
from: docs/community/support.rst
to: {{ cookiecutter.package_name }}/docs/community/support.rst
from: docs/community/release-process.rst
to: {{ cookiecutter.package_name }}/docs/community/release-process.rst
from: docs/community/out-there.rst
to: {{ cookiecutter.package_name }}/docs/community/out-there.rst
from: docs/community/vulnerabilities.rst
to: {{ cookiecutter.package_name }}/docs/community/vulnerabilities.rst
from: docs/community/recommended.rst
to: {{ cookiecutter.package_name }}/docs/community/recommended.rst
from: docs/community/faq.rst
to: {{ cookiecutter.package_name }}/docs/community/faq.rst
from: docs/community/updates.rst
to: {{ cookiecutter.package_name }}/docs/community/updates.rst
from: docs/api.rst
to: {{ cookiecutter.package_name }}/docs/api.rst
from: NOTICE
to: {{ cookiecutter.package_name }}/NOTICE
from: README.md
to: {{ cookiecutter.package_name }}/README.md
from: setup.py
to: {{ cookiecutter.package_name }}/setup.py
from: requirements-dev.txt
to: {{ cookiecutter.package_name }}/requirements-dev.txt
from: .gitignore
to: {{ cookiecutter.package_name }}/.gitignore
from: .github
to: {{ cookiecutter.package_name }}/.github
from: .github/FUNDING.yml
to: {{ cookiecutter.package_name }}/.github/FUNDING.yml
from: .github/CODE_OF_CONDUCT.md
to: {{ cookiecutter.package_name }}/.github/CODE_OF_CONDUCT.md
from: .github/workflows
to: {{ cookiecutter.package_name }}/.github/workflows
from: .github/workflows/codeql-analysis.yml
to: {{ cookiecutter.package_name }}/.github/workflows/codeql-analysis.yml
from: .github/workflows/lint.yml
to: {{ cookiecutter.package_name }}/.github/workflows/lint.yml
from: .github/workflows/run-tests.yml
to: {{ cookiecutter.package_name }}/.github/workflows/run-tests.yml
from: .github/workflows/lock-issues.yml
to: {{ cookiecutter.package_name }}/.github/workflows/lock-issues.yml
from: .github/workflows/close-issues.yml
to: {{ cookiecutter.package_name }}/.github/workflows/close-issues.yml
from: .github/ISSUE_TEMPLATE.md
to: {{ cookiecutter.package_name }}/.github/ISSUE_TEMPLATE.md
from: .github/CONTRIBUTING.md
to: {{ cookiecutter.package_name }}/.github/CONTRIBUTING.md
from: .github/ISSUE_TEMPLATE
to: {{ cookiecutter.package_name }}/.github/ISSUE_TEMPLATE
from: .github/ISSUE_TEMPLATE/Feature_request.md
to: {{ cookiecutter.package_name }}/.github/ISSUE_TEMPLATE/Feature_request.md
from: .github/ISSUE_TEMPLATE/Bug_report.md
to: {{ cookiecutter.package_name }}/.github/ISSUE_TEMPLATE/Bug_report.md
from: .github/ISSUE_TEMPLATE/Custom.md
to: {{ cookiecutter.package_name }}/.github/ISSUE_TEMPLATE/Custom.md
from: .github/dependabot.yml
to: {{ cookiecutter.package_name }}/.github/dependabot.yml
from: .github/SECURITY.md
to: {{ cookiecutter.package_name }}/.github/SECURITY.md
from: tox.ini
to: {{ cookiecutter.package_name }}/tox.ini
from: AUTHORS.rst
to: {{ cookiecutter.package_name }}/AUTHORS.rst
from: setup.cfg
to: {{ cookiecutter.package_name }}/setup.cfg
from: .readthedocs.yaml
to: {{ cookiecutter.package_name }}/.readthedocs.yaml
from: src
to: {{ cookiecutter.package_name }}/src
from: src/requests
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}
from: src/requests/cookies.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/cookies.py
from: src/requests/auth.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/auth.py
from: src/requests/sessions.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/sessions.py
from: src/requests/hooks.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/hooks.py
from: src/requests/compat.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/compat.py
from: src/requests/models.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/models.py
from: src/requests/certs.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/certs.py
from: src/requests/__init__.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/__init__.py
from: src/requests/status_codes.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/status_codes.py
from: src/requests/packages.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/packages.py
from: src/requests/__version__.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/__version__.py
from: src/requests/api.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/api.py
from: src/requests/_internal_utils.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/_internal_utils.py
from: src/requests/utils.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/utils.py
from: src/requests/exceptions.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/exceptions.py
from: src/requests/structures.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/structures.py
from: src/requests/help.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/help.py
from: src/requests/adapters.py
to: {{ cookiecutter.package_name }}/src/{{ cookiecutter.package_name }}/adapters.py
Step 3. Use the generated template with cookiecutter:
Once the template is generated, you can create new projects with:
cookiecutter path/to/generated/template
More Examples¶
Enterprise Applications¶
In enterprise environments, this tool is particularly valuable for:
Internal frameworks and libraries with consistent structure
Microservice templates that follow company standards
Domain-specific applications with similar patterns
Closed-source or private repositories that need standardization
Projects in any programming language (not limited to Python)
You can develop a well-designed “seed” project according to your organization’s best practices, then:
Use cookiecutter_maker to generate a template from your seed project
Share the template within your organization
Use cookiecutter to consistently generate new projects based on this template
Maintain standards and reduce setup time for new initiatives
Each generated project will have the same structure and patterns, but with customized parameters (names, versions, etc.) based on your specifications.