Scaffolding engine for Create Awesome Python App
Project description
create-python-app-core
Programmatic scaffolding engine behind Create Awesome Python App. Import the scaffolding pipeline -- composable, headless, and CI-ready.
Requires Python >= 3.12.
This is the engine package. For the interactive CLI, use
create-awesome-python-appinstead.
Installation
pip install create-python-app-core
Or with uv:
uv add create-python-app-core
Usage
Scaffold a project programmatically
import asyncio
from create_python_app_core import create_python_app
async def main() -> None:
await create_python_app(
"my-app",
{
"projectName": "my-app",
"template": "file:///path/to/template",
"install": True,
},
transform_options=lambda opts: asyncio.sleep(0, result=opts),
)
asyncio.run(main())
Scaffold with the installer API
from create_python_app_core import scaffold_project
scaffold_project(
"my-app",
template="file:///path/to/template",
addons=[],
extend=[],
install=True,
force=False,
offline=False,
)
Resolve a template source
from create_python_app_core import resolve_source, get_template_dir_path
source = resolve_source(
"https://github.com/Create-Python-App/cpa-templates?ref=main&subdir=fastapi"
)
print(source.kind) # github
print(source.ref) # main
print(source.subdir) # fastapi
Download a repository into the cache
from create_python_app_core import resolve_source, download_repository
source = resolve_source("https://github.com/org/my-template")
root = download_repository(source, refresh="stale", offline=False)
template_dir = get_template_dir_path(source, root)
Load template configuration
from pathlib import Path
from create_python_app_core import load_cpa_config
cfg = load_cpa_config(Path("/path/to/template/cpa.config.json"))
for opt in cfg.custom_options:
print(opt.key, opt.default)
Check environment info
from create_python_app_core import print_env_info
print_env_info()
# Prints Python, platform, uv, and git info. Then exits.
Validate the Python version
from create_python_app_core import check_python_version
check_python_version(">=3.12", "my-tool")
# Exits with code 1 if the interpreter does not match.
API Reference
All public exports from create_python_app_core:
Functions
| Signature | Description |
|---|---|
create_python_app(project_directory, options, transform_options=None) |
Async orchestrator. Applies transform_options, then delegates to scaffold_project. |
scaffold_project(project_directory, *, template, addons=None, extend=None, force=False, install=True, offline=False, refresh=None, keep_on_failure=False, cache_dir=None, options=None) |
Main scaffolding pipeline. Resolves sources, downloads layers, merges files, runs uv sync, and initializes git. |
resolve_source(spec, *, cache_dir=None) |
Parses a template/extension specifier (GitHub URL, file://, slug) into a ResolvedSource. |
get_template_dir_path(source, root) |
Returns the template/ subdirectory when present, otherwise the resolved root. |
default_cache_dir() |
Returns CPA_CACHE_DIR or ~/.cache/cpa. |
download_repository(source, *, offline=False, refresh=None, cache_root=None) |
Clones or refreshes a Git repo into the cache. Returns the entry directory. |
read_cache_meta(entry) |
Reads .cpa-cache.json metadata from a cache entry. |
write_cache_meta(entry, meta) |
Writes .cpa-cache.json metadata for a cache entry. |
load_cpa_config(path) |
Loads optional cpa.config.json (custom CLI prompts). Returns empty CpaConfig when missing. |
assert_directory_is_empty(path, *, force=False) |
Raises NonEmptyTargetDirectoryError when the target exists and is non-empty. |
load_layer(source, root, dest, *, overwrite=True, context=None) |
Copies one template/extension layer into dest. |
merge_layers(layers, dest, *, context=None) |
Applies layers in order (template, addons, extend). Later layers win. |
merge_pyproject_text(base_text, overlay_text) |
Deep-merges two pyproject.toml documents as TOML. |
check_python_version(required, package_name) |
Compares sys.version_info against a PEP 440 specifier. Exits with code 1 if too old. |
check_for_latest_version(package_name) |
Async. Fetches the latest version from PyPI. Returns None on failure. |
print_env_info() |
Prints OS, Python, uv, and git info to stdout, then exits. |
Constants
| Name | Description |
|---|---|
__version__ |
Installed package version string. |
CPA_USER_AGENT |
HTTP User-Agent sent to PyPI (create-python-app-core/<version>). |
NON_EMPTY_DIR_ERROR_CODE |
Stable code for NonEmptyTargetDirectoryError (CPA_NON_EMPTY_TARGET_DIR). |
Types
| Type | Shape |
|---|---|
ResolvedSource |
kind (github | file | slug | git), url, ref, subdir, local_path |
CacheMeta |
url, ref, fetched_at, commit |
CpaConfig |
name, custom_options, raw |
CpaCustomOption |
key, type, message, default |
CpaError |
Base exception with .code attribute |
ConfigParseError |
Invalid cpa.config.json (code: CPA_CONFIG_PARSE) |
ManifestLoadError |
Missing template directory (code: CPA_MANIFEST_LOAD) |
PackageManagerFallbackError |
Package manager fallback failure (code: CPA_PM_FALLBACK) |
ScaffoldAbortedError |
Scaffold failed mid-run (code: CPA_ABORTED) |
NonEmptyTargetDirectoryError |
Target directory not empty (code: CPA_NON_EMPTY_TARGET_DIR) |
create_python_app options dict
| Key | Type | Default | Description |
|---|---|---|---|
template |
str |
"" |
Primary template specifier (URL, file://, or slug). |
addons |
list[str] |
[] |
Additional template layers applied after the base template. |
extend |
list[str] |
[] |
Extension layers applied last (later wins on conflicts). |
force |
bool |
False |
Allow scaffolding into a non-empty directory. |
install |
bool |
True |
Run uv sync when pyproject.toml is present. |
offline |
bool |
False |
Use cached repos only; raise on cache miss. |
refresh |
str |
env / "stale" |
Cache refresh mode: always, stale, or manual. |
keep_on_failure |
bool |
False |
Keep the partial project directory when scaffolding fails. |
cache_dir |
str | Path |
None |
Override the default cache root. |
set |
dict |
{} |
Jinja context overrides (merged into projectName and custom option defaults). |
Environment Variables
All CPA_* variables read by the core engine:
| Variable | Default | Description |
|---|---|---|
CPA_CACHE_DIR |
~/.cache/cpa |
Root directory for cloned repository cache entries. |
CPA_REFRESH |
stale |
Default cache refresh mode: always, stale, or manual. |
CPA_REFRESH_AFTER_HOURS |
24 |
Hours before a stale cache entry is refreshed. |
CPA_SKIP_GIT |
unset | Set to 1 to skip git init and block all git subprocess calls. |
CPA_STRICT_REPRO |
unset | Set to 1 to require a full 40-character commit SHA in ?ref= query params. |
Error Codes
Stable machine-readable codes on CpaError.code:
| Code | Exception class | When raised |
|---|---|---|
CPA_ERROR |
CpaError |
Generic base error (default). |
CPA_CONFIG_PARSE |
ConfigParseError |
Malformed or invalid cpa.config.json. |
CPA_MANIFEST_LOAD |
ManifestLoadError |
Template directory not found on disk. |
CPA_PM_FALLBACK |
PackageManagerFallbackError |
Package manager fallback failure. |
CPA_ABORTED |
ScaffoldAbortedError |
Scaffold failed (template render, unexpected error, etc.). |
CPA_NON_EMPTY_TARGET_DIR |
NonEmptyTargetDirectoryError |
Target directory exists and is not empty. |
CPA_GIT |
CpaError |
Git subprocess failed or git not found. |
CPA_SKIP_GIT |
CpaError |
Git operation attempted while CPA_SKIP_GIT=1. |
CPA_FILE |
CpaError |
file:// source path does not exist. |
CPA_OFFLINE |
CpaError |
Offline mode with no cached copy of the repository. |
CPA_STRICT_REPRO |
CpaError |
?ref= is not a full SHA while CPA_STRICT_REPRO=1. |
How It Works
create_python_app()
|-- transform_options() (optional)
|-- scaffold_project()
|-- assert_directory_is_empty()
|-- resolve_source() for each template / addon / extend
|-- download_repository() (git clone or file://)
|-- load_cpa_config() from cpa.config.json
|-- build_scaffold_context() (projectName + custom options + --set)
|-- merge_layers() (Jinja .template, .append, pyproject merge)
|-- uv sync (when install=True and pyproject.toml exists)
|-- git init (unless CPA_SKIP_GIT=1)
+-- cleanup partial directory on failure (unless keep_on_failure)
Architecture
The package is organized into these modules:
| Module | Responsibility |
|---|---|
__init__.py |
Barrel export and public API surface |
api.py |
create_python_app, version checks, env info, PyPI lookup |
installer.py |
scaffold_project orchestration, uv sync, git init |
loaders.py |
File discovery, .template / .append processing, layer merge |
pyproject_merge.py |
Deep-merge pyproject.toml across template layers |
paths.py |
URL resolution (GitHub, file://, slugs, ?ref=, ?subdir=) |
git_cache.py |
Clone/pull with cache, refresh modes, offline support |
config.py |
Reads optional cpa.config.json for custom CLI prompts |
errors.py |
Typed CpaError hierarchy with stable codes |
Related
create-awesome-python-app-- Interactive CLI built on this core- Create Python App -- Monorepo
- Templates catalog
License
MIT (c) Create Python App Contributors
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 create_python_app_core-0.2.2.tar.gz.
File metadata
- Download URL: create_python_app_core-0.2.2.tar.gz
- Upload date:
- Size: 16.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
43049bb2327418b4e64f10aa8d4e2ec40d48ad3fc0e1c7e9a9ece8be751e3924
|
|
| MD5 |
5f4c0b2ada3b856606ae3757e614080b
|
|
| BLAKE2b-256 |
0bca473bf1ee5d0f69074cbc89faf0f9f330ba5e406733d39ea1fb54c5e053cc
|
Provenance
The following attestation bundles were made for create_python_app_core-0.2.2.tar.gz:
Publisher:
publish.yml on Create-Python-App/create-python-app
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
create_python_app_core-0.2.2.tar.gz -
Subject digest:
43049bb2327418b4e64f10aa8d4e2ec40d48ad3fc0e1c7e9a9ece8be751e3924 - Sigstore transparency entry: 2191324903
- Sigstore integration time:
-
Permalink:
Create-Python-App/create-python-app@127ada68420c1a4340a35257a7bf7c32ef656ab1 -
Branch / Tag:
refs/tags/create-awesome-python-app@0.2.2 - Owner: https://github.com/Create-Python-App
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@127ada68420c1a4340a35257a7bf7c32ef656ab1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file create_python_app_core-0.2.2-py3-none-any.whl.
File metadata
- Download URL: create_python_app_core-0.2.2-py3-none-any.whl
- Upload date:
- Size: 17.2 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 |
1ea6202375efe7a3dfc73324896e9f90b67bebee36fb893680ca4389897ce19a
|
|
| MD5 |
0290989d2adb25571ceb9980126836f0
|
|
| BLAKE2b-256 |
f15369a3d9037342878e338c4b6a1b4fa7a31de4c27ba3c8e3baf95c1d36e0d1
|
Provenance
The following attestation bundles were made for create_python_app_core-0.2.2-py3-none-any.whl:
Publisher:
publish.yml on Create-Python-App/create-python-app
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
create_python_app_core-0.2.2-py3-none-any.whl -
Subject digest:
1ea6202375efe7a3dfc73324896e9f90b67bebee36fb893680ca4389897ce19a - Sigstore transparency entry: 2191324917
- Sigstore integration time:
-
Permalink:
Create-Python-App/create-python-app@127ada68420c1a4340a35257a7bf7c32ef656ab1 -
Branch / Tag:
refs/tags/create-awesome-python-app@0.2.2 - Owner: https://github.com/Create-Python-App
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@127ada68420c1a4340a35257a7bf7c32ef656ab1 -
Trigger Event:
push
-
Statement type: