Innovenergy_trunk/firmware/opt/innovenergy/python_libs/pysnooper/variables.py

134 lines
3.0 KiB
Python

import itertools
import abc
try:
from collections.abc import Mapping, Sequence
except ImportError:
from collections import Mapping, Sequence
from copy import deepcopy
from . import utils
from . import pycompat
def needs_parentheses(source):
def code(s):
return compile(s, '<variable>', 'eval').co_code
return code('{}.x'.format(source)) != code('({}).x'.format(source))
class BaseVariable(pycompat.ABC):
def __init__(self, source, exclude=()):
self.source = source
self.exclude = utils.ensure_tuple(exclude)
self.code = compile(source, '<variable>', 'eval')
if needs_parentheses(source):
self.unambiguous_source = '({})'.format(source)
else:
self.unambiguous_source = source
def items(self, frame, normalize=False):
try:
main_value = eval(self.code, frame.f_globals or {}, frame.f_locals)
except Exception:
return ()
return self._items(main_value, normalize)
@abc.abstractmethod
def _items(self, key, normalize=False):
raise NotImplementedError
@property
def _fingerprint(self):
return (type(self), self.source, self.exclude)
def __hash__(self):
return hash(self._fingerprint)
def __eq__(self, other):
return (isinstance(other, BaseVariable) and
self._fingerprint == other._fingerprint)
class CommonVariable(BaseVariable):
def _items(self, main_value, normalize=False):
result = [(self.source, utils.get_shortish_repr(main_value, normalize=normalize))]
for key in self._safe_keys(main_value):
try:
if key in self.exclude:
continue
value = self._get_value(main_value, key)
except Exception:
continue
result.append((
'{}{}'.format(self.unambiguous_source, self._format_key(key)),
utils.get_shortish_repr(value)
))
return result
def _safe_keys(self, main_value):
try:
for key in self._keys(main_value):
yield key
except Exception:
pass
def _keys(self, main_value):
return ()
def _format_key(self, key):
raise NotImplementedError
def _get_value(self, main_value, key):
raise NotImplementedError
class Attrs(CommonVariable):
def _keys(self, main_value):
return itertools.chain(
getattr(main_value, '__dict__', ()),
getattr(main_value, '__slots__', ())
)
def _format_key(self, key):
return '.' + key
def _get_value(self, main_value, key):
return getattr(main_value, key)
class Keys(CommonVariable):
def _keys(self, main_value):
return main_value.keys()
def _format_key(self, key):
return '[{}]'.format(utils.get_shortish_repr(key))
def _get_value(self, main_value, key):
return main_value[key]
class Indices(Keys):
_slice = slice(None)
def _keys(self, main_value):
return range(len(main_value))[self._slice]
def __getitem__(self, item):
assert isinstance(item, slice)
result = deepcopy(self)
result._slice = item
return result
class Exploding(BaseVariable):
def _items(self, main_value, normalize=False):
if isinstance(main_value, Mapping):
cls = Keys
elif isinstance(main_value, Sequence):
cls = Indices
else:
cls = Attrs
return cls(self.source, self.exclude)._items(main_value, normalize)