Simple and replicable Python server deployment toolkit
Project description
pyeasydeploy 0.1.0
A small library for deploying Python applications to Linux servers over SSH. Plain Python functions on top of Fabric: no agents on the server, no YAML, no DSL to learn. Your deploy script reads top to bottom.
It doesn't try to compete with Ansible or Docker. If you have a few servers, you write Python, and you want your deploy to be just another deploy.py in your project, it might be for you.
A complete deploy
from pyeasydeploy import (
SupervisorService, connect_to_host, create_venv,
deploy_supervisor_service, get_target_python_instance,
install_local_package,
)
APP = "myapp"
USER = "deploy"
conn = connect_to_host(
host="203.0.113.10",
user=USER,
key_filename="~/.ssh/id_ed25519",
sudo_password="...", # better: os.environ["SUDO_PASSWORD"]
)
py = get_target_python_instance(conn, "3.11")
venv = create_venv(conn, py, f"/home/{USER}/venvs/{APP}")
install_local_package(conn, venv, f"./{APP}")
deploy_supervisor_service(conn, SupervisorService(
name=APP,
command=f"{venv.venv_path}/bin/python -m {APP}",
directory=f"/home/{USER}",
user=USER,
))
Connect, pick an interpreter, create the venv, install your package with its dependencies, and leave it running as a supervised service that survives reboots. The venv object returned by create_venv carries its own path: the service command is built from it, no paths repeated by hand.
The ideas behind it
Destructive and reproducible. Uploads remove the destination and copy from scratch, every time. After each deploy, the server has exactly what you have locally — no leftovers from previous versions. This is not configurable; it's the contract. (The one safety net: paths like /, /home or /etc are rejected as destinations.)
Fail early, fail clearly. Models validate on construction: a relative path or a service name that would corrupt the INI file blows up on your laptop with a useful message, before touching the server. Functions that need sudo check for it upfront — an immediate error with instructions, instead of the classic hang waiting for a password that will never come.
Trust the user. The library validates form (types, absolute paths, dangerous characters), not your facts: if you hand-build a PythonInstance pointing at an exotic interpreter, it's accepted. You know what's on your server.
Installation
pip install pyeasydeploy
Python ≥ 3.10 on your machine. On the server: SSH and some python3 (tested on Debian/Ubuntu).
Quick guide
Connecting
conn = connect_to_host(host, user, password="...") # password (reused for sudo)
conn = connect_to_host(host, user, key_filename="~/.ssh/id_ed25519") # SSH key
With key auth and sudo operations, add sudo_password=. The connection is lazy: a wrong password shows up on the first command, not at connect time.
Remote Python
py = get_any_python_instance(conn) # newest on the server
py = get_target_python_instance(conn, "3.11") # a specific one
Only real interpreters are matched (python3.X-config and friends are filtered out), and version matching is component-wise: "3.1" means 3.1, not 3.11. For non-standard locations, build the model yourself:
py = PythonInstance(version="3.12", executable="/opt/py312/bin/python3.12")
Venvs and packages
venv = create_venv(conn, py, "/home/deploy/venvs/myapp") # idempotent
install_packages(conn, venv, ["fastapi", "uvicorn[standard]"])
install_local_package(conn, venv, "./myapp")
install_package_from_private_github(conn, venv, "git@github.com:org/private.git")
run_in_venv(conn, venv, "python -m myapp --check")
Installs use uv inside the venv (fast; use_uv=False for classic pip). Private repos are cloned on your machine with your own credentials, then the source is uploaded: the server never needs access to your GitHub.
Files
upload_directory(conn, "./data", "/home/deploy/data")
upload_file(conn, "config.toml", "/home/deploy/myapp/config.toml")
⚠️ Destructive: the destination is removed before copying. .git, __pycache__, venvs and similar are excluded by default (DEFAULT_IGNORE); pass ignore=[] to upload everything.
Services
install_supervisor(conn) # once per server
deploy_supervisor_service(conn, SupervisorService(
name="myapp",
command=f"{venv.venv_path}/bin/python -m myapp",
extra={
"stdout_logfile_maxbytes": "10MB", # any supervisord option,
"stdout_logfile_backups": 5, # passed through verbatim
"stopsignal": "INT",
},
))
supervisor_status(conn)
supervisor_restart(conn, "myapp")
Named fields cover the common cases; the extra dict accepts any supervisord option with no restrictions — the library only blocks what would corrupt the generated file.
What it is not
- Not Ansible/Terraform. No inventories, no state, no declarative idempotency. Imperative on purpose.
- Not provisioning. It installs supervisor because services are its job, and that's where it stops: nginx, databases and the rest of your server are up to you.
- No secret management. The passwords you pass in are your environment's responsibility.
- No fleet orchestration. One connection, one server. For several, write a loop.
- Linux targets only. The source machine can be Windows, macOS or Linux.
For many of those cases, bigger tools will do it better. This one exists for when you don't need them.
License
MIT
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 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 pyeasydeploy-0.1.0.tar.gz.
File metadata
- Download URL: pyeasydeploy-0.1.0.tar.gz
- Upload date:
- Size: 19.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f20a99262dbdec60031cee111b918a7d01ae5ca54c39bb048c712daee7bdc56c
|
|
| MD5 |
65b2e45c50b8d372d4313b4aebffba37
|
|
| BLAKE2b-256 |
51c600029a408e5d0f85a5cd37a0dfbaf3a62ee0b2e219ddb550b1eacd3039d5
|
File details
Details for the file pyeasydeploy-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyeasydeploy-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db5d3605699cc3d38427048ad964728aea26849511653d5c4761f61393a6ac03
|
|
| MD5 |
92d3e468d8b19d98c35e59d87c8b9d06
|
|
| BLAKE2b-256 |
0086b4cee90f4fee5a37b615f47e138fea64ad06ba09aa580b6de2a99ec5f13f
|