Skip to main content

awepatch

English | 中文

Awesome Patch - A Python library for runtime function patching using AST manipulation.

Build Status Python Version License

Overview

awepatch is a powerful Python library that allows you to dynamically patch source code at runtime by manipulating their Abstract Syntax Tree (AST). Unlike traditional monkey patching, awepatch modifies the actual code object of functions, providing a cleaner and more maintainable approach to runtime code modification.

Features

  • 🔧 Runtime Function Patching: Modify function behavior without changing source code
  • 🎯 AST-Based Manipulation: Clean and precise code modifications using AST
  • 🔄 Automatic Restoration: Context manager support for temporary patches
  • 🎭 Multiple Patch Modes: Insert code before, after, or replace existing statements
  • 🧩 Pattern Matching: Use string, regex, or tuple patterns to locate code to patch
  • 🎯 Nested Matching: Target nested code blocks with tuple pattern syntax
  • 🔗 Decorator Support: Works with decorated functions, class methods, and static methods
  • ⚡ Type-Safe: Full type hints support with strict type checking

Installation

pip install awepatch

Or using uv:

uv pip install awepatch

Quick Start

Function Patching

import re

from awepatch import FunctionPatcher


def calculate(x: int, y: int) -> int:
    x = x + 10
    y = y * 2
    result = x + y
    return result


patcher = FunctionPatcher()
patcher.add_patch(
    calculate,
    target="x = x + 10",
    content="print(f'processing: {x=}')",
    mode="before",
)
patcher.add_patch(
    calculate,
    target="y = y * 2",
    content="y = y * 3",
    mode="replace",
)
patcher.add_patch(
    calculate,
    target=re.compile(r"result = x \+ y"),
    content="print(f'result: {result}')",
    mode="after",
)
with patcher:
    print(calculate(5, 10))

# Output:
# processing: x=5
# result: 45
# 45

Module Patching

# foo.py
from dataclasses import dataclass

@dataclass(slots=True)
class User:
    name: str
    age: int

def greet(user: User) -> str:
    if hasattr(user, "gender"):
        return f"Hello, {user.name}! You are {user.age} years old. Your gender is {user.gender}."
    else:
        return f"Hello, {user.name}! You are {user.age} years old."

# example.py
from awepatch.module import ModulePatcher

patcher = ModulePatcher()
patcher.add_patch(
    "foo",
    target=(
        "class User:",
        "age: int",
    ),
    content=""" 
gender: str = "unspecified"
""",
    mode="after",
)
with patcher:
    import foo
    user = foo.User(name="Bob", age=25)
    print(foo.greet(user))

# Output: Hello, Bob! You are 25 years old. Your gender is unspecified.

Nested Pattern Matching

For complex nested structures, you can use tuple patterns or lineno offsets to match nested AST nodes:

from awepatch import FunctionPatcher, Ident


def nested_function(x: int) -> int:
    if x > 0:
        x = x * 2
    x = x * 2
    return x


# Match nested statement inside if block
with FunctionPatcher().add_patch(
    nested_function,
    target=("if x > 0:", "x = x * 2"),
    content="x = x * 3",
    mode="replace",
):
    print(nested_function(5))  # Output: 30


# Or match by line number offset
with FunctionPatcher().add_patch(
    nested_function,
    target=Ident("x = x * 2", lineno="+2"),
    content="x = x * 3",
    mode="replace",
):
    print(nested_function(5))  # Output: 30

Advanced Usage

Patch for multi-process applications

For applications that spawn multiple processes, you must use ModulePatcher to ensure that patches are applied in each child process.

Use .pth file to auto-apply patches on module import in each process may be a good choice.

# loader.py
patcher = ModulePatcher()
patcher.add_patch(
    "foo",
    target=(
        "class User:",
        "age: int",
    ),
    content 
)
patcher.apply()

# xxx-awepatch.pth
# xxx-awepatch.pth must be placed in site-packages directory
import loader

See Also:

https://github.com/tox-dev/pre-commit-uv/blob/main/src/pre_commit_uv_patch.pth https://github.com/pypa/setuptools/blob/main/setup.py#L12 https://github.com/jawah/urllib3.future/blob/main/urllib3_future.pth

Use Cases

  • Testing: Mock function behavior without complex mocking frameworks
  • Debugging: Inject logging or debugging code at runtime
  • Hot-patching: Apply fixes or modifications without restarting applications
  • Experimentation: Test code changes quickly without modifying source files
  • Instrumentation: Add monitoring or profiling code dynamically

Limitations

  • Lambda functions cannot be patched (they lack proper source code information)
  • Functions must have accessible source code via inspect.getsourcelines()
  • Pattern matching must uniquely identify target statement(s) in the function
  • Only single function definitions are supported in the AST
  • Conflicting patches (e.g., combining 'replace' with 'before'/'after' on same target) are not allowed

Development

Setup Development Environment

# Clone the repository
git clone https://github.com/fanck0605/awepatch.git
cd awepatch

# Install development dependencies
uv sync

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=awepatch --cov-report=html

# Run specific test file
pytest tests/test_patch_callable.py

Code Quality

# Format code
ruff format

# Lint code
ruff check

# Fix auto-fixable issues
ruff check --fix

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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Chuck Fan - fanck0605@qq.com

Acknowledgments

  • Inspired by the need for cleaner runtime code modification in Python
  • Built with modern Python tooling and best practices

Note: This library modifies function code objects at runtime. Use with caution in production environments and always test thoroughly.

Metadata

Release files for awepatch 0.1.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for awepatch 0.1.9
File Size Uploaded
awepatch-0.1.9.tar.gz 54.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for awepatch 0.1.9
File Interpreter ABI Platform
awepatch-0.1.9-py3-none-any.whl Python 3 none any Details

Total release size: 68.5 kB

Release files / awepatch-0.1.9.tar.gz

Download URL awepatch-0.1.9.tar.gz
Size 54.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ba7d3642f37ee90b0fb1a42c6e13cf917dd706789192d1ab9fc6b6bb1a938837
BLAKE2b-256 checksum
How to use checksums
cb67529267d14908233329f2d33eed20fef3204cf27a430bb07f988ceeea4038
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 18, 2026.

Transparency log

Release files / awepatch-0.1.9-py3-none-any.whl

Download URL awepatch-0.1.9-py3-none-any.whl
Size 13.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a087e12079bb3d100a2470785b7adb5da10eb903e7c02fedbf11703fefacd8c2
BLAKE2b-256 checksum
How to use checksums
d4de321d5051dd7954be3fe1a8092ef0f3c7613e3f03d4e82f680f72f42936ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.9 This release

2 release files

0.1.8

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page