Finding Functions Defined in a with: Block
contextmanager, python, scope, with-statement
Solution
Here's one way:
from __future__ import with_statement
import inspect
class button(object):
def __enter__(self):
# keep track of all that's already defined BEFORE the `with`
f = inspect.currentframe(1)
self.mustignore = dict(f.f_locals)
def __exit__(self, exc_type, exc_value, traceback):
f = inspect.currentframe(1)
# see what's been bound anew in the body of the `with`
interesting = dict()
for n in f.f_locals:
newf = f.f_locals[n]
if n not in self.mustignore:
interesting[n] = newf
continue
anf = self.mustignore[n]
if id(newf) != id(anf):
interesting[n] = newf
if interesting:
print 'interesting new things: %s' % ', '.join(sorted(interesting))
for n, v in interesting.items():
if isinstance(v, type(lambda:None)):
print 'function %r' % n
print v()
else:
print 'nothing interesting'
def main():
for i in (1, 2):
def ignorebefore():
pass
with button():
def testing(i=i):
return i
def ignoreafter():
pass
main()
Edit: stretched code a bit more, added some explanation...:
Catching caller's locals at `__exit__` is easy -- trickier is avoiding those locals that were already defined before the `with` block, which is why I added to main two local functions that the `with` should ignore. I'm not 100% happy with this solution, which looks a bit complicated, but I couldn't get equality testing correct with either `==` or `is`, so I resorted to this rather complicated approach.
I've also added a loop (to make more strongly sure the `def`s before / within / after are being properly handled) and a type-check and function-call to make sure the right incarnation of `testing` is the one that's identified (everything seems to work fine) -- of course the code as written only works if the `def` inside the `with` is for a function callable without arguments, it's not hard to get the signature with `inspect` to ward against that (but since I'm doing the call only for the purpose of checking that the right function objects are identified, I didn't bother about this last refinement;-).
Problem
Here's some code from Richard Jones' Blog: ``` with gui.vertical: text = gui.label('hello!') items = gui.selection(['one', 'two', 'three']) with gui.button('click me!'): def on_click(): text.value = items.value text.foreground = red ``` My question is: how the heck did he do this? How can the context manager access the scope inside the with block? Here's a basic template for trying to figure this out: ``` from __future__ import with_statement class button(object): def __enter__(self): #do some setup pass def __exit__(self, exc_type, exc_value, traceback): #XXX: how can we find the testing() function? pass with button(): def testing(): pass ```