Globalsub: Replace objects Globally

Globalsub is a tool for use in testing. It allows you to scan all namespaces in the Python interpreter to find references to a given object and replace those references with references to another object. It then allows you to return the references back to the original object when you are finished.

Interactive Usage:

>>> import globalsub
>>> def x():
...     print 'x'
...
>>> def y():
...     print 'y'
...
>>> globalsub.subs( x, y )
<function y at 0xb7470a04>
>>> x()
y
>>> y()
y
>>> globalsub.restore( x )
<function x at 0xb74709cc>
>>> x()
x
>>> y()
y

Test Case Usage:

import globalsub
import somemodule
import settings
class MyTests( unittest.TestCase ):
    def setUp( self ):
        # stub out the function so that it is never run during this
        # test suite...
        # default subs is a function that takes *args, **named and returns None
        globalsub.subs( somemodule.should_never_run )
    def tearDown( self ):

        # we always subs'd this, we always restore it
        globalsub.restore( somemodule.should_never_run )

        # we *may* have subs'd these, restoring them doesn't hurt us...
        globalsub.restore( somemodule.whatever )
        globalsub.restore( settings.PATH_TO_EXECUTABLE )

    def test_something_specific( self ):
        def fake_whatever( *args, **named ):
            return ['this']
        globalsub.subs( somemodule.whatever, fake_whatever )

    def test_with_a_mockproc( self ):
        globalsub.subs( settings.PATH_TO_EXECUTABLE, 'fake-executable' )

Referencing the Original Object:

holder = [ original_function ]
def fake_function( *args, **named ):
    result = holder[0]( *args, **named )
    return result.replace( 'a', 'b' )
globalsub.subs( original_function, fake_function )

How it Works

globalsub.subs() uses the gc module to find all references to a given object. It tracks each object which is holding a reference to the replacement, along with the original object (in a list internally), then replaces all (dictionary) references to the object with the replacement object (using the globalsub.global_replace() function).

globalsub.restore() uses the substituted object’s metadata to do the inverse replacement, using the filter-set of references which were to the replacement object (rather than the original) to avoid unintentionally replacing the replacement with the original.

Installation

Standard Python library installation from PyPI:

$> source my-virtual-env/bin/activate
$> pip install globalsub

To help contribute/develop globalsub, install bzr and then use the following command:

$> pip install -e bzr+http://bazaar.launchpad.net/~mcfletch/globalsub/trunk#egg=globalsub

Which will install globalsub into your VirtualEnv’s src directory in an editable format. The LaunchPad Project can be used to report bugs, or you can contact the author directly.

Limitations

The implementation has the following major limitations:

  • will only replace references in dictionaries (not lists, not tuples)
  • replaces all references, so if you replace the digit 1, every reference to the shared small integer object will be replaced with your replacement object
  • can only handle a couple of built-in types (str/unicode being the useful ones, normally)
  • you must call restore on the substituted object, not the original object, so if you store references to objects in lists “subs all these” you are going to have to store the result of the subs calls to do the restoration
  • you cannot use the same object twice as the substituted object, as only the last item replaced can be restored

Contents:

Indices and tables

Table Of Contents

Next topic

Globalsub

This Page