Back to index

moin  1.9.0~rc2
console.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003     werkzeug.debug.console
00004     ~~~~~~~~~~~~~~~~~~~~~~
00005 
00006     Interactive console support.
00007 
00008     :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
00009     :license: BSD.
00010 """
00011 import sys
00012 import code
00013 from types import CodeType
00014 from werkzeug.utils import escape
00015 from werkzeug.local import Local
00016 from werkzeug.debug.repr import debug_repr, dump, helper
00017 from werkzeug.debug.utils import render_template
00018 
00019 
00020 _local = Local()
00021 
00022 
00023 class HTMLStringO(object):
00024     """A StringO version that HTML escapes on write."""
00025 
00026     def __init__(self):
00027         self._buffer = []
00028 
00029     def isatty(self):
00030         return False
00031 
00032     def close(self):
00033         pass
00034 
00035     def reset(self):
00036         val = ''.join(self._buffer)
00037         del self._buffer[:]
00038         return val
00039 
00040     def _write(self, x):
00041         if isinstance(x, str):
00042             x = x.decode('utf-8', 'replace')
00043         self._buffer.append(x)
00044 
00045     def write(self, x):
00046         self._write(escape(x))
00047 
00048     def writelines(self, x):
00049         self._write(escape(''.join(x)))
00050 
00051 
00052 class ThreadedStream(object):
00053     """Thread-local wrapper for sys.stdout for the interactive console."""
00054 
00055     def push():
00056         if sys.stdout is sys.__stdout__:
00057             sys.stdout = ThreadedStream()
00058         _local.stream = HTMLStringO()
00059     push = staticmethod(push)
00060 
00061     def fetch():
00062         try:
00063             stream = _local.stream
00064         except AttributeError:
00065             return ''
00066         return stream.reset()
00067     fetch = staticmethod(fetch)
00068 
00069     def displayhook(obj):
00070         try:
00071             stream = _local.stream
00072         except AttributeError:
00073             return _displayhook(obj)
00074         # stream._write bypasses escaping as debug_repr is
00075         # already generating HTML for us.
00076         if obj is not None:
00077             stream._write(debug_repr(obj))
00078     displayhook = staticmethod(displayhook)
00079 
00080     def __setattr__(self, name, value):
00081         raise AttributeError('read only attribute %s' % name)
00082 
00083     def __dir__(self):
00084         return dir(sys.__stdout__)
00085 
00086     def __getattribute__(self, name):
00087         if name == '__members__':
00088             return dir(sys.__stdout__)
00089         try:
00090             stream = _local.stream
00091         except AttributeError:
00092             stream = sys.__stdout__
00093         return getattr(stream, name)
00094 
00095     def __repr__(self):
00096         return repr(sys.__stdout__)
00097 
00098 
00099 # add the threaded stream as display hook
00100 _displayhook = sys.displayhook
00101 sys.displayhook = ThreadedStream.displayhook
00102 
00103 
00104 class _ConsoleLoader(object):
00105 
00106     def __init__(self):
00107         self._storage = {}
00108 
00109     def register(self, code, source):
00110         self._storage[id(code)] = source
00111         # register code objects of wrapped functions too.
00112         for var in code.co_consts:
00113             if isinstance(var, CodeType):
00114                 self._storage[id(var)] = source
00115 
00116     def get_source_by_code(self, code):
00117         try:
00118             return self._storage[id(code)]
00119         except KeyError:
00120             pass
00121 
00122 
00123 def _wrap_compiler(console):
00124     compile = console.compile
00125     def func(source, filename, symbol):
00126         code = compile(source, filename, symbol)
00127         console.loader.register(code, source)
00128         return code
00129     console.compile = func
00130 
00131 
00132 class _InteractiveConsole(code.InteractiveInterpreter):
00133 
00134     def __init__(self, globals, locals):
00135         code.InteractiveInterpreter.__init__(self, locals)
00136         self.globals = dict(globals)
00137         self.globals['dump'] = dump
00138         self.globals['help'] = helper
00139         self.globals['__loader__'] = self.loader = _ConsoleLoader()
00140         self.more = False
00141         self.buffer = []
00142         _wrap_compiler(self)
00143 
00144     def runsource(self, source):
00145         source = source.rstrip() + '\n'
00146         ThreadedStream.push()
00147         prompt = self.more and '... ' or '>>> '
00148         try:
00149             source_to_eval = ''.join(self.buffer + [source])
00150             if code.InteractiveInterpreter.runsource(self,
00151                source_to_eval, '<debugger>', 'single'):
00152                 self.more = True
00153                 self.buffer.append(source)
00154             else:
00155                 self.more = False
00156                 del self.buffer[:]
00157         finally:
00158             output = ThreadedStream.fetch()
00159         return prompt + source + output
00160 
00161     def runcode(self, code):
00162         try:
00163             exec code in self.globals, self.locals
00164         except:
00165             self.showtraceback()
00166 
00167     def showtraceback(self):
00168         from werkzeug.debug.tbtools import get_current_traceback
00169         tb = get_current_traceback(skip=1)
00170         sys.stdout._write(tb.render_summary())
00171 
00172     def showsyntaxerror(self, filename=None):
00173         from werkzeug.debug.tbtools import get_current_traceback
00174         tb = get_current_traceback(skip=4)
00175         sys.stdout._write(tb.render_summary())
00176 
00177     def write(self, data):
00178         sys.stdout.write(data)
00179 
00180 
00181 class Console(object):
00182     """An interactive console."""
00183 
00184     def __init__(self, globals=None, locals=None):
00185         if locals is None:
00186             locals = {}
00187         if globals is None:
00188             globals = {}
00189         self._ipy = _InteractiveConsole(globals, locals)
00190 
00191     def eval(self, code):
00192         return self._ipy.runsource(code)