CLI tool to publish Python packages and documentation with external configuration
Project description
cal-publish-python
CLI tool to publish Python packages and documentation with external configuration.
Overview
cal-publish-python is designed to keep sensitive configuration (tokens, registry URLs, SSH keys) outside of build jobs. The project being published defines the "what" (name, version), while a named profile in the publishing configuration defines the "where" (registry, documentation platform).
Installation
pip install cal-publish-python
Or with uv:
uv pip install cal-publish-python
Usage
# Publish everything in output/ (wheel + docs zip)
cal-publish-python --set-latest output/
# Publish only the PyPI package
cal-publish-python --pypi-only output/
# Publish only the documentation
cal-publish-python --docs-only --set-latest output/
# Specify a profile explicitly
cal-publish-python --profile internal --set-latest output/
# Specify individual files
cal-publish-python output/my-package-1.0.0-py3-none-any.whl output/my-package-1.0.0-docs.zip
CLI Arguments
| Argument | Short | Description |
|---|---|---|
ARTIFACT |
Directory or file(s) to publish (.whl and/or docs .zip) | |
--config |
-c |
Path to JSON configuration file |
--profile |
Profile to use from the configuration file | |
--pypi-only |
Only publish to PyPI (skip documentation) | |
--docs-only |
Only publish documentation (skip PyPI) | |
--set-latest |
-l |
Also set this version as 'latest' (GitLab Pages mode only) |
--force |
-f |
Overwrite existing documentation version if it exists |
--verbose |
-v |
Verbose output |
Configuration
Profiles
Configuration uses named profiles. Each profile contains the full set of publishing settings (PyPI credentials, documentation targets, etc.). This allows the same config file to serve both public and internal publishing.
Create a JSON config file at ~/.config/cal-publish-python/config.json:
{
"profiles": {
"public": {
"pypi": {
"token": "pypi-xxxxxxxxxxxx",
"username": "__token__",
"repository_url": "https://upload.pypi.org/legacy/"
},
"docs": {
"mode": "gitlab-pages",
"gitlab_pages": {
"token": "glpat-xxxxxxxxxxxx",
"url": "https://gitlab.com",
"group": "mygroup/public/docs"
}
}
},
"internal": {
"pypi": {
"token": "nexus-xxxxxxxxxxxx",
"username": "deploy-user",
"repository_url": "https://nexus.internal/repository/pypi/"
},
"docs": {
"mode": "ssh",
"ssh": {
"host": "docs.internal",
"base_path": "/var/www/docs"
}
}
}
}
}
Profile Selection
A profile is required when a config file is present. The profile is resolved in this order:
--profile NAMECLI argumentCAL_PUBLISH_PROFILEenvironment variable[tool.cal-publish-python]inpyproject.toml:
[tool.cal-publish-python]
profile = "public"
This means each project can declare which profile it uses, and make publish just works without any extra arguments.
Config File Location
The config file is resolved in this order:
--config FILECLI argumentCAL_PUBLISH_CONFIGenvironment variable~/.config/cal-publish-python/config.json(default)
If no config file exists at the default path, the tool runs in environment-variable-only mode (useful for CI).
Environment Variables
All configuration values can be overridden by environment variables, regardless of what the config file/profile contains:
| Variable | Description |
|---|---|
CAL_PUBLISH_CONFIG |
Path to JSON config file |
CAL_PUBLISH_PROFILE |
Profile name to use from config file |
CAL_PUBLISH_PYPI_TOKEN |
PyPI API token or password |
CAL_PUBLISH_PYPI_USERNAME |
PyPI username (default: __token__) |
CAL_PUBLISH_PYPI_REPOSITORY_URL |
PyPI repository URL |
CAL_PUBLISH_DOCS_MODE |
Documentation mode (gitlab-pages, ssh, or cal-docs-server) |
CAL_PUBLISH_GITLAB_TOKEN |
GitLab personal access token |
CAL_PUBLISH_GITLAB_URL |
GitLab instance URL |
CAL_PUBLISH_GITLAB_GROUP |
GitLab group for docs |
CAL_PUBLISH_SSH_HOST |
SSH host |
CAL_PUBLISH_SSH_BASE_PATH |
Base path on remote server |
CAL_PUBLISH_SSH_KEY |
Path to SSH private key |
CAL_PUBLISH_SSH_USER |
SSH user |
CAL_PUBLISH_SSH_PORT |
SSH port |
CAL_PUBLISH_DOCS_SERVER_URL |
cal-docs-server URL |
CAL_PUBLISH_DOCS_SERVER_TOKEN |
API token for cal-docs-server |
Integration with Makefile
Add a publish target to your project's Makefile:
.PHONY: publish
publish: check-dependencies
uv run cal-publish-python --set-latest output/
And declare the profile in pyproject.toml:
[tool.cal-publish-python]
profile = "public"
Documentation Zip Filename
The docs zip filename is used to determine the project name and version:
project-name-VERSION-docs.zip
Examples: myproject-1.0.0-docs.zip, my-lib-2.3.4.post5+gabcdef-docs.zip
Development
# Clone the repository
git clone <repo-url>
cd cal-publish-python
# Set up development environment
make dev
# Run checks
make check
# Build
make build
Licence
MIT License - Copyright (c) 2026 Cyber Assessment Labs
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
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 cal_publish_python-1.1.0b1-py3-none-any.whl.
File metadata
- Download URL: cal_publish_python-1.1.0b1-py3-none-any.whl
- Upload date:
- Size: 31.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97e066062be51b5be5ed3849ac7f30a22cbf2f5b89f24a86c0b72aa3c3a685b5
|
|
| MD5 |
3b3b6c4b159d9828481ed842a24cb8c1
|
|
| BLAKE2b-256 |
e25b588aa22bc0018859e0f9b41baecd5b3eec189196b9ed12cc35639e215a35
|