from pypy.interpreter import error from pypy.interpreter import baseobjspace, module, main import sys import code import time class Completer: """ Stolen mostly from CPython's rlcompleter.py """ def __init__(self, space, w_globals): self.space = space self.w_globals = w_globals def complete(self, text, state): if state == 0: if "." in text: self.matches = self.attr_matches(text) else: self.matches = self.global_matches(text) try: return self.matches[state] except IndexError: return None def global_matches(self, text): import keyword w_res = self.space.call_method(self.w_globals, "keys") namespace_keys = self.space.unwrap(w_res) w_res = self.space.call_method(self.space.builtin.getdict(), "keys") builtin_keys = self.space.unwrap(w_res) matches = [] n = len(text) for l in [namespace_keys, builtin_keys, keyword.kwlist]: for word in l: if word[:n] == text and word != "__builtins__": matches.append(word) return matches def attr_matches(self, text): import re m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) if not m: return expr, attr = m.group(1, 3) s = self.space w_obj = s.eval(expr, self.w_globals, self.w_globals) words = self.get_words(w_obj) w_clz = s.getattr(w_obj, s.wrap("__class__")) words += self.get_class_members(w_clz) matches = [] n = len(attr) for word in words: if word[:n] == attr and word != "__builtins__": matches.append("%s.%s" % (expr, word)) return matches def get_words(self, w_clz): s = self.space w_dir_func = s.builtin.get("dir") w_res = s.call_function(w_dir_func, w_clz) return s.unwrap(w_res) def get_class_members(self, w_clz): s = self.space words = self.get_words(w_clz) try: w_bases = s.getattr(w_clz, s.wrap("__bases__")) bases_w = s.fixedview(w_bases) except error.OperationError: return words for w_clz in bases_w: words += self.get_class_members(w_clz) return words class PyPyConsole(code.InteractiveConsole): def __init__(self, objspace, verbose=0, completer=False): code.InteractiveConsole.__init__(self) self.space = objspace self.verbose = verbose space = self.space self.console_compiler_flags = 0 mainmodule = main.ensure__main__(space) self.w_globals = mainmodule.w_dict space.setitem(self.w_globals, space.wrap('__builtins__'), space.builtin) if completer: self.enable_command_line_completer() # forbidden: #space.exec_("__pytrace__ = 0", self.w_globals, self.w_globals) space.setitem(self.w_globals, space.wrap('__pytrace__'),space.wrap(0)) self.tracelevel = 0 self.console_locals = {} def enable_command_line_completer(self): try: import readline # Keep here to save windoze tears readline.set_completer(Completer(self.space, self.w_globals).complete) readline.parse_and_bind("tab: complete") readline.set_history_length(25000) try: readline.read_history_file() except IOError: pass # guess it doesn't exit import atexit atexit.register(readline.write_history_file) except: pass def interact(self, banner=None): #banner = "Python %s in pypy\n%s / %s" % ( # sys.version, self.__class__.__name__, # self.space.__class__.__name__) w_sys = self.space.sys major, minor, micro, _, _ = self.space.unwrap(self.space.sys.get('pypy_version_info')) elapsed = time.time() - self.space._starttime banner = "PyPy %d.%d.%d in %r on top of Python %s (startuptime: %.2f secs)" % ( major, minor, micro, self.space, sys.version.split()[0], elapsed) code.InteractiveConsole.interact(self, banner) def raw_input(self, prompt=""): # add a character to the PyPy prompt so that you know where you # are when you debug it with "python -i py.py" try: return code.InteractiveConsole.raw_input(self, prompt[0] + prompt) except KeyboardInterrupt: # fires into an interpreter-level console print banner = ("Python %s on %s\n" % (sys.version, sys.platform) + "*** Entering interpreter-level console ***") local = self.console_locals # don't copy attributes that look like names that came # from self.w_globals (itself the main offender) as they # would then get copied back into the applevel namespace. local.update(dict([(k,v) for (k, v) in self.__dict__.iteritems() if not k.startswith('w_')])) del local['locals'] for w_name in self.space.unpackiterable(self.w_globals): local['w_' + self.space.str_w(w_name)] = ( self.space.getitem(self.w_globals, w_name)) code.interact(banner=banner, local=local) # copy back 'w_' names for name in local: if name.startswith('w_'): self.space.setitem(self.w_globals, self.space.wrap(name[2:]), local[name]) print '*** Leaving interpreter-level console ***' raise def runcode(self, code): raise NotImplementedError def runsource(self, source, ignored_filename="", symbol="single"): # the following hacked file name is recognized specially by error.py hacked_filename = '\n' + source compiler = self.space.getexecutioncontext().compiler # CPython 2.6 turns console input into unicode if isinstance(source, unicode): source = source.encode(sys.stdin.encoding) def doit(): # compile the provided input code = compiler.compile_command(source, hacked_filename, symbol, self.console_compiler_flags) if code is None: raise IncompleteInput self.console_compiler_flags |= compiler.getcodeflags(code) # execute it self.settrace() try: code.exec_code(self.space, self.w_globals, self.w_globals) finally: if self.tracelevel: self.space.unsettrace() self.checktrace() # run doit() in an exception-catching box try: main.run_toplevel(self.space, doit, verbose=self.verbose) except IncompleteInput: return 1 else: return 0 def settrace(self): if self.tracelevel: self.space.settrace() def checktrace(self): from pypy.objspace import trace s = self.space # Did we modify __pytrace__ tracelevel = s.int_w(s.getitem(self.w_globals, s.wrap("__pytrace__"))) if self.tracelevel > 0 and tracelevel == 0: s.reset_trace() print "Tracing disabled" if self.tracelevel == 0 and tracelevel > 0: trace.create_trace_space(s) self.space.unsettrace() print "Tracing enabled" self.tracelevel = tracelevel class IncompleteInput(Exception): pass