Python packaging made human — initialise, build, version, and deploy Python packages from one CLI or GUI.
PiPnDeploy wraps the Python packaging workflow — pyproject.toml generation, dependency detection, building, version bumping, and PyPI upload — into a single tool with both a desktop GUI and a CLI.
It is designed for solo developers and small teams who want to stop copy-pasting packaging boilerplate between projects.
- Init — generate a PEP 621-compliant
pyproject.tomlfrom a form or a single command - Surgical update — edit only the fields you own;
[tool.ruff],[tool.pytest],[tool.hatch], comments, and custom sections are never touched - Dependency detection — AST scan your package folder; stdlib and self-imports are excluded automatically; supports flat,
src/, and multi-package layouts - Build — wraps
python -m buildwith a pre-build hook gate - Deploy — wraps
twine uploadwith a pre-flight auth check so it never hangs waiting for interactive input - Version bump — patch / minor / major from the GUI version tab or
pipndeploy bump - Clean — removes build artefacts; uninstall is always opt-in
- Auth check — validates
~/.pypirctoken configuration before attempting upload - Lifecycle hooks —
hooks/pre_build.pyandhooks/post_deploy.pywith correct lifecycle (post-deploy runs only after a successful upload, never during dry-run) - GUI and CLI — same core logic, two interfaces
CLI only (no Qt required):
pip install pipndeployCLI + GUI:
pip install pipndeploy[gui]# Initialise packaging metadata for an existing project
pipndeploy init
# Initialise and also create a minimal package skeleton
pipndeploy init --create-package
# Check whether a package name is available on PyPI
pipndeploy name-check my-package
# Build wheel + sdist
pipndeploy build
# Upload to TestPyPI (dry run first)
pipndeploy deploy --test --dry-run
# Upload to PyPI
pipndeploy deploy
# Bump the patch version (1.2.3 → 1.2.4)
pipndeploy bump patch
# Bump minor or major
pipndeploy bump minor
pipndeploy bump major
# Set an exact version
pipndeploy bump --set 2.0.0
# Clean build artefacts (does NOT uninstall by default)
pipndeploy clean
# Clean and uninstall (opt-in)
pipndeploy clean --uninstall
# Validate ~/.pypirc token configuration
pipndeploy auth-check
# Full interactive pipeline (init → build → deploy)
pipndeploy full
# All commands accept --project-dir / -d to target a specific directory
pipndeploy build -d /path/to/my-projectLaunch the GUI:
# If installed with [gui] extra
pipndeploy-gui
# Or from the project root
python -m PiPnDeploy.gui_mainThe GUI provides tabs for every operation. The Init tab pre-fills from an existing pyproject.toml if one is found in the project directory. The Version tab shows a two-step preview before writing anything to disk.
PiPnDeploy is designed to be non-destructive by default:
| Operation | Default behaviour | Opt-in to be destructive |
|---|---|---|
clean |
Removes build/, dist/, *.egg-info |
--uninstall to also remove the package |
init on existing project |
Warns before overwriting pyproject.toml |
Confirm in dialog |
~/.pypirc generation |
Warns before overwriting, creates .pypirc.bak |
Confirm in dialog |
post_deploy hook |
Runs only after successful upload | — |
pre_build hook |
Failure aborts the build | — |
| Surgical TOML update | Only edits [project] fields; all other sections preserved |
— |
Place Python scripts in a hooks/ directory at your project root:
my-project/
hooks/
pre_build.py # runs before build; non-zero exit aborts the build
post_deploy.py # runs after successful upload; skipped on dry-run
Hooks receive no arguments. Use sys.exit(1) to signal failure.
Use the Auth Gen tab or configure ~/.pypirc manually:
[distutils]
index-servers =
pypi
testpypi
[pypi]
repository = https://upload.pypi.org/legacy/
username = __token__
password = pypi-your-token-here
[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-your-testpypi-token-hereRun pipndeploy auth-check to validate your configuration before deploying.
On Unix-like systems, PiPnDeploy sets ~/.pypirc permissions to 600 (owner read/write only) automatically.
PiPnDeploy AST-scans your package folder to detect third-party imports. It supports:
- Flat layout:
my-project/mypkg/__init__.py - src layout:
my-project/src/mypkg/__init__.py - Multi-package: multiple packages in the same project root
The following are always excluded from the scan:
- Python standard library modules
- The project's own package name (self-imports)
- Directories:
tests,docs,examples,build,dist,.venv,venv - Files:
conftest.py,dummy.py,setup.py
Auto-detected dependencies are a starting point. Review them before publishing.
- Dependency detection is AST-based and may miss dynamic imports (
importlib.import_module,__import__) or conditional imports behind non-trivial logic - The GUI does not update
[project.scripts]in surgical mode — use the Init tab to change entry points - No Git integration (commit, tag, release) — this is intentional; PiPnDeploy handles packaging, not source control
- Pre-release version strings (
1.2.3rc1,1.2.3.dev0) are not incremented bybump— use--setfor those
git clone https://github.com/7h3v01d/PiPnDeploy
cd PiPnDeploy
pip install -e ".[gui,dev]"
python -m pytest tests/ -vPiPnDeploy/
├── PiPnDeploy/
│ ├── __init__.py
│ ├── cli_main.py # Typer CLI — thin wrapper around core_logic
│ ├── core_logic.py # All shared logic — the single source of truth
│ ├── gui_main.py # PyQt6 GUI — thin wrapper around core_logic
│ └── Utils/
│ └── __init__.py
├── tests/
│ ├── test_clean_safety.py
│ ├── test_dep_detection.py
│ ├── test_entry_point_wrappers.py
│ ├── test_fixes_5678.py
│ ├── test_init_scaffold.py
│ ├── test_items_123.py
│ ├── test_pyproject_generation.py
│ └── test_version_bump.py
├── hooks/ # Optional lifecycle hooks (user-created)
├── pyproject.toml
└── README.md
MIT — see LICENSE for details.