2

I'm using the requests module, but the question is much more generic.

Is there a way to automatically execute code before calling methods from imported modules?

This would make writing code easier for me. At the moment I worry about hammering friendly webservices, so unless I can find an answer, I'll have to implement my own controls.


I thought by doing this:

import requests as requests2

...then at some point further on in the code, define a requests() function, with special arguments or some magical undiscovered syntax. After running its own code, the special sauce would forward method calls to the real module aliased to requests2.

Can this be done?

Jeremy
  • 1
  • 85
  • 340
  • 366
jon
  • 5,986
  • 5
  • 28
  • 35

2 Answers2

3

You have the right idea. Make a proxy for 'requests' that does whatever it wants to do then forwards the method call to the actual requests module. For example

class RequestProxy(object):
    def __init__(self):
        import requests as _requests
        self._requests = _requests

    def __getattribute__(self, attr):
        run_custom_code()
        return getattr(self._requests, attr)

requests = RequestProxy()
Katriel
  • 120,462
  • 19
  • 136
  • 170
  • One thing, you have `__getattribute__`, whereas Claudiu has `__getattr__`. I didn't mention a python version...apologies. – jon Aug 13 '12 at 22:56
  • @Jon it's not a Python version thing -- [they do different things](http://stackoverflow.com/questions/4295678/understanding-the-difference-between-getattr-and-getattribute) =) – Katriel Aug 13 '12 at 23:02
  • "RuntimeError: maximum recursion depth exceeded while calling a Python object" - I shamefully can't get this to work. py 2.6.6, requests v0.13.6 – jon Aug 14 '12 at 07:46
  • Oops, sorry, of course that would happen -- my bad! The problem is that `getattr` calls `__getattribute__`. You want Claudiu's `__getattr__`. – Katriel Aug 14 '12 at 15:29
3

You mean something like adding decorators to every function in another module? You could emulate that with a class:

class RequestsProxy(object):
    def __init__(self):
        self.special_sauce_decorator = special_sauce_indeed()
        self._requests = __import__("requests")

    def __getattr__(self, attrname):
        val = getattr(self._requests, attrname) 
        if callable(val):
            return self.special_sauce_decorator(val)
        return val

Example usage:

>>> def special_sauce_indeed():
        def decorator(f):
                def wrapped(*args, **kwargs):
                        print 'wrapped'
                        return f(*args, **kwargs)
                return wrapped
        return decorator

>>> class OsProxy(object):
        def __init__(self):
            self.special_sauce_decorator = special_sauce_indeed()
            self._requests = __import__("os")

        def __getattr__(self, attrname):
            val = getattr(self._requests, attrname)
            if callable(val):
                return self.special_sauce_decorator(val)
            return val


>>> os = OsProxy()
>>> os.listdir(".")
wrapped
['DLLs', 'Doc', 'faiojerf.py', 'func_counter_test.py', 'include', 'inet_time.py', 'kcol.py', 'Lib', 'libs', 'LICENSE.txt', 'memoize_test.py', 'minpy.py', 'NEWS.txt', 'numpy-wininst.log', 'paren_test.py', 'PIL-wininst.log', 'psycopg2-wininst.log', 'python.exe', 'pythonw.exe', 'pywin32-wininst.log', 'README.txt', 'Removenumpy.exe', 'RemovePIL.exe', 'Removepsycopg2.exe', 'Removepywin32.exe', 'Removescipy.exe', 'Removesetuptools.exe', 'scipy-wininst.log', 'Scripts', 'setuptools-wininst.log', 'slots.py', 'so1.py', 'staticvar.py', 'summing.py', 'taojiwjiot.,py', 'tcl', 'templol.py', 'test.py', 'thunkify_test.py', 'TicketNumberGenerator.py', 'Tools', 'w9xpopen.exe', 'wordcount.py']
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • Neato! I wouldn't do all of the exception checking -- 'getattr' will raise the default exception anyway (and arguably `special_sauce_decorator` should handle the case of non-callables). EAFP and all that =) – Katriel Aug 13 '12 at 23:01
  • 1
    European Association of Fish Pathologists? oh, [gotcha](http://docs.python.org/glossary.html#term-eafp). good point – Claudiu Aug 13 '12 at 23:16