A cross-platform Python deployment framework for automated remote server deployments via SSH
Project description
🌼 PyDaffodil
Cross-Platform Python Deployment Framework
Automate remote server deployments with ease. Transfer files, execute commands, and manage deployments across Windows, macOS, and Linux.
📋 Table of Contents
- Overview
- Features
- Installation
- Quick Start
- Usage Examples
- API Reference
- Requirements
- Contributing
- License
🎯 Overview
PyDaffodil is a powerful, cross-platform Python deployment framework designed to simplify and automate the process of deploying applications to remote servers via SSH. Whether you're deploying to a VPS, cloud instance, or dedicated server, PyDaffodil provides a clean, intuitive API for managing your deployment workflows.
Key Benefits
- ✅ Cross-Platform: Works seamlessly on Windows, macOS, and Linux
- ✅ No Admin Required: Runs without administrator privileges
- ✅ Efficient Transfers: Automatically archives files before transfer for faster deployments
- ✅ Secure: Supports SSH key and password authentication
- ✅ Progress Tracking: Visual progress bars for file transfers and operations
- ✅ Modular: Build reusable deployment steps with a simple, declarative API
✨ Features
Core Capabilities
- 🔐 Secure SSH Connections: Connect using SSH keys (RSA, DSA, ECDSA, Ed25519) or password authentication
- 📦 Smart File Transfer: Automatically creates archives before transfer and extracts them on the remote server
- ⚡ Remote Command Execution: Execute shell commands and SSH commands on remote servers
- 📁 Directory Management: Create directories and manage file structures on remote servers
- 🎨 Colored Output: Beautiful, color-coded terminal output for better visibility
- 📊 Progress Tracking: Real-time progress bars for file operations
- 🔄 Deployment Workflows: Chain multiple deployment steps together for complex workflows
Technical Features
- Cross-platform archive creation and extraction (ZIP format)
- Automatic cleanup of temporary files
- Comprehensive error handling and reporting
- Support for hidden files and directories
- Configurable remote paths and SSH ports
- Ignore file support (
.scpignore)
🚀 Installation
Prerequisites
- Python 3.6 or higher
- SSH access to your remote server
- SCP installed on your local machine (usually comes with SSH)
Install from PyPI
pip install pydaffodil
Verify Installation
from pydaffodil import Daffodil
print("PyDaffodil installed successfully!")
🏃 Quick Start
Here's a simple example to get you started:
from pydaffodil import Daffodil
# Initialize the deployment client
cli = Daffodil(
remote_user="root",
remote_host="your-server.com",
remote_path="/var/www/myapp"
)
# Define deployment steps
steps = [
{"step": "Build the project", "command": lambda: cli.run_command("npm run build")},
{"step": "Transfer files", "command": lambda: cli.transfer_files("dist")},
{"step": "Restart service", "command": lambda: cli.ssh_command("sudo systemctl restart myapp")}
]
# Execute deployment
cli.deploy(steps)
📚 Usage Examples
Basic File Transfer
from pydaffodil import Daffodil
cli = Daffodil(
remote_user="deploy",
remote_host="192.168.1.100",
remote_path="/home/deploy/app"
)
# Transfer files (automatically archived and extracted)
cli.transfer_files("build", destination_path="/home/deploy/app/production")
Using SSH Keys
cli = Daffodil(
remote_user="deploy",
remote_host="example.com",
ssh_key_path="~/.ssh/id_rsa",
ssh_key_pass="your-passphrase" # Optional, only if key is encrypted
)
Custom Port and Path
cli = Daffodil(
remote_user="admin",
remote_host="server.example.com",
port=2222, # Custom SSH port
remote_path="/opt/myapplication"
)
Complex Deployment Workflow
from pydaffodil import Daffodil
cli = Daffodil(
remote_user="root",
remote_host="production.example.com",
remote_path="/var/www/production"
)
steps = [
{
"step": "Build frontend",
"command": lambda: cli.run_command("cd frontend && npm run build")
},
{
"step": "Build backend",
"command": lambda: cli.run_command("cd backend && npm run build")
},
{
"step": "Stop services",
"command": lambda: cli.ssh_command("sudo systemctl stop myapp")
},
{
"step": "Backup current deployment",
"command": lambda: cli.ssh_command("cp -r /var/www/production /var/www/backup/$(date +%Y%m%d_%H%M%S)")
},
{
"step": "Transfer frontend",
"command": lambda: cli.transfer_files("frontend/dist", "/var/www/production/frontend")
},
{
"step": "Transfer backend",
"command": lambda: cli.transfer_files("backend/dist", "/var/www/production/backend")
},
{
"step": "Install dependencies",
"command": lambda: cli.ssh_command("cd /var/www/production/backend && npm install --production")
},
{
"step": "Start services",
"command": lambda: cli.ssh_command("sudo systemctl start myapp")
}
]
cli.deploy(steps)
📖 API Reference
Daffodil Class
Constructor Parameters
remote_user(str, required): Username for SSH connectionremote_host(str, required): Hostname or IP address of the remote serverremote_path(str, optional): Default remote directory pathport(int, optional): SSH port number (default: 22)ssh_key_path(str, optional): Path to SSH private key filessh_key_pass(str, optional): Passphrase for encrypted SSH keysscp_ignore(str, optional): Path to ignore file (default: ".scpignore")
Methods
transfer_files(local_path, destination_path=None)
Transfer files and directories to the remote server. Files are automatically archived before transfer and extracted on the remote server.
local_path(str): Local directory or file path to transferdestination_path(str, optional): Remote destination path (defaults toremote_path)
run_command(command)
Execute a shell command on the local machine.
command(str): Shell command to execute
ssh_command(command)
Execute a command on the remote server via SSH.
command(str): Command to execute on remote server
make_directory(directory_name)
Create a directory on the remote server.
directory_name(str): Name of the directory to create
deploy(steps)
Execute a series of deployment steps.
steps(list): List of step dictionaries, each containing:step(str): Description of the stepcommand(callable): Lambda function or callable to execute
🔧 Requirements
System Requirements
- Python 3.6+
- SCP (usually included with SSH/OpenSSH)
Python Dependencies
paramiko>= 2.0.0 - SSH client librarytqdm>= 4.60.0 - Progress barscolorama>= 0.4.0 - Cross-platform colored terminal output
🌍 Cross-Platform Support
PyDaffodil is fully cross-platform and has been tested on:
- Windows 10/11
- macOS (all recent versions)
- Linux (Ubuntu, Debian, CentOS, etc.)
The framework automatically handles platform-specific differences in:
- Archive creation and extraction
- File path handling
- SSH key detection
- Command execution
🔒 Security
PyDaffodil prioritizes security:
- Supports all major SSH key types (RSA, DSA, ECDSA, Ed25519)
- Encrypted key support with passphrase protection
- Secure password authentication (when keys aren't available)
- No storage of credentials in code
- Automatic cleanup of temporary files
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📝 Publishing to PyPI
Automated Publishing (Recommended)
This project uses GitHub Actions to automatically publish to PyPI when a new release is created.
Setup:
- Go to your PyPI account settings: https://pypi.org/manage/account/
- Create an API token: https://pypi.org/manage/account/token/
- Add the token as a GitHub secret:
- Go to your repository → Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name:
PYPI_API_TOKEN - Value: Your PyPI API token (starts with
pypi-)
Publishing:
- Update version in
setup.py - Commit and push your changes
- Create a new release on GitHub (the workflow will automatically publish to PyPI)
Alternatively, you can trigger the workflow manually:
- Go to Actions → "Publish to PyPI" → Run workflow
Manual Publishing
To publish manually:
- Update version in
setup.py - Install build tools:
pip install build twine - Build package:
python -m build - Check package:
twine check dist/* - Upload:
twine upload dist/*
For testing, use TestPyPI:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
👤 Author
Mark Wayne Menorca
- Email: marcuwynu23@gmail.com
- GitHub: @marcuwynu23
🙏 Acknowledgments
- Built with Paramiko for SSH functionality
- Progress bars powered by tqdm
- Cross-platform colors with Colorama
Made with ❤️ for developers who love automation
⭐ Star this repo if you find it useful!
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 pydaffodil-1.2.0.tar.gz.
File metadata
- Download URL: pydaffodil-1.2.0.tar.gz
- Upload date:
- Size: 18.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66bd7d09914850181a10e4a449ed97aba2a0ba383cf38be2c089d671c1ab1e5e
|
|
| MD5 |
63e1c92b5e7a35beaa2280cfcb7a5787
|
|
| BLAKE2b-256 |
b28979c57939f2f8269e336e50b2c0daff1b90bbd35bd79110ef216b5e02b9bc
|
File details
Details for the file pydaffodil-1.2.0-py3-none-any.whl.
File metadata
- Download URL: pydaffodil-1.2.0-py3-none-any.whl
- Upload date:
- Size: 13.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
106bada1a210e8750661baad1d670dfa27052c720bf29e436f95cd93a350c198
|
|
| MD5 |
c45cfa03f269480cf3a246e321c5f8c7
|
|
| BLAKE2b-256 |
c7761cd48a7e583a837a621e89f16c881e06eb0fc2de706c2044fdaf50b438d3
|