This page guides users through installing AfterPython, initializing a project, and understanding the generated project structure.
For detailed information:
ap init: see page 2.2The following diagram shows the minimal steps to initialize and run an AfterPython project:
Sources: README.md62-69 src/afterpython/cli/commands/init.py50-108 src/afterpython/cli/commands/sync.py38-152 src/afterpython/cli/commands/build.py179-261
Install AfterPython as a development dependency using uv:
This command:
afterpython to the [project.optional-dependencies] or [tool.uv] section in pyproject.tomlap CLI entry point available in your project environmentNo project files or directories are created until ap init is executed.
Prerequisites:
uv package manager (for Python dependency management)pnpm (for SvelteKit website development)CLI Entry Points:
AfterPython provides two CLI entry points defined in src/afterpython/__init__.py7-15:
ap - Main AfterPython CLI (delegates to cli.main())pcu - Python Config Updater (delegates to update_py_deps.main())See page 2.1 for detailed system requirements and installation instructions.
Sources: README.md62-69 src/afterpython/__init__.py7-15
After installation, initialize your project structure:
The init() function in src/afterpython/cli/commands/init.py42-108 orchestrates the creation of the afterpython/ directory, configuration files, and GitHub Actions workflows.
The init() function in src/afterpython/cli/commands/init.py50-108 orchestrates initialization by calling multiple setup functions in sequence:
Sources: src/afterpython/cli/commands/init.py50-108 src/afterpython/tools/pyproject.py66-111 src/afterpython/cli/commands/init.py9-40
The init() command includes four optional prompts controlled by click.confirm(). Use --yes or -y to bypass prompts and accept all defaults:
| Prompt Text | Default | Line Reference | Created Files | Purpose |
|---|---|---|---|---|
| "Create .pre-commit-config.yaml in {afterpython_path}?" | Yes | 86-89 | afterpython/.pre-commit-config.yaml | Pre-commit hooks for ruff and commitizen |
| "Create ruff.toml in {afterpython_path}?" | Yes | 91-92 | afterpython/ruff.toml | Linting and formatting configuration |
| "Create commitizen configuration (cz.toml) in {afterpython_path} and release workflow in .github/workflows/release.yml?" | Yes | 94-100 | afterpython/cz.toml, .github/workflows/release.yml | Conventional commits and PyPI release automation |
| "Create Dependabot configuration (.github/dependabot.yml) to auto-update GitHub Actions versions?" | Yes | 102-107 | .github/dependabot.yml | Automated dependency updates for GitHub Actions |
Sources: src/afterpython/cli/commands/init.py86-107
The ap init command creates the following directory structure:
your-project/
├── afterpython/ # Created by init() at line :67
│ ├── doc/ # Created by init_myst() from CONTENT_TYPES
│ │ ├── myst.yml # MyST configuration
│ │ └── index.md # Default content
│ ├── blog/ # Created by init_myst()
│ │ ├── myst.yml
│ │ └── index.md
│ ├── tutorial/ # Created by init_myst()
│ │ ├── myst.yml
│ │ └── index.md
│ ├── example/ # Created by init_myst()
│ │ ├── myst.yml
│ │ └── index.md
│ ├── guide/ # Created by init_myst()
│ │ ├── myst.yml
│ │ └── index.md
│ ├── static/ # Created by init() at line :68
│ │ └── (place logo.svg, favicon.svg here)
│ ├── _website/ # Cloned by init_website() via 'ap update website'
│ │ ├── src/
│ │ │ ├── routes/ # SvelteKit routes (+page.svelte files)
│ │ │ └── lib/ # Shared components
│ │ ├── static/ # Website static files
│ │ └── package.json # Node.js dependencies managed by pnpm
│ ├── afterpython.toml # Created by init_afterpython()
│ ├── authors.yml # Created by init_myst()
│ ├── cz.toml # Created by init_commitizen() (optional)
│ ├── ruff.toml # Created by init_ruff_toml() (optional)
│ └── .pre-commit-config.yaml # Created by init_pre_commit() (optional)
├── .github/
│ └── workflows/
│ ├── ci.yml # Created by create_workflow('ci') at line :84
│ ├── deploy.yml # Created by create_workflow('deploy') at line :83
│ ├── release.yml # Created by create_workflow('release') (optional)
│ └── dependabot.yml # Created by create_dependabot() (optional)
├── src/
│ └── {package_name}/ # Found by find_package_directory()
│ └── py.typed # Created by init_py_typed() at line :38
└── pyproject.toml # Updated by init_pyproject()
Key Directories:
afterpython/ - Root directory for all AfterPython content and configuration (referenced as paths.afterpython_path)afterpython/doc/, blog/, tutorial/, example/, guide/ - Five content types defined in CONTENT_TYPES constant (see src/afterpython/const.py)afterpython/static/ - Static assets copied to website during postbuild phase (referenced as paths.static_path)afterpython/_website/ - SvelteKit website template (referenced as paths.website_path).github/workflows/ - GitHub Actions CI/CD workflows (referenced as paths.github_workflows_path)See page 2.3 for detailed path configuration and directory usage.
Sources: src/afterpython/cli/commands/init.py50-108 src/afterpython/const.py
This diagram maps initialization functions to the files and directories they create:
Sources: src/afterpython/cli/commands/init.py50-108 src/afterpython/const.py
After initialization, run ap sync to propagate metadata from pyproject.toml and afterpython.toml to derived configuration files:
This diagram shows how the sync() function reads source configurations and updates derived files:
Synchronization Steps:
Read source configurations - Lines 50-72 read pyproject.toml using StandardMetadata.from_pyproject() and afterpython.toml using read_afterpython()
Generate authors.yml - _sync_authors_yml() at 11-34 extracts pyproject.authors (list of tuples with name and email), converts names to IDs using convert_author_name_to_id(), and writes to afterpython/authors.yml
Update pyproject.toml URLs - Lines 93-97 update project.urls.homepage and project.urls.documentation based on afterpython.toml website URL
Update all myst.yml files - Loop at 101-152 updates each content type's myst.yml with:
project.authors - Author IDs referencing authors.ymlproject.venue - Company name and URLproject.copyright - Copyright noticeproject.title, description, keywords, github, thumbnail - From pyproject.toml and afterpython.tomlsite.title, site.options - Site configuration with logo, favicon, and logo_urlsite.actions - GitHub star buttonSources: src/afterpython/cli/commands/sync.py38-152 src/afterpython/cli/commands/sync.py11-34
Edit afterpython/afterpython.toml to configure company and website information:
These values are read by read_afterpython() and used by sync() to update all myst.yml files and pyproject.toml URLs. The paths are normalized using normalize_static_path() at src/afterpython/cli/commands/sync.py58-69
Run ap sync to propagate changes:
Sources: src/afterpython/cli/commands/sync.py52-72
Place static assets in afterpython/static/:
logo.svg - Site logo (referenced in afterpython.toml as /logo.svg)favicon.svg - Browser faviconlogo-dark.svg - Dark mode logo (optional)thumbnail.png - Social media preview imageDuring the postbuild() phase, all files from paths.static_path are copied to paths.website_path / "static" via _move_files() at src/afterpython/cli/commands/build.py165
Sources: src/afterpython/cli/commands/build.py165
Start the SvelteKit development server to preview the website:
The dev() command starts the website at http://localhost:5173 with hot module reloading. By default, it does not start MyST servers for content types.
Development Server Options:
When MyST servers are started, they provide live preview of content at URLs like http://localhost:3000 (doc), http://localhost:3001 (blog), etc.
See page 9.1 for detailed development server modes and workflows.
Sources: src/afterpython/cli/commands/dev.py
Add content files to any content directory (afterpython/doc/, blog/, tutorial/, example/, guide/):
.md) - Processed by MyST with support for directives, roles, and cross-references.ipynb) - Executed and rendered by MyST (use --execute flag during build)Each content directory has a myst.yml file that configures:
version - MyST configuration version (1)project - Project metadata (extends authors.yml)site - Site configuration (logo, favicon, navigation)See page 7.1 for content type organization and page 7.2 for MyST Markdown syntax.
Sources: src/afterpython/const.py src/afterpython/cli/commands/build.py214-250
Generate the production build:
The build() command in src/afterpython/cli/commands/build.py179-261 orchestrates a multi-stage build pipeline:
Build Pipeline Stages:
Stage Details:
Prebuild Phase (prebuild() at 64-96)
_check_initialized() - Verifies afterpython/afterpython.toml exists_clean_up_builds() - Removes afterpython/_build/, afterpython/_website/build/, and afterpython/_website/static/{content_type}/create_placeholder_index_md_files() - Creates placeholder index.md files for empty content directoriesbuild_metadata() - Generates metadata.json from pyproject.tomlbuild_markdown() - Injects Molab badges if AP_MOLAB_BADGE=1 environment variable is setbuild_jupyter_notebooks() - Processes notebook metadataMyST Build Phase (214-250)
determine_base_path() at 29-62 calculates BASE_PATH based on website URL (empty for custom domains, /repo-name for GitHub Pages)CONTENT_TYPES, runs myst build --html with environment variables:
BASE_URL - Set to {BASE_PATH}/{content_type} for correct routingBASE_PATH - Set to repository-specific path for GitHub Pages subdirectory hostingmyst.yml or content files (checked by has_content_for_myst())Postbuild Phase (postbuild(dev_build=False) at 98-166)
build_content_json() - Generates blog.json, tutorial.json, etc. for content listingsdelete_placeholder_index_md_files() - Removes placeholder files created in prebuild_move_files() - Copies MyST build outputs from afterpython/{content_type}/_build/html/ to afterpython/_website/static/{content_type}/afterpython/static/ to afterpython/_website/static/Website Build Phase (254-260)
pnpm build in afterpython/_website/ directory with BASE_PATH environment variableafterpython/_website/build/Optional Flags:
--execute - Executes Jupyter notebooks during MyST build (passed to myst build --execute)myst build commandSee page 6 for comprehensive build system architecture documentation.
Sources: src/afterpython/cli/commands/build.py179-261 src/afterpython/cli/commands/build.py64-96 src/afterpython/cli/commands/build.py98-166 src/afterpython/cli/commands/build.py29-62
Preview the production build locally:
The preview() command runs the SvelteKit preview server on the built static site in afterpython/_website/build/.
Sources: src/afterpython/cli/commands/dev.py
The .github/workflows/deploy.yml workflow automatically deploys to GitHub Pages when changes are pushed to the main branch. The workflow executes these steps:
uv sync, pnpm install)ap build to generate the static siteafterpython/_website/build/actions/deploy-pages@v4No manual deployment steps are required after initial setup. The deployment workflow is created by create_workflow('deploy') during ap init.
See page 5.2 for detailed deploy workflow configuration.
Sources: src/afterpython/tools/github_actions.py
After completing initialization and building your first site:
| Task | Command | Function/Module Reference | Documentation |
|---|---|---|---|
| Install dependencies | ap install | install() in cli/commands/install.py | Page 4.4.1 - Runs uv sync, pixi install, and pnpm install |
| Commit with conventional format | ap commit | commit() in cli/commands/commit.py | Page 4.6.1 - Runs pre-commit hooks and cz commit |
| Run tests | pytest | Test suite execution | Page 9.3 - Testing across Python 3.11-3.14 |
| Update dependencies | ap update deps | update() with deps subcommand (runs pcu) | Page 8.5 - Dependency update system |
| Bump version | ap bump | bump() in cli/commands/bump.py | Page 4.6.2 - Semantic versioning with cz bump |
| Set up branch protection | ap init-branch-rules | init_branch_rules() in cli/commands/git.py | Page 5.4 - GitHub branch protection |
| Update website template | ap update website | update() with website subcommand | Page 7.3 - Pulls latest project-website-template |
For complete CLI command reference, see page 4.
For development workflows, see page 9.
Sources: README.md73-80 src/afterpython/cli/commands/
Two environment variables control initialization behavior:
| Variable | Default | Effect |
|---|---|---|
AP_AUTO_SYNC | Not set | If set, automatically runs ap sync after certain operations |
AP_MOLAB_BADGE | 1 | Controls Molab badge injection into Jupyter notebooks during build |
See Environment Variables for complete reference.
Refresh this wiki