Mocker's hidden gem...

Mocker has one uber-nice feature... it will mock out an object in basically all namespaces, so you can do a .proxy( 'mymodule.this.that' ) and have the resulting mock object replace the target "that" wherever it's been imported.  It won't, for instance, pick up references in lists, sets and the like, but for basic namespaces (dictionaries) it works really nicely. The cool thing is, the code to do the replacing is *tiny*:

def global_replace(remove, install):
    """Replace object 'remove' with object 'install' on all dictionaries."""
    for referrer in gc.get_referrers(remove):
        if (type(referrer) is dict and
            referrer.get("__mocker_replace__", True)):
            for key, value in list(referrer.iteritems()):
                if value is remove:
                    referrer[key] = install

That's just so neat as an approach I felt people should see it.

Comments

  1. Michael Foord

    Michael Foord on 06/24/2010 5:03 a.m. #

    That's even more evil than the mock patch decorator... :-) (patch only replaces names in scopes - so it patches out objects where they are *used* rather than finding referrers.)

  2. Mike C. Fletcher

    Mike C. Fletcher on 06/24/2010 7:22 a.m. #

    That's the "magic" that made me go "ooh shiny" :) . It's a neat little hack to make a nice feature possible.

    In building a few mock-like mechanisms I've always done the patch-where-used approach, but I always missed that "just replace it anywhere and clean up later" functionality. Particularly in code-bases where lots of functions are imported individually into other namespaces it can save a lot of work for stubbing-out dangerous functionality.

  3. Virgil Dupras

    Virgil Dupras on 06/24/2010 7:23 a.m. #

    I haven't tried it, but it seems to me like this approach has one fundamental problem: If you replace *all* refs of 'remove' with 'install', wouldn't it also remove instances Mocker holds to 'remove' and prevent any unpatching during the cleanup phase?

    How does Mocker get around this?

  4. Mike C. Fletcher

    Mike C. Fletcher on 06/24/2010 7:34 a.m. #

    There's higher-level objects which are tracking what is replaced (the actual Mock objects). They hold references to remove and install.

  5. 90 30 plc

    90 30 plc on 07/03/2010 10:18 a.m. #

    They hold references to remove and install?

  6. Mike C. Fletcher

    Mike C. Fletcher on 07/03/2010 8:32 p.m. #

    Yes, only references in *dictionaries* are replaced, so holding references in lists, tuples, etceteras keeps them alive.

Comments are closed.

Pingbacks

Pingbacks are closed.