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.
- scaffld-0.1.0/LICENSE +21 -0
- scaffld-0.1.0/MANIFEST.in +3 -0
- scaffld-0.1.0/PKG-INFO +219 -0
- scaffld-0.1.0/README.md +189 -0
- scaffld-0.1.0/pyproject.toml +66 -0
- scaffld-0.1.0/setup.cfg +4 -0
- scaffld-0.1.0/src/scaffld/__init__.py +7 -0
- scaffld-0.1.0/src/scaffld/__main__.py +8 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/.github/workflows/ci.yml +26 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/.gitignore +25 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/.pre-commit-config.yaml +14 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/LICENSE +1 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/README.md +29 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/pyproject.toml +30 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/src/{{ package_name }}/__init__.py +7 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/src/{{ package_name }}/app.py +21 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/files/tests/test_app.py +17 -0
- scaffld-0.1.0/src/scaffld/builtins/python-api/template.toml +4 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/.github/workflows/ci.yml +26 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/.gitignore +25 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/.pre-commit-config.yaml +14 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/LICENSE +1 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/README.md +30 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/pyproject.toml +29 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/src/{{ package_name }}/__init__.py +7 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/src/{{ package_name }}/cli.py +29 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/files/tests/test_cli.py +15 -0
- scaffld-0.1.0/src/scaffld/builtins/python-cli/template.toml +4 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/.github/workflows/ci.yml +26 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/.gitignore +25 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/.pre-commit-config.yaml +14 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/LICENSE +1 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/README.md +31 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/pyproject.toml +27 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/src/{{ package_name }}/__init__.py +16 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/files/tests/test_{{ package_name }}.py +9 -0
- scaffld-0.1.0/src/scaffld/builtins/python-lib/template.toml +4 -0
- scaffld-0.1.0/src/scaffld/cli.py +291 -0
- scaffld-0.1.0/src/scaffld/context.py +82 -0
- scaffld-0.1.0/src/scaffld/generator.py +107 -0
- scaffld-0.1.0/src/scaffld/licenses.py +97 -0
- scaffld-0.1.0/src/scaffld/naming.py +105 -0
- scaffld-0.1.0/src/scaffld/render.py +156 -0
- scaffld-0.1.0/src/scaffld/templates.py +119 -0
- scaffld-0.1.0/src/scaffld.egg-info/PKG-INFO +219 -0
- scaffld-0.1.0/src/scaffld.egg-info/SOURCES.txt +53 -0
- scaffld-0.1.0/src/scaffld.egg-info/dependency_links.txt +1 -0
- scaffld-0.1.0/src/scaffld.egg-info/entry_points.txt +2 -0
- scaffld-0.1.0/src/scaffld.egg-info/requires.txt +8 -0
- scaffld-0.1.0/src/scaffld.egg-info/top_level.txt +1 -0
- scaffld-0.1.0/tests/test_cli.py +267 -0
- scaffld-0.1.0/tests/test_generator.py +166 -0
- scaffld-0.1.0/tests/test_naming.py +43 -0
- scaffld-0.1.0/tests/test_render.py +85 -0
- 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.
|
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
|
+

|
|
34
|
+

|
|
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)).
|
scaffld-0.1.0/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# scaffld
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
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"
|
scaffld-0.1.0/setup.cfg
ADDED
|
@@ -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"]
|