[portland] Follow up to last night

jason kirtland jek at discorporate.us
Wed Apr 16 21:48:47 CEST 2008


Matt McCredie wrote:
> Hi all,
> 
>      Last night Jason gave a demo "Using inspect + exec to match
> function signatures". He mentioned that  the decorated function still
> didn't have the correct filename. I brought something up, I don't
> think anybody really followed what I was saying. Anyway, here is what
> I was getting at, and it seems to work.
> 
>     Seems to work. Feedback welcome.
> 
> Matt
> 
> [code]
> import codeop
> import inspect
> import warnings
> 
> def deprecated(fn):
>     """Decorate a function and issue a deprecation warning on execution."""
>     spec = inspect.getargspec(fn)
>     func_name = fn.func_name
>     argspec = inspect.formatargspec(*spec)
>     callspec = inspect.formatargspec(*spec[:3])
> 
>     # adding newlines seems to be the easiest way to get the line number to
>     # report correctly.
> 
>     text = "\n"*fn.func_code.co_firstlineno + """\
> def %(func_name)s%(argspec)s:
>     warnings.warn(DeprecationWarning('%(func_name)s'))
>     return fn%(callspec)s
> """
>     text %= locals()
> 
>     # compile it with the appropriate file name
>     code = codeop.compile_command(text, fn.func_code.co_filename, "exec")
> 
>     env = locals().copy()
>     env['warnings'] = warnings
> 
>     # just exec the code object instead of the string
>     exec code in env
>     env[func_name].func_doc = fn.func_doc
>     return env[func_name]
> [/code]

Nice.  The last step would be to get 'inspect.getsourcelines' to return 
the source of the generated decorator, rather than the decoratee:

def a():
     print 'a!'

print inspect.getsourcelines(a)
source = inspect.getsourcelines(a)[0]

@deprecated
def a():
     print 'a!'

print inspect.getsourcelines(a)
assert source != inspect.getsourcelines(a)[0]

(...and preferably without monkeypatching in the stdlib. ;)



More information about the Portland mailing list