scaffld 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. scaffld-0.1.0/LICENSE +21 -0
  2. scaffld-0.1.0/MANIFEST.in +3 -0
  3. scaffld-0.1.0/PKG-INFO +219 -0
  4. scaffld-0.1.0/README.md +189 -0
  5. scaffld-0.1.0/pyproject.toml +66 -0
  6. scaffld-0.1.0/setup.cfg +4 -0
  7. scaffld-0.1.0/src/scaffld/__init__.py +7 -0
  8. scaffld-0.1.0/src/scaffld/__main__.py +8 -0
  9. scaffld-0.1.0/src/scaffld/builtins/python-api/files/.github/workflows/ci.yml +26 -0
  10. scaffld-0.1.0/src/scaffld/builtins/python-api/files/.gitignore +25 -0
  11. scaffld-0.1.0/src/scaffld/builtins/python-api/files/.pre-commit-config.yaml +14 -0
  12. scaffld-0.1.0/src/scaffld/builtins/python-api/files/LICENSE +1 -0
  13. scaffld-0.1.0/src/scaffld/builtins/python-api/files/README.md +29 -0
  14. scaffld-0.1.0/src/scaffld/builtins/python-api/files/pyproject.toml +30 -0
  15. scaffld-0.1.0/src/scaffld/builtins/python-api/files/src/{{ package_name }}/__init__.py +7 -0
  16. scaffld-0.1.0/src/scaffld/builtins/python-api/files/src/{{ package_name }}/app.py +21 -0
  17. scaffld-0.1.0/src/scaffld/builtins/python-api/files/tests/test_app.py +17 -0
  18. scaffld-0.1.0/src/scaffld/builtins/python-api/template.toml +4 -0
  19. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/.github/workflows/ci.yml +26 -0
  20. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/.gitignore +25 -0
  21. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/.pre-commit-config.yaml +14 -0
  22. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/LICENSE +1 -0
  23. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/README.md +30 -0
  24. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/pyproject.toml +29 -0
  25. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/src/{{ package_name }}/__init__.py +7 -0
  26. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/src/{{ package_name }}/cli.py +29 -0
  27. scaffld-0.1.0/src/scaffld/builtins/python-cli/files/tests/test_cli.py +15 -0
  28. scaffld-0.1.0/src/scaffld/builtins/python-cli/template.toml +4 -0
  29. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/.github/workflows/ci.yml +26 -0
  30. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/.gitignore +25 -0
  31. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/.pre-commit-config.yaml +14 -0
  32. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/LICENSE +1 -0
  33. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/README.md +31 -0
  34. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/pyproject.toml +27 -0
  35. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/src/{{ package_name }}/__init__.py +16 -0
  36. scaffld-0.1.0/src/scaffld/builtins/python-lib/files/tests/test_{{ package_name }}.py +9 -0
  37. scaffld-0.1.0/src/scaffld/builtins/python-lib/template.toml +4 -0
  38. scaffld-0.1.0/src/scaffld/cli.py +291 -0
  39. scaffld-0.1.0/src/scaffld/context.py +82 -0
  40. scaffld-0.1.0/src/scaffld/generator.py +107 -0
  41. scaffld-0.1.0/src/scaffld/licenses.py +97 -0
  42. scaffld-0.1.0/src/scaffld/naming.py +105 -0
  43. scaffld-0.1.0/src/scaffld/render.py +156 -0
  44. scaffld-0.1.0/src/scaffld/templates.py +119 -0
  45. scaffld-0.1.0/src/scaffld.egg-info/PKG-INFO +219 -0
  46. scaffld-0.1.0/src/scaffld.egg-info/SOURCES.txt +53 -0
  47. scaffld-0.1.0/src/scaffld.egg-info/dependency_links.txt +1 -0
  48. scaffld-0.1.0/src/scaffld.egg-info/entry_points.txt +2 -0
  49. scaffld-0.1.0/src/scaffld.egg-info/requires.txt +8 -0
  50. scaffld-0.1.0/src/scaffld.egg-info/top_level.txt +1 -0
  51. scaffld-0.1.0/tests/test_cli.py +267 -0
  52. scaffld-0.1.0/tests/test_generator.py +166 -0
  53. scaffld-0.1.0/tests/test_naming.py +43 -0
  54. scaffld-0.1.0/tests/test_render.py +85 -0
  55. scaffld-0.1.0/tests/test_templates.py +71 -0
scaffld-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fernando Aporta Franco (ferinazumaDEV)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ recursive-include src/scaffld/builtins *
2
+ include LICENSE
3
+ include README.md
scaffld-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,219 @@
1
+ Metadata-Version: 2.4
2
+ Name: scaffld
3
+ Version: 0.1.0
4
+ Summary: Scaffold new Python projects in seconds with a friendly TUI.
5
+ Author: Fernando Aporta Franco
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ferinazumaDEV/scaffld
8
+ Project-URL: Source, https://github.com/ferinazumaDEV/scaffld
9
+ Project-URL: Issues, https://github.com/ferinazumaDEV/scaffld/issues
10
+ Keywords: scaffold,boilerplate,project-generator,cookiecutter,template,cli,tui
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Code Generators
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: typer<1.0,>=0.12
25
+ Requires-Dist: rich>=13.7
26
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=8.0; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # scaffld
32
+
33
+ ![Python](https://img.shields.io/badge/python-3.9%2B-blue)
34
+ ![License: MIT](https://img.shields.io/badge/License-MIT-green)
35
+
36
+ **Scaffold a new, fully-wired Python project in seconds — with a friendly terminal UI.**
37
+
38
+ `scaffld` generates a clean project skeleton (src layout, tests, typed code, CI,
39
+ pre-commit, license, and an optional virtualenv) from extensible templates. No
40
+ cookiecutter YAML to memorize, no `{% raw %}` gymnastics to keep GitHub Actions
41
+ files intact — just answer a few prompts and start writing code.
42
+
43
+ ```bash
44
+ pip install git+https://github.com/ferinazumaDEV/scaffld
45
+ scaffld new
46
+ ```
47
+
48
+ ## Features
49
+
50
+ - **Interactive TUI** built with [Rich](https://github.com/Textualize/rich) — pick a
51
+ template from a table, confirm a summary, watch the file tree appear.
52
+ - **Batteries included** — every project ships with `pyproject.toml`, a `src/` layout,
53
+ `pytest` tests that pass out of the box, a GitHub Actions matrix CI, a
54
+ `.pre-commit-config.yaml`, a real `LICENSE`, and a sensible `.gitignore`.
55
+ - **Three built-in templates** — `python-lib`, `python-cli`, and `python-api` (FastAPI).
56
+ - **GitHub-Actions-safe templating** — a tiny custom engine leaves `${{ ... }}`
57
+ expressions untouched, so your workflow files render correctly with zero escaping.
58
+ - **Extensible** — drop your own template folder in `~/.scaffld/templates` and it shows
59
+ up instantly. Templates are just a `template.toml` plus a `files/` tree.
60
+ - **Scriptable** — `--no-input` makes `scaffld` behave in CI and Makefiles.
61
+ - **Zero-config virtualenv** — optionally creates `.venv` for the new project.
62
+
63
+ ## Install
64
+
65
+ ```bash
66
+ pip install git+https://github.com/ferinazumaDEV/scaffld
67
+ # or, from a clone:
68
+ pip install -e ".[dev]"
69
+ ```
70
+
71
+ Installing from the repository needs `git` on your machine; `scaffld` is not on
72
+ PyPI yet, so `pip install scaffld` will not find it.
73
+
74
+ Requires Python 3.9+. Runtime dependencies: `typer` and `rich` (plus `tomli` on 3.9/3.10).
75
+
76
+ ## Usage
77
+
78
+ List the available templates:
79
+
80
+ ```console
81
+ $ scaffld list
82
+ Available templates
83
+ ┏━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
84
+ ┃ # ┃ Template ┃ Kind ┃ Description ┃
85
+ ┡━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
86
+ │ 1 │ python-api │ api │ FastAPI service with a health route, typed │
87
+ │ │ │ │ handlers, and CI. │
88
+ │ 2 │ python-cli │ cli │ Zero-dependency argparse CLI with a │
89
+ │ │ │ │ console-script entry point. │
90
+ │ 3 │ python-lib │ library │ Importable Python library: src/ layout, typed │
91
+ │ │ │ │ API, tests, and CI. │
92
+ └───┴────────────┴─────────┴───────────────────────────────────────────────────┘
93
+ ```
94
+
95
+ Create a project. Run `scaffld new` with no arguments for the full interactive flow,
96
+ or pass flags to skip the prompts:
97
+
98
+ ```console
99
+ $ scaffld new "Weather Bot" -t python-cli -a "Ada Lovelace" -d "A tiny weather CLI." --no-input --no-venv
100
+ weather-bot/
101
+ ├── .github/
102
+ │ └── workflows/
103
+ │ └── ci.yml
104
+ ├── .gitignore
105
+ ├── .pre-commit-config.yaml
106
+ ├── LICENSE
107
+ ├── README.md
108
+ ├── pyproject.toml
109
+ ├── src/
110
+ │ └── weather_bot/
111
+ │ ├── __init__.py
112
+ │ └── cli.py
113
+ └── tests/
114
+ └── test_cli.py
115
+ ╭──────────────────────────────────── Done ────────────────────────────────────╮
116
+ │ Created 9 files in /tmp/weather-bot │
117
+ ╰──────────────────────────────────────────────────────────────────────────────╯
118
+
119
+ Next steps:
120
+ cd weather-bot
121
+ pip install -e ".[dev]"
122
+ pytest
123
+ ```
124
+
125
+ `scaffld show python-lib` prints the file tree a template would generate, without
126
+ writing anything to disk.
127
+
128
+ The generated project is real and works immediately:
129
+
130
+ ```console
131
+ $ cd weather-bot && pip install -e ".[dev]" && pytest -q
132
+ ... [100%]
133
+ 3 passed in 0.01s
134
+
135
+ $ weather-bot Fernando
136
+ Hello, Fernando!
137
+ ```
138
+
139
+ ### Useful flags
140
+
141
+ | Flag | Meaning |
142
+ | --- | --- |
143
+ | `-t, --type` | Template to use (`scaffld list`). |
144
+ | `-a, --author` | Author name (defaults to `SCAFFLD_AUTHOR`, then `git config user.name`, then `$USER`). |
145
+ | `--email` | Author email (defaults to `SCAFFLD_EMAIL`, then `git config user.email`). |
146
+ | `-d, --description` | One-line project description. |
147
+ | `-l, --license` | `MIT`, `BSD-3-Clause`, `ISC`, or `none`. |
148
+ | `-o, --output` | Directory to create the project in (defaults to the current directory). |
149
+ | `--python` | Minimum Python version for the generated project (`3.N` or `3.N.P`). |
150
+ | `--venv` / `--no-venv` | Create a `.venv` in the new project. On by default. |
151
+ | `--no-input` | Never prompt — fail if a required value is missing (great for CI). |
152
+ | `--force` | Write into a non-empty directory. |
153
+
154
+ `scaffld -V` (or `--version`) prints the version and exits.
155
+
156
+ ## How it works
157
+
158
+ A template is just a directory:
159
+
160
+ ```
161
+ my-template/
162
+ ├── template.toml # name, kind, description
163
+ └── files/ # the tree that gets rendered
164
+ ├── pyproject.toml
165
+ ├── src/{{ package_name }}/__init__.py
166
+ └── ...
167
+ ```
168
+
169
+ Both **file contents and path segments** are rendered, so a directory literally named
170
+ `{{ package_name }}` becomes `weather_bot/` on disk.
171
+
172
+ The rendering engine is deliberately small and has one property that matters for real
173
+ projects: **unknown `{{ ... }}` expressions are left untouched.** That means a GitHub
174
+ Actions file can contain `${{ matrix.python-version }}` right next to a scaffld variable
175
+ like `{{ project_name }}`, and only the latter is substituted — no escaping required. It
176
+ also supports filters (`{{ project_name | snake }}`) and nestable conditionals
177
+ (`{% if has_license %}...{% endif %}`).
178
+
179
+ Derived variables are computed once and kept consistent: give it `"Weather Bot"` and you
180
+ get `package_name = weather_bot`, `project_slug = weather-bot`, a filled-in license, the
181
+ year, and more. Names are transliterated to ASCII first, so `"Café Búho"` yields
182
+ `cafe_buho` rather than a shredded `caf_b_ho`, and a name that collides with a Python
183
+ keyword gets a trailing underscore (`class` → `class_`) so the package stays importable.
184
+
185
+ ## Custom templates
186
+
187
+ Point `scaffld` at your own templates by dropping them in `~/.scaffld/templates/`
188
+ (or any directory listed in the `SCAFFLD_TEMPLATES` environment variable). A user
189
+ template that shares a name with a built-in one shadows it, so you can override the
190
+ defaults. Available variables include `project_name`, `package_name`, `project_slug`,
191
+ `author`, `author_email`, `description`, `license`, `python_version`, and `year`.
192
+
193
+ ## Development
194
+
195
+ ```bash
196
+ python -m venv .venv && source .venv/bin/activate
197
+ pip install -e ".[dev]"
198
+ pytest
199
+ ```
200
+
201
+ ## Part of the ferinazumaDEV ecosystem
202
+
203
+ `scaffld` is one of a family of small, focused open-source tools I build and maintain. If it saved you some project-setup time, a few of the sibling projects tackle neighbouring problems in the same practical, batteries-included spirit.
204
+
205
+ - [The GEO Handbook](https://github.com/ferinazumaDEV/generative-engine-optimization-handbook) — the open reference on getting content cited by AI answer engines (ChatGPT, Perplexity, Google AI Overviews, Gemini, Copilot).
206
+ - [politeclient](https://github.com/ferinazumaDEV/politeclient) — a polite, bulletproof HTTP client for Python: retries with backoff, per-host rate-limiting, caching, and pagination.
207
+ - [typedout](https://github.com/ferinazumaDEV/typedout) — reliable structured output from any LLM: schema-validated JSON with tolerant repair and retries.
208
+ - [webhook-replay](https://github.com/ferinazumaDEV/webhook-replay) — capture a webhook once, then replay it at your local app as many times as you need.
209
+ - Hub & writing: [zentimes.es](https://zentimes.es).
210
+
211
+ By [ferinazumaDEV](https://github.com/ferinazumaDEV).
212
+
213
+ ## License
214
+
215
+ MIT — see [LICENSE](LICENSE).
216
+
217
+ ---
218
+
219
+ Built by Fernando ([@ferinazumaDEV](https://github.com/ferinazumaDEV)).
@@ -0,0 +1,189 @@
1
+ # scaffld
2
+
3
+ ![Python](https://img.shields.io/badge/python-3.9%2B-blue)
4
+ ![License: MIT](https://img.shields.io/badge/License-MIT-green)
5
+
6
+ **Scaffold a new, fully-wired Python project in seconds — with a friendly terminal UI.**
7
+
8
+ `scaffld` generates a clean project skeleton (src layout, tests, typed code, CI,
9
+ pre-commit, license, and an optional virtualenv) from extensible templates. No
10
+ cookiecutter YAML to memorize, no `{% raw %}` gymnastics to keep GitHub Actions
11
+ files intact — just answer a few prompts and start writing code.
12
+
13
+ ```bash
14
+ pip install git+https://github.com/ferinazumaDEV/scaffld
15
+ scaffld new
16
+ ```
17
+
18
+ ## Features
19
+
20
+ - **Interactive TUI** built with [Rich](https://github.com/Textualize/rich) — pick a
21
+ template from a table, confirm a summary, watch the file tree appear.
22
+ - **Batteries included** — every project ships with `pyproject.toml`, a `src/` layout,
23
+ `pytest` tests that pass out of the box, a GitHub Actions matrix CI, a
24
+ `.pre-commit-config.yaml`, a real `LICENSE`, and a sensible `.gitignore`.
25
+ - **Three built-in templates** — `python-lib`, `python-cli`, and `python-api` (FastAPI).
26
+ - **GitHub-Actions-safe templating** — a tiny custom engine leaves `${{ ... }}`
27
+ expressions untouched, so your workflow files render correctly with zero escaping.
28
+ - **Extensible** — drop your own template folder in `~/.scaffld/templates` and it shows
29
+ up instantly. Templates are just a `template.toml` plus a `files/` tree.
30
+ - **Scriptable** — `--no-input` makes `scaffld` behave in CI and Makefiles.
31
+ - **Zero-config virtualenv** — optionally creates `.venv` for the new project.
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ pip install git+https://github.com/ferinazumaDEV/scaffld
37
+ # or, from a clone:
38
+ pip install -e ".[dev]"
39
+ ```
40
+
41
+ Installing from the repository needs `git` on your machine; `scaffld` is not on
42
+ PyPI yet, so `pip install scaffld` will not find it.
43
+
44
+ Requires Python 3.9+. Runtime dependencies: `typer` and `rich` (plus `tomli` on 3.9/3.10).
45
+
46
+ ## Usage
47
+
48
+ List the available templates:
49
+
50
+ ```console
51
+ $ scaffld list
52
+ Available templates
53
+ ┏━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
54
+ ┃ # ┃ Template ┃ Kind ┃ Description ┃
55
+ ┡━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
56
+ │ 1 │ python-api │ api │ FastAPI service with a health route, typed │
57
+ │ │ │ │ handlers, and CI. │
58
+ │ 2 │ python-cli │ cli │ Zero-dependency argparse CLI with a │
59
+ │ │ │ │ console-script entry point. │
60
+ │ 3 │ python-lib │ library │ Importable Python library: src/ layout, typed │
61
+ │ │ │ │ API, tests, and CI. │
62
+ └───┴────────────┴─────────┴───────────────────────────────────────────────────┘
63
+ ```
64
+
65
+ Create a project. Run `scaffld new` with no arguments for the full interactive flow,
66
+ or pass flags to skip the prompts:
67
+
68
+ ```console
69
+ $ scaffld new "Weather Bot" -t python-cli -a "Ada Lovelace" -d "A tiny weather CLI." --no-input --no-venv
70
+ weather-bot/
71
+ ├── .github/
72
+ │ └── workflows/
73
+ │ └── ci.yml
74
+ ├── .gitignore
75
+ ├── .pre-commit-config.yaml
76
+ ├── LICENSE
77
+ ├── README.md
78
+ ├── pyproject.toml
79
+ ├── src/
80
+ │ └── weather_bot/
81
+ │ ├── __init__.py
82
+ │ └── cli.py
83
+ └── tests/
84
+ └── test_cli.py
85
+ ╭──────────────────────────────────── Done ────────────────────────────────────╮
86
+ │ Created 9 files in /tmp/weather-bot │
87
+ ╰──────────────────────────────────────────────────────────────────────────────╯
88
+
89
+ Next steps:
90
+ cd weather-bot
91
+ pip install -e ".[dev]"
92
+ pytest
93
+ ```
94
+
95
+ `scaffld show python-lib` prints the file tree a template would generate, without
96
+ writing anything to disk.
97
+
98
+ The generated project is real and works immediately:
99
+
100
+ ```console
101
+ $ cd weather-bot && pip install -e ".[dev]" && pytest -q
102
+ ... [100%]
103
+ 3 passed in 0.01s
104
+
105
+ $ weather-bot Fernando
106
+ Hello, Fernando!
107
+ ```
108
+
109
+ ### Useful flags
110
+
111
+ | Flag | Meaning |
112
+ | --- | --- |
113
+ | `-t, --type` | Template to use (`scaffld list`). |
114
+ | `-a, --author` | Author name (defaults to `SCAFFLD_AUTHOR`, then `git config user.name`, then `$USER`). |
115
+ | `--email` | Author email (defaults to `SCAFFLD_EMAIL`, then `git config user.email`). |
116
+ | `-d, --description` | One-line project description. |
117
+ | `-l, --license` | `MIT`, `BSD-3-Clause`, `ISC`, or `none`. |
118
+ | `-o, --output` | Directory to create the project in (defaults to the current directory). |
119
+ | `--python` | Minimum Python version for the generated project (`3.N` or `3.N.P`). |
120
+ | `--venv` / `--no-venv` | Create a `.venv` in the new project. On by default. |
121
+ | `--no-input` | Never prompt — fail if a required value is missing (great for CI). |
122
+ | `--force` | Write into a non-empty directory. |
123
+
124
+ `scaffld -V` (or `--version`) prints the version and exits.
125
+
126
+ ## How it works
127
+
128
+ A template is just a directory:
129
+
130
+ ```
131
+ my-template/
132
+ ├── template.toml # name, kind, description
133
+ └── files/ # the tree that gets rendered
134
+ ├── pyproject.toml
135
+ ├── src/{{ package_name }}/__init__.py
136
+ └── ...
137
+ ```
138
+
139
+ Both **file contents and path segments** are rendered, so a directory literally named
140
+ `{{ package_name }}` becomes `weather_bot/` on disk.
141
+
142
+ The rendering engine is deliberately small and has one property that matters for real
143
+ projects: **unknown `{{ ... }}` expressions are left untouched.** That means a GitHub
144
+ Actions file can contain `${{ matrix.python-version }}` right next to a scaffld variable
145
+ like `{{ project_name }}`, and only the latter is substituted — no escaping required. It
146
+ also supports filters (`{{ project_name | snake }}`) and nestable conditionals
147
+ (`{% if has_license %}...{% endif %}`).
148
+
149
+ Derived variables are computed once and kept consistent: give it `"Weather Bot"` and you
150
+ get `package_name = weather_bot`, `project_slug = weather-bot`, a filled-in license, the
151
+ year, and more. Names are transliterated to ASCII first, so `"Café Búho"` yields
152
+ `cafe_buho` rather than a shredded `caf_b_ho`, and a name that collides with a Python
153
+ keyword gets a trailing underscore (`class` → `class_`) so the package stays importable.
154
+
155
+ ## Custom templates
156
+
157
+ Point `scaffld` at your own templates by dropping them in `~/.scaffld/templates/`
158
+ (or any directory listed in the `SCAFFLD_TEMPLATES` environment variable). A user
159
+ template that shares a name with a built-in one shadows it, so you can override the
160
+ defaults. Available variables include `project_name`, `package_name`, `project_slug`,
161
+ `author`, `author_email`, `description`, `license`, `python_version`, and `year`.
162
+
163
+ ## Development
164
+
165
+ ```bash
166
+ python -m venv .venv && source .venv/bin/activate
167
+ pip install -e ".[dev]"
168
+ pytest
169
+ ```
170
+
171
+ ## Part of the ferinazumaDEV ecosystem
172
+
173
+ `scaffld` is one of a family of small, focused open-source tools I build and maintain. If it saved you some project-setup time, a few of the sibling projects tackle neighbouring problems in the same practical, batteries-included spirit.
174
+
175
+ - [The GEO Handbook](https://github.com/ferinazumaDEV/generative-engine-optimization-handbook) — the open reference on getting content cited by AI answer engines (ChatGPT, Perplexity, Google AI Overviews, Gemini, Copilot).
176
+ - [politeclient](https://github.com/ferinazumaDEV/politeclient) — a polite, bulletproof HTTP client for Python: retries with backoff, per-host rate-limiting, caching, and pagination.
177
+ - [typedout](https://github.com/ferinazumaDEV/typedout) — reliable structured output from any LLM: schema-validated JSON with tolerant repair and retries.
178
+ - [webhook-replay](https://github.com/ferinazumaDEV/webhook-replay) — capture a webhook once, then replay it at your local app as many times as you need.
179
+ - Hub & writing: [zentimes.es](https://zentimes.es).
180
+
181
+ By [ferinazumaDEV](https://github.com/ferinazumaDEV).
182
+
183
+ ## License
184
+
185
+ MIT — see [LICENSE](LICENSE).
186
+
187
+ ---
188
+
189
+ Built by Fernando ([@ferinazumaDEV](https://github.com/ferinazumaDEV)).
@@ -0,0 +1,66 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "scaffld"
7
+ version = "0.1.0"
8
+ description = "Scaffold new Python projects in seconds with a friendly TUI."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Fernando Aporta Franco" }]
14
+ keywords = [
15
+ "scaffold",
16
+ "boilerplate",
17
+ "project-generator",
18
+ "cookiecutter",
19
+ "template",
20
+ "cli",
21
+ "tui",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 4 - Beta",
25
+ "Environment :: Console",
26
+ "Intended Audience :: Developers",
27
+ "Programming Language :: Python :: 3 :: Only",
28
+ "Programming Language :: Python :: 3.9",
29
+ "Programming Language :: Python :: 3.10",
30
+ "Programming Language :: Python :: 3.11",
31
+ "Programming Language :: Python :: 3.12",
32
+ "Topic :: Software Development :: Code Generators",
33
+ "Typing :: Typed",
34
+ ]
35
+ dependencies = [
36
+ "typer>=0.12,<1.0",
37
+ "rich>=13.7",
38
+ "tomli>=2.0 ; python_version < '3.11'",
39
+ ]
40
+
41
+ [project.optional-dependencies]
42
+ dev = ["pytest>=8.0"]
43
+
44
+ [project.scripts]
45
+ scaffld = "scaffld.cli:main"
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/ferinazumaDEV/scaffld"
49
+ Source = "https://github.com/ferinazumaDEV/scaffld"
50
+ Issues = "https://github.com/ferinazumaDEV/scaffld/issues"
51
+
52
+ [tool.setuptools]
53
+ include-package-data = true
54
+
55
+ [tool.setuptools.packages.find]
56
+ where = ["src"]
57
+
58
+ [tool.setuptools.package-data]
59
+ scaffld = ["builtins/**/*", "builtins/**/.*"]
60
+
61
+ [tool.pytest.ini_options]
62
+ testpaths = ["tests"]
63
+
64
+ [tool.ruff]
65
+ line-length = 90
66
+ target-version = "py39"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ """scaffld -- scaffold new projects in seconds with a friendly TUI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.1.0"
6
+
7
+ __all__ = ["__version__"]
@@ -0,0 +1,8 @@
1
+ """Enable ``python -m scaffld``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ main()
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.9", "3.10", "3.11", "3.12"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - name: Set up Python ${{ matrix.python-version }}
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - name: Install
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install -e ".[dev]"
25
+ - name: Test
26
+ run: pytest -q
@@ -0,0 +1,25 @@
1
+ # Byte-compiled / optimized
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+ env/
13
+
14
+ # Test & coverage
15
+ .pytest_cache/
16
+ .coverage
17
+ htmlcov/
18
+ .tox/
19
+ .mypy_cache/
20
+ .ruff_cache/
21
+
22
+ # Editors / OS
23
+ .idea/
24
+ .vscode/
25
+ .DS_Store
@@ -0,0 +1,14 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.6.9
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: https://github.com/pre-commit/pre-commit-hooks
9
+ rev: v4.6.0
10
+ hooks:
11
+ - id: end-of-file-fixer
12
+ - id: trailing-whitespace
13
+ - id: check-yaml
14
+ - id: check-toml
@@ -0,0 +1 @@
1
+ {{ license_text }}
@@ -0,0 +1,29 @@
1
+ # {{ project_name }}
2
+
3
+ {{ description }}
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ python -m venv .venv && source .venv/bin/activate
9
+ pip install -e ".[dev]"
10
+ ```
11
+
12
+ ## Run
13
+
14
+ ```bash
15
+ uvicorn {{ package_name }}.app:app --reload
16
+ # GET http://127.0.0.1:8000/health -> {"status": "ok"}
17
+ # GET http://127.0.0.1:8000/greet/you -> {"message": "Hello, you!"}
18
+ ```
19
+
20
+ ## Development
21
+
22
+ ```bash
23
+ pytest
24
+ ```
25
+ {% if has_license %}
26
+ ## License
27
+
28
+ {{ license }}. See [LICENSE](LICENSE).
29
+ {% endif %}
@@ -0,0 +1,30 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "{{ project_slug }}"
7
+ version = "0.1.0"
8
+ description = "{{ description }}"
9
+ readme = "README.md"
10
+ requires-python = ">={{ python_version }}"
11
+ {% if has_license %}license = "{{ license }}"
12
+ license-files = ["LICENSE"]
13
+ {% endif %}authors = [{ name = "{{ author }}"{% if has_email %}, email = "{{ author_email }}"{% endif %} }]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Framework :: FastAPI",
17
+ ]
18
+ dependencies = [
19
+ "fastapi>=0.110",
20
+ "uvicorn[standard]>=0.29",
21
+ ]
22
+
23
+ [project.optional-dependencies]
24
+ dev = ["pytest>=8.0", "httpx>=0.27"]
25
+
26
+ [tool.setuptools.packages.find]
27
+ where = ["src"]
28
+
29
+ [tool.pytest.ini_options]
30
+ testpaths = ["tests"]
@@ -0,0 +1,7 @@
1
+ """{{ description }}"""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.1.0"
6
+
7
+ __all__ = ["__version__"]