Python Makefile (pmake)
Using Makefiles for project command orchestration is becoming more common.
However often writing logic in bash is a pain - pmake allows writing everything in Python using the powerful amoffat/sh library.
Note: Python Makefile (pmake) is not for building CLIs, just a simple way to run orchestration within your project.
Overview
# Create a Makefile.py in your project directory (see guidance with pmake when no file exists)
# Run the default command from your Makefile.py
pmake
# Run specific command directly
pmake build_images
pmake status
pmake build_and_push
# Pass parameters and override environment variables
pmake build_images IMAGE=myapp VERSION=1.0.0
Example:
Content in Makefile.py
from pmake import sh, _, dep
from pmake import docker, git, echo # Direct command imports
# Read from env
DOCKER_REPO = _('DOCKER_REPO')
IMAGE = _('IMAGE')
VERSION = _('VERSION', "0.0.1") # Default value
def build_images():
# Use sh object - automatically inherits environment including venv
sh.docker("build", "-f", "./docker/Dockerfile", ".",
"-t", f"{DOCKER_REPO}/{IMAGE}:{VERSION}")
def push_images():
# Use direct command imports - environment variables from _() automatically available
docker("push", f"{DOCKER_REPO}/{IMAGE}:{VERSION}")
def status():
# All commands automatically use your current shell environment
git("status")
echo(f"Build completed for {IMAGE} v{VERSION}!")
@dep(build_images, push_images)
def build_and_push():
pass
Run commands
# Runs the default command (first alphabetically: build_and_push in this case)
pmake
# Run specific commands directly
pmake build_images
pmake push_images
pmake status
# Runs build_and_push (with dependencies: build_images, push_images)
pmake build_and_push
# Run with parameter overrides
pmake build_and_push IMAGE="myimage" VERSION="2.0.0"
# See all available commands with descriptions and dependencies
pmake --help
Getting Started
Creating Your First Makefile.py
When you run pmake in a directory without a Makefile.py, it will show helpful guidance. Here's a simple starter example:
from pmake import sh, _, dep
from pmake import echo, python, pip
def hello():
'''Say hello - this will be your default command'''
echo('Hello from pmake!')
def test():
'''Run tests'''
python('-m', 'pytest')
@dep(test)
def deploy():
'''Deploy after running tests'''
echo('Deploying application...')
Then run:
pmake- Runs default command (hello in this case)pmake test- Runs test commandpmake deploy- Runs test, then deploy (due to @dep dependency)pmake --help- Shows all available commands with descriptions and dependencies
Features
Universal Command Imports
Import any shell command directly from pmake:
from pmake import docker, git, echo, ls, grep, curl, wget, find
# Equivalent to: from sh import docker, git, echo, ls, grep, curl, wget, find
# Use them directly
docker("build", "-t", "myapp", ".")
git("commit", "-m", "Update")
echo("Hello World")
Powerful Shell Execution with Automatic Environment Inheritance
pmake uses the amoffat/sh library under the hood with enhanced environment management:
- Automatic virtual environment inheritance: Commands use your current venv
- Environment variable tracking: Variables accessed via
_()are automatically available to shell commands - Parameter override inheritance: CLI
PARAM=valueoverrides are passed to all shell commands - Better error handling and superior command composition
- Rich command objects with piping support
No more _env=os.environ needed! All pmake shell commands automatically include:
- Your current shell environment (including PATH, VIRTUAL_ENV, etc.)
- Any environment variables accessed through
_()calls - Any parameter overrides from the command line
Automatic Environment Inheritance
All shell commands automatically inherit your environment:
from pmake import sh, python, pip, _
# Environment variables accessed via _() are tracked
VENV_PATH = _('VIRTUAL_ENV')
PROJECT_NAME = _('PROJECT_NAME', 'myproject')
def setup_venv():
# python command automatically uses current virtual environment
python("-m", "pip", "install", "-e", ".")
# No need for _env=os.environ - it's automatic!
pip("install", "pytest", "black", "mypy")
def test():
# All environment variables from _() calls are available
python("-c", f"print('Testing {PROJECT_NAME}')")
Both Syntaxes Supported
from pmake import sh, docker
# Option 1: Direct imports (automatically inherit environment)
docker("build", "-t", "myapp", ".")
# Option 2: Through sh object (automatically inherit environment)
sh.docker("build", "-t", "myapp", ".")
# Complex shell operations (with full environment)
sh.bash("-c", "docker build . | grep 'Successfully built'")
Equivalent makefile
IMAGE ?= $(IMAGE)
DOCKER_REPO ?= $(DOCKER_REPO)
VERSION ?= $(VERSION)
build_images:
docker build -f ./docker/Dockerfile . \
-t $(DOCKER_REPO)/$(IMAGE):$(VERSION)
push_images:
docker push $(DOCKER_REPO)/$(IMAGE):$(VERSION)
build_and_push: build_images, push_images
Migration from bash()
The old bash() function has been removed in favor of direct command usage:
# OLD (removed)
bash("echo hello")
bash("docker build -t myapp .")
# NEW - Direct imports
from pmake import echo, docker
echo("hello")
docker("build", "-t", "myapp", ".")
# NEW - sh object
from pmake import sh
sh.echo("hello")
sh.docker("build", "-t", "myapp", ".")
Metadata
Release files for python-pmake 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| python_pmake-0.1.0.tar.gz | 19.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| python_pmake-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.5 kB
Release files / python_pmake-0.1.0.tar.gz
| Download URL | python_pmake-0.1.0.tar.gz |
|---|---|
| Size | 19.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
abc6b7f971d4e57a9e15299deee65c084d99365201955abfaf5937be2cb90ab7
|
|
BLAKE2b-256 checksum How to use checksums |
8cb386e981495467560ad732900515929f1a15d4ce10bc2a6c526606ec404118
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.13
|
Release files / python_pmake-0.1.0-py3-none-any.whl
| Download URL | python_pmake-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0837fb8ba5f7aae388976fb360de22780693649ef350979a2d97d67e94f0f610
|
|
BLAKE2b-256 checksum How to use checksums |
920e21d94853cd85b43294a9f825bde6946010c4006fa1c9ab430c3f575d23ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.13
|
Security for python-pmake 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.