def defer_demo(): def lazy(frame, obj): obj.load() return obj class Lazily: def load(self): self.value = 10 x = Lazily() setrwatch({id(x): lazy}) print(x.value) def promise(frame, obj): return obj.value class Promise: @property def value(self): return 10 x = Promise() setrwatch({id(x): promise}) print(x)
def debug_demo(x='some data'): from inspect import getframeinfo def view(frame, obj): info = getframeinfo(frame) msg = 'Access to {!r} (@{}) at {}:{}:{}' print(msg.format(obj, hex(id(obj)), info.filename, info.lineno, info.function)) return obj setrwatch({id(x): view}) print(getrwatch()) def f(x): x # ← here f(x) # ← here def f(x): def g(): x # ← here return g f(x)() # ← here class Foo: def __init__(self, x): self.x = x # ← here def __call__(self): return self.x # ← here @property def value(self): return self.x # ← here foo = Foo(x) # ← here foo() foo.value x = 10 # not here (rebind, no push)
def sandbox_demo(x='some data'): def forbid(frame, obj): raise SystemError("can't touch this") setrwatch({id(x): forbid}) try: # x pass except: pass
def indirection_demo(): def pointer(frame, obj): return obj() def make_pointer(x): cell = [x] pointer = lambda: cell[0] def repoint(x): cell[0] = x return pointer, repoint y, z = 1234, 4567 x, x_ = make_pointer(y) setrwatch({id(x): pointer}) print(x) x_(z) print(x)
def debug_demo(x='some data'): from inspect import getframeinfo def view(frame, obj): info = getframeinfo(frame) msg = 'Access to {!r} (@{}) at {}:{}:{}' print( msg.format(obj, hex(id(obj)), info.filename, info.lineno, info.function)) return obj setrwatch({id(x): view}) print(getrwatch()) def f(x): x # ← here f(x) # ← here def f(x): def g(): x # ← here return g f(x)() # ← here class Foo: def __init__(self, x): self.x = x # ← here def __call__(self): return self.x # ← here @property def value(self): return self.x # ← here foo = Foo(x) # ← here foo() foo.value x = 10 # not here (rebind, no push)
def mutable_demo(x='some data', y='other data'): def view(frame, obj): print('Saw access to {!r}'.format(obj)) return obj watches = {id(x): view} setrwatch(watches) x watches[id(y)] = view y class Predicate(dict): def dispatch(self, frame, obj): for pred, func in self.items(): if pred(obj): func(frame, obj) def __getitem__(self, _): return self.dispatch from collections.abc import Sized watches = Predicate({lambda o: isinstance(o, Sized) and len(o) > 9: view}) setrwatch(watches) x, y
def f(): x = object() setrwatch({id(x): view}) print({hex(k): v for k, v in (getrwatch() or {}).items()}) print('x =', x)
def f(): x = object() setrwatch({id(x): view}) print({hex(k): v for k,v in (getrwatch() or {}).items()}) print('x =', x)
def __exit__(self, exc_type, exc_val, exc_tb): setrwatch({})
def __enter__(self): setrwatch(defaultdict(lambda: self.rwatch))
def __enter__(self): setrwatch(defaultdict(lambda: add_white_noise_to_complex))
def __enter__(self): setrwatch(defaultdict(lambda: debug_view_for_any_object))
# In[5]: get_ipython().run_cell_magic('bash', '', 'tmpdir=$(mktemp -d)\ncd $tmpdir\ngit clone https://github.com/dutc/rwatch\ncd rwatch/src/\nmake\nls -larth ./rwatch.so\nfile ./rwatch.so\n# cp ./rwatch.so /where/ver/you/need/ # ~/publis/notebook/ for me') # Anyhow, if `rwatch` is installed, we can import it, and it enables two new functions in the `sys` module: # In[6]: import rwatch from sys import setrwatch, getrwatch setrwatch({}) # clean any previously installed rwatch getrwatch() # Finally, we need the [`collections`](https://docs.python.org/3/library/collections.html) module and its [`defaultdict`](https://docs.python.org/3/library/collections.html#collections.defaultdict) magical datastructure. # In[7]: from collections import defaultdict # ---- # ## Defining a debugging context manager, just to try # # This is the first example given in [James presentation]() at PyCon Canada 2016.