Add automatic exploded_variables

This commit is contained in:
Alex Hall 2019-04-28 21:48:33 +02:00 committed by Ram Rachum
parent fb62a57a52
commit 97dc802ee6
3 changed files with 37 additions and 8 deletions

View file

@ -39,7 +39,7 @@ def get_write_and_truncate_functions(output):
return (write, truncate)
def snoop(output=None, variables=(), depth=1, prefix='', overwrite=False):
def snoop(output=None, variables=(), exploded_variables=(), depth=1, prefix='', overwrite=False):
'''
Snoop on the function, writing everything it's doing to stderr.
@ -75,7 +75,8 @@ def snoop(output=None, variables=(), depth=1, prefix='', overwrite=False):
target_code_object = function.__code__
tracer = Tracer(target_code_object=target_code_object, write=write,
truncate=truncate, variables=variables, depth=depth,
prefix=prefix, overwrite=overwrite)
prefix=prefix, overwrite=overwrite,
exploded_variables=exploded_variables)
def inner(function_, *args, **kwargs):
with tracer:

View file

@ -7,7 +7,7 @@ import collections
import datetime as datetime_module
import itertools
from .variables import Variable
from .variables import CommonVariable, Exploded, BaseVariable
from .third_party import six
from .utils import get_shortish_repr, ensure_tuple
@ -99,13 +99,16 @@ def get_source_from_frame(frame):
class Tracer:
def __init__(self, target_code_object, write, truncate, variables=(),
depth=1, prefix='', overwrite=False):
exploded_variables=(), depth=1, prefix='', overwrite=False):
self.target_code_object = target_code_object
self._write = write
self.truncate = truncate
self.variables = [
v if isinstance(v, Variable) else Variable(v)
v if isinstance(v, BaseVariable) else CommonVariable(v)
for v in ensure_tuple(variables)
] + [
v if isinstance(v, BaseVariable) else Exploded(v)
for v in ensure_tuple(exploded_variables)
]
self.frame_to_old_local_reprs = collections.defaultdict(lambda: {})
self.frame_to_local_reprs = collections.defaultdict(lambda: {})

View file

@ -4,7 +4,7 @@ from copy import deepcopy
from .utils import get_shortish_repr, ensure_tuple
class Variable(object):
class BaseVariable(object):
def __init__(self, source, exclude=()):
self.source = source
self.exclude = ensure_tuple(exclude)
@ -15,6 +15,14 @@ class Variable(object):
main_value = eval(self.code, frame.f_globals, frame.f_locals)
except Exception:
return ()
return self._items(main_value)
def _items(self, key):
raise NotImplementedError()
class CommonVariable(BaseVariable):
def _items(self, main_value):
result = [(self.source, get_shortish_repr(main_value))]
for key in self._safe_keys(main_value):
if key in self.exclude:
@ -46,7 +54,7 @@ class Variable(object):
raise NotImplementedError()
class Attrs(Variable):
class Attrs(CommonVariable):
def _keys(self, main_value):
return itertools.chain(
getattr(main_value, '__dict__', ()),
@ -60,7 +68,7 @@ class Attrs(Variable):
return getattr(main_value, key)
class Keys(Variable):
class Keys(CommonVariable):
def _keys(self, main_value):
return main_value.keys()
@ -82,3 +90,20 @@ class Indices(Keys):
result = deepcopy(self)
result._slice = item
return result
class Exploded(BaseVariable):
def _items(self, main_value):
typ = main_value.__class__
def has_method(name):
return callable(getattr(typ, name, None))
cls = Attrs
if has_method('__getitem__'):
if has_method('keys'):
cls = Keys
elif has_method('__len__'):
cls = Indices
return cls(self.source, self.exclude)._items(main_value)