[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