import inspect
import six
from .namespace import Namespace
from .container_namespace import ContainerNamespace
from .python_object_namespace import PythonObjectNamespace
from rook.exceptions import RookAttributeNotFound, RookInvalidMethodArguments
# Fixing a bug in PyPy
import platform
if 'PyPy' == platform.python_implementation():
import sys
FakeFrameType = type(next(six.itervalues(sys._current_frames())))
from types import FrameType
def isframe(object):
return isinstance(object, (FrameType, FakeFrameType))
inspect.isframe = isframe
class FrameNamespace(Namespace):
def __init__(self, frame, lineno=None):
"""
:param lineno: Lineno with which to override the lineno fetched from the frame.
"""
super(FrameNamespace, self).__init__(self.METHODS)
self.frame = frame
if lineno is None:
self._lineno = inspect.getlineno(frame)
else:
self._lineno = lineno
self._function = self.frame.f_code.co_name
def read_attribute(self, name):
if name in self.frame.f_locals:
return PythonObjectNamespace(self.frame.f_locals[name])
elif name in self.frame.f_globals:
return PythonObjectNamespace(self.frame.f_globals[name])
else:
raise RookAttributeNotFound(name)
@property
def _filename(self):
return inspect.getsourcefile(self.frame) or inspect.getfile(self.frame)
def filename(self, args=None):
return PythonObjectNamespace(self._filename)
def line(self, args=None):
return PythonObjectNamespace(self._lineno)
def function(self, args=None):
return PythonObjectNamespace(self._function)
def module(self, args=None):
module = inspect.getmodule(self.frame)
if module:
return PythonObjectNamespace(module.__name__)
else:
return PythonObjectNamespace(None)
def locals(self, args=None):
depth = None
dump_config = None
if args:
try:
depth = int(args)
except ValueError:
if isinstance(args, six.string_types):
try:
dump_config = PythonObjectNamespace.dump_configs[args.lower()]
except KeyError:
raise RookInvalidMethodArguments('locals()', args)
else:
raise RookInvalidMethodArguments('locals()', args)
result = {}
for name, value in six.iteritems(self.frame.f_locals):
ns = PythonObjectNamespace(value)
if depth is not None:
ns.dump_config.max_depth = depth
elif dump_config is not None:
ns.dump_config = dump_config
result[name] = ns
return ContainerNamespace(result)
def globals(self, args):
return PythonObjectNamespace(self.frame.f_globals)
def dump(self, args):
return ContainerNamespace({
'locals': self.locals(args),
'module': self.module(),
'filename': self.filename(),
'line': self.line(),
'function': self.function(),
})
def f_back(self):
frame = self.frame.f_back
if frame:
return FrameNamespace(self.frame.f_back)
else:
return PythonObjectNamespace(None)
def f_next(self):
frame = self.frame.f_next
if frame:
return FrameNamespace(self.frame.f_next)
else:
return PythonObjectNamespace(None)
METHODS = (filename, line, function, module, locals, globals, dump)