Preprocessing Function Text In Runtime Bofore Compilation
Solution 1:
One can avoid creating a temporary file by invoking the exec
statement on the source. (You can also explicitly call compile
prior to exec
if you want additional control over compilation, but exec
will do the compilation for you, so it's not necessary.) Correctly calling exec
has the additional benefit that the function will work correctly if it accesses global variables from the namespace of its module.
The problem described in the second question can be resolved by temporarily blocking the decorator while it is running. That way the decorator remains, along all the other ones, but is a no-op.
Here is the updated source.
from __future__ import print_function
import sys
defa():
print('a()')
defcomment_1(s):
lines = s.split('\n')
return'\n'.join(line.replace(';','#;',1) if line.strip().startswith('1;') else line for line in lines)
_blocked = Falsedefremove_1(f):
global _blocked
if _blocked:
return f
import inspect
source = inspect.getsource(f)
new_source = comment_1(source)
env = sys.modules[f.__module__].__dict__
_blocked = Truetry:
exec new_source in env
finally:
_blocked = Falsereturn env[f.__name__]
@remove_1deff():
1;a()
print('Some statements 1')
1;a()
print('Some statements 2')
f()
defremove_1(f):
import inspect
source = inspect.getsource(f)
new_source = comment_1(source)
env = sys.modules[f.__module__].__dict__.copy()
exec new_source in env
return env[f.__name__]
Solution 2:
I'll leave a modified version of the solution given in the answer by user4815162342. It uses ast
module to delete some parts of f
, as was suggested in the comment to the question. To make it I majorly relied on the information in this article.
This implementation deletes all occurrences of a
as standalone expression.
from __future__ import print_function
import sys
import ast
import inspect
defa():
print('a() is called')
_blocked = Falsedefremove_1(f):
global _blocked
if _blocked:
return f
import inspect
source = inspect.getsource(f)
a = ast.parse(source) #get ast tree of fclassTransformer(ast.NodeTransformer):
'''Will delete all expressions containing 'a' functions at the top level'''defvisit_Expr(self, node): #visit all expressionstry:
if node.value.func.id == 'a': #if expression consists of function with name areturnNone#delete itexcept(ValueError):
passreturn node #return node unchanged
transformer = Transformer()
a_new = transformer.visit(a)
f_new_compiled = compile(a_new,'<string>','exec')
env = sys.modules[f.__module__].__dict__
_blocked = Truetry:
exec(f_new_compiled,env)
finally:
_blocked = Falsereturn env[f.__name__]
@remove_1deff():
a();a()
print('Some statements 1')
a()
print('Some statements 2')
f()
The output is:
Some statements 1Some statements 2
Post a Comment for "Preprocessing Function Text In Runtime Bofore Compilation"