Mocker's hidden gem...
Written by
on
in
Snaking.
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
Comments are closed.
Pingbacks
Pingbacks are closed.
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.)
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.
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?
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.
90 30 plc on 07/03/2010 10:18 a.m. #
They hold references to remove and install?
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.