Skip to main content

Python Makefile - Simple command orchestration through Makefile.py

Project description

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 command
  • pmake 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=value overrides 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", ".")

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_pmake-0.1.0.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_pmake-0.1.0-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

Details for the file python_pmake-0.1.0.tar.gz.

File metadata

  • Download URL: python_pmake-0.1.0.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.13

File hashes

Hashes for python_pmake-0.1.0.tar.gz
Algorithm Hash digest
SHA256 abc6b7f971d4e57a9e15299deee65c084d99365201955abfaf5937be2cb90ab7
MD5 742b8be9eac5913d5dfcfaa35eb2349a
BLAKE2b-256 8cb386e981495467560ad732900515929f1a15d4ce10bc2a6c526606ec404118

See more details on using hashes here.

File details

Details for the file python_pmake-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for python_pmake-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0837fb8ba5f7aae388976fb360de22780693649ef350979a2d97d67e94f0f610
MD5 28a490f70b06574618bf758ef94bd937
BLAKE2b-256 920e21d94853cd85b43294a9f825bde6946010c4006fa1c9ab430c3f575d23ae

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page