| 25 | # Decorator that turns global names into locals |
| 26 | def lower_names(*namelist): |
| 27 | def lower(func): |
| 28 | srclines = inspect.getsource(func).splitlines() |
| 29 | # Skip source lines prior to the @lower_names decorator |
| 30 | for n, line in enumerate(srclines): |
| 31 | if '@lower_names' in line: |
| 32 | break |
| 33 | |
| 34 | src = '\n'.join(srclines[n+1:]) |
| 35 | # Hack to deal with indented code |
| 36 | if src.startswith((' ','\t')): |
| 37 | src = 'if 1:\n' + src |
| 38 | top = ast.parse(src, mode='exec') |
| 39 | |
| 40 | # Transform the AST |
| 41 | cl = NameLower(namelist) |
| 42 | cl.visit(top) |
| 43 | |
| 44 | # Execute the modified AST |
| 45 | temp = {} |
| 46 | exec(compile(top,'','exec'), temp, temp) |
| 47 | |
| 48 | # Pull out the modified code object |
| 49 | func.__code__ = temp[func.__name__].__code__ |
| 50 | return func |
| 51 | return lower |
| 52 | |
| 53 | # Example of use |