DEV Community

Cover image for Quick Tips: Monkey Patching
Nathan Caracho
Nathan Caracho

Posted on

Quick Tips: Monkey Patching

Monkey Patching Done Right: Essential Rules for Safe Runtime Modifications

Monkey patching is a runtime component override. This is useful for mocking dependencies during testing or extending features from an external library.

Let's patch the print function:

import builtins

original_print = builtins.print

def monkey_print(*args, **kwargs):
    message = ' '.join(map(str, args))
    original_print(f'🐵{message}🐵', **kwargs)

# Applying the patch
builtins.print = monkey_print
print('This is a monkey patching')  # 🐵This is a monkey patching🐵
Enter fullscreen mode Exit fullscreen mode

Okay, this is a great tool for unit testing, extending a feature from that library, or fixing that midnight issue. But take it easy—using monkey patching is very dangerous if you don't follow these golden rules.

Be explicit

You should explicitly patch the feature by creating a new function to patch:

import builtins

original_print = builtins.print

def monkey_print(*args, **kwargs):
    message = ' '.join(map(str, args))
    original_print(f'🐵{message}🐵', **kwargs)

def apply_print_patch():
    builtins.print = monkey_print

apply_print_patch()
print('This is a monkey patching')  # 🐵This is a monkey patching🐵
Enter fullscreen mode Exit fullscreen mode

Encapsulate business logic

Modularize your business logic by creating dedicated functions or classes, which naturally leads to more testable code:

import builtins

original_print = builtins.print

# Business logic
def add_monkey_to_message(msg: str) -> str:
    return f'🐵{msg}🐵'

def monkey_print(*args, **kwargs):
    message = add_monkey_to_message(' '.join(map(str, args)))
    original_print(message, **kwargs)

def apply_print_patch():
    builtins.print = monkey_print

apply_print_patch()
print('This is a monkey patching')  # 🐵This is a monkey patching🐵
Enter fullscreen mode Exit fullscreen mode

Use context

The patching should be specified in context and reverted when it is no longer used:

import builtins
from contextlib import contextmanager

# Business logic
def add_monkey_to_message(msg: str) -> str:
    return f'🐵{msg}🐵'

original_print = builtins.print

def apply_monkey_patch():
    def monkey_print(*args, **kwargs):
        message = add_monkey_to_message(' '.join(map(str, args)))
        original_print(message, **kwargs)
    builtins.print = monkey_print

@contextmanager
def monkey_context():
    apply_monkey_patch()
    try:
        yield
    finally:
        builtins.print = original_print

with monkey_context():
    print('This is inside monkey patching')  # 🐵This is inside monkey patching🐵
print('This is outside monkey patching')  # This is outside monkey patching
Enter fullscreen mode Exit fullscreen mode

Test it

If you're patching a component from an external library, you should test if this component exists before patching it, which is important before a version upgrade, ensuring the library will work:

import builtins
from contextlib import contextmanager

# Business logic
def add_monkey_to_message(msg: str) -> str:
    return f'🐵{msg}🐵'

class PrintPatchException(Exception):
    pass

original_print = builtins.print

def apply_monkey_patch():
    def monkey_print(*args, **kwargs):
        message = add_monkey_to_message(' '.join(map(str, args)))
        original_print(message, **kwargs)
    builtins.print = monkey_print

@contextmanager
def monkey_context():
    if not hasattr(builtins, 'print'):
        raise PrintPatchException()
    apply_monkey_patch()
    try:
        yield
    finally:
        builtins.print = original_print

with monkey_context():
    print('This is inside monkey patching')  # 🐵This is inside monkey patching🐵
print('This is outside monkey patching')  # This is outside monkey patching
Enter fullscreen mode Exit fullscreen mode

Conclusion

Monkey patching is an awesome tool, but it can be dangerous if you don't apply proper guardrails to ensure correct behavior of your override features. The key is being explicit about your overrides and thoroughly testing them. By following these golden rules, you can harness the power of monkey patching while keeping your code safe and maintainable.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more