Created
May 7, 2021 14:47
-
-
Save kezabelle/caf342ffd8a05570583985849985bf47 to your computer and use it in GitHub Desktop.
lets play at tracking calls and the locals at the point of return ...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import threading | |
from operator import itemgetter | |
from pprint import pprint, saferepr | |
keyonly = itemgetter(0) | |
class ZMixin: | |
def mixin_via_z(self) -> int: | |
varz = 999 | |
return varz | |
def goes_through_everything(self) -> None: | |
varz = 'whee' | |
return None | |
class YMixin: | |
def mixin_via_y(self) -> int: | |
vary = 998 | |
return vary | |
def goes_through_everything(self) -> None: | |
vary = super().goes_through_everything() | |
return vary | |
class XMixin: | |
def mixin_via_x(self) -> int: | |
varx = 997 | |
return varx | |
def goes_through_everything(self) -> None: | |
varx = super().goes_through_everything() | |
return varx | |
class A(ZMixin): | |
def __init__(self): | |
test = 'in a' | |
super().__init__() | |
def test_c_to_a(self) -> int: | |
return 1 | |
def test_b_to_a_via_c(self) -> int: | |
return 3 | |
def test_c_to_a_through_b(self) -> int: | |
return 4 | |
def goes_through_everything(self) -> None: | |
vara = super().goes_through_everything() | |
return vara | |
class B(YMixin, A): | |
def __init__(self): | |
test = 'in b' | |
super().__init__() | |
def test_c_to_b(self) -> int: | |
return 2 | |
def test_b_to_a_via_c(self) -> int: | |
return super().test_b_to_a_via_c() | |
def test_c_to_a_through_b(self) -> int: | |
return super().test_c_to_a_through_b() | |
def goes_through_everything(self) -> None: | |
varb = super().goes_through_everything() | |
return varb | |
class C(XMixin, B): | |
def __init__(self): | |
test = 'in c' | |
super().__init__() | |
def test_c_to_a(self) -> int: | |
return super().test_c_to_a() | |
def test_c_to_b(self) -> int: | |
return super().test_c_to_b() | |
def test_c_to_a_through_b(self) -> int: | |
return super().test_c_to_a_through_b() | |
def goes_through_everything(self) -> None: | |
varc = super().goes_through_everything() | |
return varc | |
localvars = threading.local() | |
# In case you're a doofus like I am, it's worth pointing out that printing or | |
# pprinting a dictionary doesn't necessarily output it in the same insertion | |
# order it is, which caused me to scratch my head a bunch and debug a problem | |
# that doesn't exist if you just iterate over .items() | |
localvars.seen = {} | |
def tracefunc(frame, event, arg): | |
def update_seen(_theframe_): | |
name = _theframe_.f_code.co_name | |
vars = _theframe_.f_locals | |
if 'self' in vars: | |
self = vars['self'] | |
ancestors = self.__class__.__mro__ | |
template = "%s.%s.%s" | |
if '__class__' in vars: | |
currentcls = vars['__class__'] | |
return template % (currentcls.__module__, currentcls.__qualname__, name) | |
else: | |
for currentcls in reversed(ancestors): | |
if hasattr(currentcls, name): | |
return template % (currentcls.__module__, currentcls.__qualname__, name) | |
return "" | |
if event == 'call': | |
currentcls = update_seen(frame) | |
localvars.seen[currentcls] = 1 | |
if event == "return": | |
currentcls = update_seen(frame) | |
local_reprs = { | |
lname: saferepr(lval) | |
for lname, lval in sorted(frame.f_locals.items(), key=keyonly) | |
if lname != "self" and lname[0:2] != "__" | |
} | |
localvars.seen[currentcls] = local_reprs | |
sys.setprofile(tracefunc) | |
thing = C() | |
thing.mixin_via_z() | |
thing.mixin_via_y() | |
thing.mixin_via_x() | |
thing.test_c_to_a() | |
thing.test_c_to_b() | |
thing.test_b_to_a_via_c() | |
thing.test_c_to_a_through_b() | |
thing.goes_through_everything() | |
sys.setprofile(None) | |
for k, v in localvars.seen.items(): | |
pprint(k) | |
pprint(v) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment