A dynamic, interactive CLI-based project generator with a tree-based question system and custom template executors.
Project description
Project Scaffolder
A dynamic, interactive CLI-based project generator that simplifies the process of scaffolding new projects through a tree-based question system and custom template executors.
Features
- Interactive Question Tree: Navigate through a logical hierarchy of choices defined in JSON.
- Extensible Architecture: Easily add new templates and questions by adding JSON files and Python executors.
- Styled CLI Output: Uses
richto provide a clean and professional command-line interface with panels, colors, and spinners. - Robust Input Handling: Powered by
inquirerfor intuitive selections and confirmations. - Environment-Aware Output: Projects and virtual environments are created in
temp/during development, keeping generated files out of version control. - Base Executor Pattern: All executors inherit from
BaseExecutor, which provides a consistent lifecycle and a built-in loading spinner that automatically pauses around interactive prompts.
Installation
Prerequisites
- Python 3.8+
Setup
-
Clone the repository:
git clone <repository-url> cd template
-
Install the required dependencies:
pip install -r requirements.txt
-
Configure your environment by creating a
.envfile in the project root:ENVIRONMENT=development
Accepted values:
development,production.
Usage
To start the project generation process, run the main scaffolder script:
python scripts/scaffolder/scaffolder.py
Follow the on-screen prompts to select your project type, language, and other configurations.
Project Structure
template/
├── .env # Environment configuration (ENVIRONMENT=development|production)
├── questions/ # JSON files defining the question hierarchy
├── executors/ # Executor classes for each supported framework
│ ├── base.py # BaseExecutor abstract class (lifecycle + spinner)
│ └── backend/
│ └── python/
│ └── django/ # Django-specific executors
├── processors/ # Core logic: question loading, input handling, template resolution
├── utils/
│ ├── base.py # Subprocess, file, and venv utilities
│ └── env.py # Environment detection and path resolution
├── constants/ # Framework-specific code snippets and configuration strings
├── typings/ # Shared type definitions and dataclasses
└── scripts/ # Entry points for running the scaffolder
How It Works
- Question Loading: The system starts by loading
questions/base.json. - Dynamic Traversal: Based on user selection, it recursively loads child questions from the file system.
- Template Resolution: Once a leaf node (a final choice) is reached, the system identifies the corresponding executor in the
executors/directory. - Execution: The executor's
run()method is called with the gathered parameters. It starts a loading spinner, delegates togenerate(), and stops the spinner when done.
Environment Modes
The ENVIRONMENT variable in .env controls where generated output is placed.
ENVIRONMENT |
Project output | Virtual environment |
|---|---|---|
development |
<project_root>/temp/ |
<project_root>/temp/venv/ |
production |
Current working directory | <project_root>/venv/ |
The temp/ directory is listed in .gitignore so development output is never committed.
Executor Architecture
All executors inherit from BaseExecutor (executors/base.py) and must implement:
| Method | Purpose |
|---|---|
get_venv_environment() |
Set up and return the venv Python path |
install_dependencies(venv_python_executor) |
Install framework packages |
execute_creation_commands(**kwargs) |
Orchestrate the full scaffold |
generate(**kwargs) |
Resolve arguments and drive the above steps |
prepare_directory() is provided as a concrete default on BaseExecutor — it creates the output directory or prompts the user to replace it if one already exists. Override it only if the executor needs different behaviour.
The public entry point is run(**kwargs), which wraps generate() with a rich loading spinner. Use self._stop_status() / self._start_status() around any interactive inquirer prompts inside your executor to prevent the spinner from blocking user input. Use self._update_status(message) to update the spinner label as execution progresses through steps.
Adding a New Executor
- Create a JSON file in
questions/defining the configuration options for the new template. - Link it to the existing question tree via
questions/base.json. - Create a Python file in the corresponding
executors/path and subclassBaseExecutor:
from src.executors.base import BaseExecutor
from typings.base import ExecutorResponseStatus
class MyFrameworkExecutor(BaseExecutor):
def get_venv_environment(self) -> str:
...
def install_dependencies(self, venv_python_executor: str) -> ExecutorResponseStatus:
...
def execute_creation_commands(self, **kwargs) -> ExecutorResponseStatus:
...
def generate(self, **kwargs):
...
if __name__ == '__main__':
args = MyFrameworkExecutor.build_arg_parser().parse_args()
MyFrameworkExecutor().run(**vars(args))
Contributing
Branching
main— stable branch; only merge via pull request- Feature branches should follow the pattern:
feature/<short-description>(e.g.feature/fastapi-executor) - Bug fix branches:
fix/<short-description>(e.g.fix/venv-path-dev-mode)
Workflow
-
Fork or branch from
main:git checkout -b feature/<short-description>
-
Set up your environment:
pip install -r requirements.txt cp .env.example .env # set ENVIRONMENT=development
-
Make your changes following the conventions below, then commit:
git add <files> git commit -m "feat: short description of change"
-
Push and open a pull request against
main.
Adding a Question
Questions live in questions/ as JSON files and mirror the executors/ directory structure. Each file defines a node in the question tree:
{
"type": "list",
"name": "my_option",
"message": "Choose an option",
"choices": ["Option A", "Option B"],
"children": []
}
Leaf nodes (no children) trigger executor resolution — the scaffolder maps the answer path directly to a file in executors/.
Adding an Executor
Follow the steps in Adding a New Executor above. Additional conventions:
- Place the file at
executors/<category>/<language>/<framework>/<name>.pyto match the question path. - Use
self.consolefor all terminal output — never useprint(). - Use
self._update_status(message)to label each distinct step inexecute_creation_commands. - Call
self._stop_status()before anyinquirer.prompt()andself._start_status()immediately after. - All subprocess calls must use the venv Python executor (
get_venv_python_executor()) rather than bare shell commands, so they work correctly in bothdevelopmentandproductionenvironments.
Code Style
- Follow PEP 8.
- All public methods must have docstrings with
:param:and:return:annotations. - Keep
utils/functions generic and stateless — executor-specific logic belongs in the executor class.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dev_scaffolder-0.0.6.tar.gz.
File metadata
- Download URL: dev_scaffolder-0.0.6.tar.gz
- Upload date:
- Size: 142.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d15b190ee1fcdd48ad43f9dd8d4966f96b865726ba687e9b4f2aafa039f44284
|
|
| MD5 |
631b01958cbe3252e5e6ec1c8345924d
|
|
| BLAKE2b-256 |
46b83b494ad118b63c588ac2aad31736cf14b6169436df1d4f4661527f2a4f47
|
Provenance
The following attestation bundles were made for dev_scaffolder-0.0.6.tar.gz:
Publisher:
publish-to-pypi.yml on Faisal-Sey/dev-scaffolder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dev_scaffolder-0.0.6.tar.gz -
Subject digest:
d15b190ee1fcdd48ad43f9dd8d4966f96b865726ba687e9b4f2aafa039f44284 - Sigstore transparency entry: 1348784879
- Sigstore integration time:
-
Permalink:
Faisal-Sey/dev-scaffolder@9ddaa50473b40e655a32dee02cb74c006740e3c8 -
Branch / Tag:
refs/tags/v0.0.6 - Owner: https://github.com/Faisal-Sey
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@9ddaa50473b40e655a32dee02cb74c006740e3c8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dev_scaffolder-0.0.6-py3-none-any.whl.
File metadata
- Download URL: dev_scaffolder-0.0.6-py3-none-any.whl
- Upload date:
- Size: 426.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
715686f43acda30bcd8b2e762e18d79fadec94560e3257abfb39baf6d0b1c383
|
|
| MD5 |
e39a9b9f3a4ff8ab546f953867462da1
|
|
| BLAKE2b-256 |
8c6835f25f07705543947f69504a774b1cf9c4a788c896b6e18023ed0f10b2e5
|
Provenance
The following attestation bundles were made for dev_scaffolder-0.0.6-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on Faisal-Sey/dev-scaffolder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dev_scaffolder-0.0.6-py3-none-any.whl -
Subject digest:
715686f43acda30bcd8b2e762e18d79fadec94560e3257abfb39baf6d0b1c383 - Sigstore transparency entry: 1348784942
- Sigstore integration time:
-
Permalink:
Faisal-Sey/dev-scaffolder@9ddaa50473b40e655a32dee02cb74c006740e3c8 -
Branch / Tag:
refs/tags/v0.0.6 - Owner: https://github.com/Faisal-Sey
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@9ddaa50473b40e655a32dee02cb74c006740e3c8 -
Trigger Event:
release
-
Statement type: