Skip to main content

before_after

before_after provides utilities to help test race conditions.

When testing Python programs that run in multiple threads or processes it’s useful to simulate race conditions to ensure you handle them properly. before_after provides two functions, before and after, that allow you to insert pre or post functions to be called before/after a function you want to test.

See this blog post for a practical example of using before_after in tests.

Patching

before_after is sugar over the Mock library. It’s recommended that you read the docs before using before_after, especially Where to patch.

Example usage

Practical example of testing race conditions

def before_fn(*a, **k):
    print 'before_fn called with', a, k

def after_fn(*a, **k):
    print 'after_fn called with', a, k

def hello(name, greeting='Hello'):
    print '{greeting} {name}!'.format(
        greeting=greeting, name=name)

with before_after.before('__main__.hello', before_fn):
    hello('World')

# before_fn called with ('World',) {}
# Hello World!

with before_after.after('__main__.hello', after_fn):
    hello('everybody', greeting='Hi there')

# Hi there everybody!
# after_fn called with ('everybody',) {'greeting': 'Hi there'}

Use with recursive functions

By default, before_after only calls the before_fn/after_fn function once. This is useful if you’re calling the original function within the before_fn/after_fn, since otherwise you’ll blow the stack. This behaviour can be disabled by passing once=False.

my_list = []

def before_fn(*a, **k):
    print 'calling my_append in before_fn'
    my_append(1)

def my_append(item):
    print 'appending', item, 'to my_list'
    my_list.append(item)
    print 'my_list is now', my_list

with before_after.before('__main__.my_append', before_fn):
    my_append(2)

# calling my_append in before_fn
# appending 1 to my_list
# my_list is now [1]
# appending 2 to my_list
# my_list is now [1, 2]

with before_after.before('__main__.my_append', before_fn, once=False):
    my_append(2)

# calling my_append in before_fn
# calling my_append in before_fn
# calling my_append in before_fn
# ...
# RuntimeError: maximum recursion depth exceeded while calling a Python object

It’s recommended that if you’re passing once=False that you make sure your program will exit cleanly!

Use with methods

Since v1.0.0 before_after can be used on function methods. Make sure your before_fn/after_fn accepts a self argument.

class Greeter(object):
    def __init__(self):
        self.greeted = []

    def greet(self, name):
        print 'Hi there', name
        self.greeted.append(name)
        print 'This is now a party of', len(self.greeted)

def after_fn(self, name):
    self.greet("{name}'s guest".format(name=name))

greeter = Greeter()

with before_after.after('__main__.Greeter.greet', after_fn):
    greeter.greet('Alice')

# Hi there Alice
# This is now a party of 1
# Hi there Alice's guest
# This is now a party of 2

Metadata

Release files for before_after 1.0.1

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

Source distribution (sdist)

Source distribution for before_after 1.0.1
File Size Uploaded
before_after-1.0.1.tar.gz 4.0 kB Details

Release files / before_after-1.0.1.tar.gz

Download URL before_after-1.0.1.tar.gz
Size 4.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c7d4f9b8b8bb52095da14c4b9c59ea6b3f5b9ea9fdce8a7bfc72ecae0f5a3f85
BLAKE2b-256 checksum
How to use checksums
9a72d530e57aef0de092dc7ce626f52812f38dd65a4bfeafd6216fb868b15119
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

1.0.1 This release

1 release file

1.0.0

1 release file

0.1.3

1 release file

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