diff --git a/src/calibre/debug.py b/src/calibre/debug.py index 9ad0f2d8b7..2b47f4700f 100644 --- a/src/calibre/debug.py +++ b/src/calibre/debug.py @@ -53,8 +53,6 @@ Everything after the -- is passed to the script. parser.add_option('--reinitialize-db', default=None, help=_('Re-initialize the sqlite calibre database at the ' 'specified path. Useful to recover from db corruption.')) - parser.add_option('-p', '--py-console', help=_('Run python console'), - default=False, action='store_true') parser.add_option('-m', '--inspect-mobi', action='store_true', default=False, help=_('Inspect the MOBI file(s) at the specified path(s)')) @@ -230,9 +228,6 @@ def main(args=sys.argv): elif opts.viewer: from calibre.gui_launch import ebook_viewer ebook_viewer(['ebook-viewer', '--debug-javascript'] + args[1:]) - elif opts.py_console: - from calibre.utils.pyconsole.main import main - main() elif opts.command: sys.argv = args exec(opts.command) diff --git a/src/calibre/utils/pyconsole/__init__.py b/src/calibre/utils/pyconsole/__init__.py deleted file mode 100644 index 5460a01691..0000000000 --- a/src/calibre/utils/pyconsole/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -import sys, os - -from calibre import prints as prints_, preferred_encoding, isbytestring -from calibre.utils.config import Config, ConfigProxy, JSONConfig -from calibre.utils.ipc.launch import Worker -from calibre.constants import __appname__, __version__, iswindows -from calibre.gui2 import error_dialog - -# Time to wait for communication to/from the interpreter process -POLL_TIMEOUT = 0.01 # seconds - -preferred_encoding, isbytestring, __appname__, __version__, error_dialog, \ -iswindows - -def console_config(): - desc='Settings to control the calibre console' - c = Config('console', desc) - - c.add_opt('theme', default='native', help='The color theme') - c.add_opt('scrollback', default=10000, - help='Max number of lines to keep in the scrollback buffer') - - return c - -prefs = ConfigProxy(console_config()) -dynamic = JSONConfig('console') - -def prints(*args, **kwargs): - kwargs['file'] = sys.__stdout__ - prints_(*args, **kwargs) - -class Process(Worker): - - @property - def env(self): - env = dict(os.environ) - env.update(self._env) - return env - - diff --git a/src/calibre/utils/pyconsole/console.py b/src/calibre/utils/pyconsole/console.py deleted file mode 100644 index e077c2c65c..0000000000 --- a/src/calibre/utils/pyconsole/console.py +++ /dev/null @@ -1,521 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -import sys, textwrap, traceback, StringIO -from functools import partial -from codeop import CommandCompiler - -from PyQt5.Qt import QTextEdit, Qt, QTextFrameFormat, pyqtSignal, \ - QApplication, QColor, QPalette, QMenu, QActionGroup, QTimer - -from pygments.lexers import PythonLexer, PythonTracebackLexer -from pygments.styles import get_all_styles - -from calibre.utils.pyconsole.formatter import Formatter -from calibre.utils.pyconsole.controller import Controller -from calibre.utils.pyconsole.history import History -from calibre.utils.pyconsole import prints, prefs, __appname__, \ - __version__, error_dialog, dynamic - -class EditBlock(object): # {{{ - - def __init__(self, cursor): - self.cursor = cursor - - def __enter__(self): - self.cursor.beginEditBlock() - return self.cursor - - def __exit__(self, *args): - self.cursor.endEditBlock() -# }}} - -class Prepender(object): # {{{ - 'Helper class to insert output before the current prompt' - def __init__(self, console): - self.console = console - - def __enter__(self): - c = self.console - self.opos = c.cursor_pos - cur = c.prompt_frame.firstCursorPosition() - cur.movePosition(cur.PreviousCharacter) - c.setTextCursor(cur) - - def __exit__(self, *args): - self.console.cursor_pos = self.opos -# }}} - -class ThemeMenu(QMenu): # {{{ - - def __init__(self, parent): - QMenu.__init__(self, _('Choose theme (needs restart)')) - parent.addMenu(self) - self.group = QActionGroup(self) - current = prefs['theme'] - alls = list(sorted(get_all_styles())) - if current not in alls: - current = prefs['theme'] = 'default' - self.actions = [] - for style in alls: - ac = self.group.addAction(style) - ac.setCheckable(True) - if current == style: - ac.setChecked(True) - self.actions.append(ac) - ac.triggered.connect(partial(self.set_theme, style)) - self.addAction(ac) - - def set_theme(self, style, *args): - prefs['theme'] = style - -# }}} - - -class Console(QTextEdit): - - running = pyqtSignal() - running_done = pyqtSignal() - - @property - def doc(self): - return self.document() - - @property - def cursor(self): - return self.textCursor() - - @property - def root_frame(self): - return self.doc.rootFrame() - - def unhandled_exception(self, type, value, tb): - if type == KeyboardInterrupt: - return - try: - sio = StringIO.StringIO() - traceback.print_exception(type, value, tb, file=sio) - fe = sio.getvalue() - prints(fe) - try: - val = unicode(value) - except: - val = repr(value) - msg = '%s:'%type.__name__ + val - error_dialog(self, _('ERROR: Unhandled exception'), msg, - det_msg=fe, show=True) - except BaseException: - pass - - def __init__(self, - prompt='>>> ', - continuation='... ', - parent=None): - QTextEdit.__init__(self, parent) - self.shutting_down = False - self.compiler = CommandCompiler() - self.buf = self.old_buf = [] - self.history = History([''], dynamic.get('console_history', [])) - self.prompt_frame = None - self.allow_output = False - self.prompt_frame_format = QTextFrameFormat() - self.prompt_frame_format.setBorder(1) - self.prompt_frame_format.setBorderStyle(QTextFrameFormat.BorderStyle_Solid) - self.prompt_len = len(prompt) - - self.doc.setMaximumBlockCount(int(prefs['scrollback'])) - self.lexer = PythonLexer(ensurenl=False) - self.tb_lexer = PythonTracebackLexer() - - self.context_menu = cm = QMenu(self) # {{{ - cm.theme = ThemeMenu(cm) - # }}} - - self.formatter = Formatter(prompt, continuation, style=prefs['theme']) - p = QPalette() - p.setColor(p.Base, QColor(self.formatter.background_color)) - p.setColor(p.Text, QColor(self.formatter.color)) - self.setPalette(p) - - self.key_dispatcher = { # {{{ - Qt.Key_Enter : self.enter_pressed, - Qt.Key_Return : self.enter_pressed, - Qt.Key_Up : self.up_pressed, - Qt.Key_Down : self.down_pressed, - Qt.Key_Home : self.home_pressed, - Qt.Key_End : self.end_pressed, - Qt.Key_Left : self.left_pressed, - Qt.Key_Right : self.right_pressed, - Qt.Key_Backspace : self.backspace_pressed, - Qt.Key_Delete : self.delete_pressed, - } # }}} - - motd = textwrap.dedent('''\ - # Python {0} - # {1} {2} - '''.format(sys.version.splitlines()[0], __appname__, - __version__)) - - sys.excepthook = self.unhandled_exception - - self.controllers = [] - QTimer.singleShot(0, self.launch_controller) - - with EditBlock(self.cursor): - self.render_block(motd) - - def shutdown(self): - dynamic.set('console_history', self.history.serialize()) - self.shutting_down = True - for c in self.controllers: - c.kill() - - def contextMenuEvent(self, event): - self.context_menu.popup(event.globalPos()) - event.accept() - - # Controller management {{{ - @property - def controller(self): - return self.controllers[-1] - - def no_controller_error(self): - error_dialog(self, _('No interpreter'), - _('No active interpreter found. Try restarting the' - ' console'), show=True) - - def launch_controller(self, *args): - c = Controller(self) - c.write_output.connect(self.show_output, type=Qt.QueuedConnection) - c.show_error.connect(self.show_error, type=Qt.QueuedConnection) - c.interpreter_died.connect(self.interpreter_died, - type=Qt.QueuedConnection) - c.interpreter_done.connect(self.execution_done) - self.controllers.append(c) - - def interpreter_died(self, controller, returncode): - if not self.shutting_down and controller.current_command is not None: - error_dialog(self, _('Interpreter died'), - _('Interpreter dies while executing a command. To see ' - 'the command, click Show details'), - det_msg=controller.current_command, show=True) - - def execute(self, prompt_lines): - c = self.root_frame.lastCursorPosition() - self.setTextCursor(c) - self.old_prompt_frame = self.prompt_frame - self.prompt_frame = None - self.old_buf = self.buf - self.buf = [] - self.running.emit() - self.controller.runsource('\n'.join(prompt_lines)) - - def execution_done(self, controller, ret): - if controller is self.controller: - self.running_done.emit() - if ret: # Incomplete command - self.buf = self.old_buf - self.prompt_frame = self.old_prompt_frame - c = self.prompt_frame.lastCursorPosition() - c.insertBlock() - self.setTextCursor(c) - else: # Command completed - try: - self.old_prompt_frame.setFrameFormat(QTextFrameFormat()) - except RuntimeError: - # Happens if enough lines of output that the old - # frame was deleted - pass - - self.render_current_prompt() - - # }}} - - # Prompt management {{{ - - @dynamic_property - def cursor_pos(self): - doc = ''' - The cursor position in the prompt has the form (row, col). - row starts at 0 for the first line - col is 0 if the cursor is at the start of the line, 1 if it is after - the first character, n if it is after the nth char. - ''' - - def fget(self): - if self.prompt_frame is not None: - pos = self.cursor.position() - it = self.prompt_frame.begin() - lineno = 0 - while not it.atEnd(): - bl = it.currentBlock() - if bl.contains(pos): - return (lineno, pos - bl.position()) - it += 1 - lineno += 1 - return (-1, -1) - - def fset(self, val): - row, col = val - if self.prompt_frame is not None: - it = self.prompt_frame.begin() - lineno = 0 - while not it.atEnd(): - if lineno == row: - c = self.cursor - c.setPosition(it.currentBlock().position()) - c.movePosition(c.NextCharacter, n=col) - self.setTextCursor(c) - break - it += 1 - lineno += 1 - - return property(fget=fget, fset=fset, doc=doc) - - def move_cursor_to_prompt(self): - if self.prompt_frame is not None and self.cursor_pos[0] < 0: - c = self.prompt_frame.lastCursorPosition() - self.setTextCursor(c) - - def prompt(self, strip_prompt_strings=True): - if not self.prompt_frame: - yield u'' if strip_prompt_strings else self.formatter.prompt - else: - it = self.prompt_frame.begin() - while not it.atEnd(): - bl = it.currentBlock() - t = unicode(bl.text()) - if strip_prompt_strings: - t = t[self.prompt_len:] - yield t - it += 1 - - def set_prompt(self, lines): - self.render_current_prompt(lines) - - def clear_current_prompt(self): - if self.prompt_frame is None: - c = self.root_frame.lastCursorPosition() - self.prompt_frame = c.insertFrame(self.prompt_frame_format) - self.setTextCursor(c) - else: - c = self.prompt_frame.firstCursorPosition() - self.setTextCursor(c) - c.setPosition(self.prompt_frame.lastPosition(), c.KeepAnchor) - c.removeSelectedText() - c.setPosition(self.prompt_frame.firstPosition()) - - def render_current_prompt(self, lines=None, restore_cursor=False): - row, col = self.cursor_pos - cp = list(self.prompt()) if lines is None else lines - self.clear_current_prompt() - - for i, line in enumerate(cp): - start = i == 0 - end = i == len(cp) - 1 - self.formatter.render_prompt(not start, self.cursor) - self.formatter.render(self.lexer.get_tokens(line), self.cursor) - if not end: - self.cursor.insertBlock() - - if row > -1 and restore_cursor: - self.cursor_pos = (row, col) - - self.ensureCursorVisible() - - # }}} - - # Non-prompt Rendering {{{ - - def render_block(self, text, restore_prompt=True): - self.formatter.render(self.lexer.get_tokens(text), self.cursor) - self.cursor.insertBlock() - self.cursor.movePosition(self.cursor.End) - if restore_prompt: - self.render_current_prompt() - - def show_error(self, is_syntax_err, tb, controller=None): - if self.prompt_frame is not None: - # At a prompt, so redirect output - return prints(tb, end='') - try: - self.buf.append(tb) - if is_syntax_err: - self.formatter.render_syntax_error(tb, self.cursor) - else: - self.formatter.render(self.tb_lexer.get_tokens(tb), self.cursor) - except: - prints(tb, end='') - self.ensureCursorVisible() - QApplication.processEvents() - - def show_output(self, raw, which='stdout', controller=None): - def do_show(): - try: - self.buf.append(raw) - self.formatter.render_raw(raw, self.cursor) - except: - import traceback - prints(traceback.format_exc()) - prints(raw, end='') - - if self.prompt_frame is not None: - with Prepender(self): - do_show() - else: - do_show() - self.ensureCursorVisible() - QApplication.processEvents() - - # }}} - - # Keyboard management {{{ - - def keyPressEvent(self, ev): - text = unicode(ev.text()) - key = ev.key() - action = self.key_dispatcher.get(key, None) - if callable(action): - action() - elif key in (Qt.Key_Escape,): - QTextEdit.keyPressEvent(self, ev) - elif text: - self.text_typed(text) - else: - QTextEdit.keyPressEvent(self, ev) - - def left_pressed(self): - lineno, pos = self.cursor_pos - if lineno < 0: - return - if pos > self.prompt_len: - c = self.cursor - c.movePosition(c.PreviousCharacter) - self.setTextCursor(c) - elif lineno > 0: - c = self.cursor - c.movePosition(c.Up) - c.movePosition(c.EndOfLine) - self.setTextCursor(c) - self.ensureCursorVisible() - - def up_pressed(self): - lineno, pos = self.cursor_pos - if lineno < 0: - return - if lineno == 0: - b = self.history.back() - if b is not None: - self.set_prompt(b) - else: - c = self.cursor - c.movePosition(c.Up) - self.setTextCursor(c) - self.ensureCursorVisible() - - def backspace_pressed(self): - lineno, pos = self.cursor_pos - if lineno < 0: - return - if pos > self.prompt_len: - self.cursor.deletePreviousChar() - elif lineno > 0: - c = self.cursor - c.movePosition(c.Up) - c.movePosition(c.EndOfLine) - self.setTextCursor(c) - self.ensureCursorVisible() - - def delete_pressed(self): - self.cursor.deleteChar() - self.ensureCursorVisible() - - def right_pressed(self): - lineno, pos = self.cursor_pos - if lineno < 0: - return - c = self.cursor - cp = list(self.prompt(False)) - if pos < len(cp[lineno]): - c.movePosition(c.NextCharacter) - elif lineno < len(cp)-1: - c.movePosition(c.NextCharacter, n=1+self.prompt_len) - self.setTextCursor(c) - self.ensureCursorVisible() - - def down_pressed(self): - lineno, pos = self.cursor_pos - if lineno < 0: - return - c = self.cursor - cp = list(self.prompt(False)) - if lineno >= len(cp) - 1: - b = self.history.forward() - if b is not None: - self.set_prompt(b) - else: - c = self.cursor - c.movePosition(c.Down) - self.setTextCursor(c) - self.ensureCursorVisible() - - def home_pressed(self): - if self.prompt_frame is not None: - mods = QApplication.keyboardModifiers() - ctrl = bool(int(mods & Qt.CTRL)) - if ctrl: - self.cursor_pos = (0, self.prompt_len) - else: - c = self.cursor - c.movePosition(c.StartOfLine) - c.movePosition(c.NextCharacter, n=self.prompt_len) - self.setTextCursor(c) - self.ensureCursorVisible() - - def end_pressed(self): - if self.prompt_frame is not None: - mods = QApplication.keyboardModifiers() - ctrl = bool(int(mods & Qt.CTRL)) - if ctrl: - self.cursor_pos = (len(list(self.prompt()))-1, self.prompt_len) - c = self.cursor - c.movePosition(c.EndOfLine) - self.setTextCursor(c) - self.ensureCursorVisible() - - def enter_pressed(self): - if self.prompt_frame is None: - return - if not self.controller.is_alive: - return self.no_controller_error() - cp = list(self.prompt()) - if cp[0]: - try: - ret = self.compiler('\n'.join(cp)) - except: - pass - else: - if ret is None: - c = self.prompt_frame.lastCursorPosition() - c.insertBlock() - self.setTextCursor(c) - self.render_current_prompt() - return - else: - self.history.enter(cp) - self.execute(cp) - - def text_typed(self, text): - if self.prompt_frame is not None: - self.move_cursor_to_prompt() - self.cursor.insertText(text) - self.render_current_prompt(restore_cursor=True) - self.history.current = list(self.prompt()) - - # }}} - - diff --git a/src/calibre/utils/pyconsole/controller.py b/src/calibre/utils/pyconsole/controller.py deleted file mode 100644 index 05db930950..0000000000 --- a/src/calibre/utils/pyconsole/controller.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -import os, cPickle, signal, time -from Queue import Queue, Empty -from multiprocessing.connection import Listener, arbitrary_address -from binascii import hexlify - -from PyQt5.Qt import QThread, pyqtSignal - -from calibre.utils.pyconsole import Process, iswindows, POLL_TIMEOUT - -class Controller(QThread): - - # show_error(is_syntax_error, traceback, self) - show_error = pyqtSignal(object, object, object) - # write_output(unicode_object, stdout or stderr, self) - write_output = pyqtSignal(object, object, object) - # Indicates interpreter has finished evaluating current command - interpreter_done = pyqtSignal(object, object) - # interpreter_died(self, returncode or None if no return code available) - interpreter_died = pyqtSignal(object, object) - - def __init__(self, parent): - QThread.__init__(self, parent) - self.keep_going = True - self.current_command = None - - self.out_queue = Queue() - self.address = arbitrary_address('AF_PIPE' if iswindows else 'AF_UNIX') - self.auth_key = os.urandom(32) - if iswindows and self.address[1] == ':': - self.address = self.address[2:] - self.listener = Listener(address=self.address, - authkey=self.auth_key, backlog=4) - - self.env = { - 'CALIBRE_SIMPLE_WORKER': - 'calibre.utils.pyconsole.interpreter:main', - 'CALIBRE_WORKER_ADDRESS': - hexlify(cPickle.dumps(self.listener.address, -1)), - 'CALIBRE_WORKER_KEY': hexlify(self.auth_key) - } - self.process = Process(self.env) - self.output_file_buf = self.process(redirect_output=False) - self.conn = self.listener.accept() - self.start() - - def run(self): - while self.keep_going and self.is_alive: - try: - self.communicate() - except KeyboardInterrupt: - pass - except EOFError: - break - self.interpreter_died.emit(self, self.returncode) - try: - self.listener.close() - except: - pass - - def communicate(self): - if self.conn.poll(POLL_TIMEOUT): - self.dispatch_incoming_message(self.conn.recv()) - try: - obj = self.out_queue.get_nowait() - except Empty: - pass - else: - try: - self.conn.send(obj) - except: - raise EOFError('controller failed to send') - - def dispatch_incoming_message(self, obj): - try: - cmd, data = obj - except: - print 'Controller received invalid message' - print repr(obj) - return - if cmd in ('stdout', 'stderr'): - self.write_output.emit(data, cmd, self) - elif cmd == 'syntaxerror': - self.show_error.emit(True, data, self) - elif cmd == 'traceback': - self.show_error.emit(False, data, self) - elif cmd == 'done': - self.current_command = None - self.interpreter_done.emit(self, data) - - def runsource(self, cmd): - self.current_command = cmd - self.out_queue.put(('run', cmd)) - - def __nonzero__(self): - return self.process.is_alive - - @property - def returncode(self): - return self.process.returncode - - def interrupt(self): - if hasattr(signal, 'SIGINT'): - os.kill(self.process.pid, signal.SIGINT) - elif hasattr(signal, 'CTRL_C_EVENT'): - os.kill(self.process.pid, signal.CTRL_C_EVENT) - - @property - def is_alive(self): - return self.process.is_alive - - def kill(self): - self.out_queue.put(('quit', 0)) - t = 0 - while self.is_alive and t < 10: - time.sleep(0.1) - self.process.kill() - self.keep_going = False - diff --git a/src/calibre/utils/pyconsole/formatter.py b/src/calibre/utils/pyconsole/formatter.py deleted file mode 100644 index 2db4eac545..0000000000 --- a/src/calibre/utils/pyconsole/formatter.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -from PyQt5.Qt import QTextCharFormat, QFont, QBrush, QColor - -from pygments.formatter import Formatter as PF -from pygments.token import Token, Generic, string_to_tokentype - -class Formatter(object): - - def __init__(self, prompt, continuation, style='default'): - if len(prompt) != len(continuation): - raise ValueError('%r does not have the same length as %r' % - (prompt, continuation)) - - self.prompt, self.continuation = prompt, continuation - self.set_style(style) - - def set_style(self, style): - pf = PF(style=style) - self.styles = {} - self.normal = self.base_fmt() - self.background_color = pf.style.background_color - self.color = 'black' - - for ttype, ndef in pf.style: - fmt = self.base_fmt() - fmt.setProperty(fmt.UserProperty, str(ttype)) - if ndef['color']: - fmt.setForeground(QBrush(QColor('#%s'%ndef['color']))) - fmt.setUnderlineColor(QColor('#%s'%ndef['color'])) - if ttype == Generic.Output: - self.color = '#%s'%ndef['color'] - if ndef['bold']: - fmt.setFontWeight(QFont.Bold) - if ndef['italic']: - fmt.setFontItalic(True) - if ndef['underline']: - fmt.setFontUnderline(True) - if ndef['bgcolor']: - fmt.setBackground(QBrush(QColor('#%s'%ndef['bgcolor']))) - if ndef['border']: - pass # No support for borders - - self.styles[ttype] = fmt - - def get_fmt(self, token): - if type(token) != type(Token.Generic): # noqa - token = string_to_tokentype(token) - fmt = self.styles.get(token, None) - if fmt is None: - fmt = self.base_fmt() - fmt.setProperty(fmt.UserProperty, str(token)) - return fmt - - def base_fmt(self): - fmt = QTextCharFormat() - fmt.setFontFamily('monospace') - return fmt - - def render_raw(self, raw, cursor): - cursor.insertText(raw, self.normal) - - def render_syntax_error(self, tb, cursor): - fmt = self.get_fmt(Token.Error) - cursor.insertText(tb, fmt) - - def render(self, tokens, cursor): - lastval = '' - lasttype = None - - for ttype, value in tokens: - while ttype not in self.styles: - ttype = ttype.parent - if ttype == lasttype: - lastval += value - else: - if lastval: - fmt = self.styles[lasttype] - cursor.insertText(lastval, fmt) - lastval = value - lasttype = ttype - - if lastval: - fmt = self.styles[lasttype] - cursor.insertText(lastval, fmt) - - def render_prompt(self, is_continuation, cursor): - pr = self.continuation if is_continuation else self.prompt - fmt = self.get_fmt(Generic.Prompt) - if fmt is None: - fmt = self.base_fmt() - cursor.insertText(pr, fmt) - - diff --git a/src/calibre/utils/pyconsole/history.py b/src/calibre/utils/pyconsole/history.py deleted file mode 100644 index e7768574e3..0000000000 --- a/src/calibre/utils/pyconsole/history.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -from collections import deque - -class History(object): # {{{ - - def __init__(self, current, entries): - self.entries = deque(entries, maxlen=max(2000, len(entries))) - self.index = len(self.entries) - 1 - self.current = self.default = current - self.last_was_back = False - - def back(self, amt=1): - if self.entries: - oidx = self.index - ans = self.entries[self.index] - self.index = max(0, self.index - amt) - self.last_was_back = self.index != oidx - return ans - - def forward(self, amt=1): - if self.entries: - d = self.index - if self.last_was_back: - d += 1 - if d >= len(self.entries) - 1: - self.index = len(self.entries) - 1 - self.last_was_back = False - return self.current - if self.last_was_back: - amt += 1 - self.index = min(len(self.entries)-1, self.index + amt) - self.last_was_back = False - return self.entries[self.index] - - def enter(self, x): - try: - self.entries.remove(x) - except ValueError: - pass - self.entries.append(x) - self.index = len(self.entries) - 1 - self.current = self.default - self.last_was_back = False - - def serialize(self): - return list(self.entries) - -# }}} - - diff --git a/src/calibre/utils/pyconsole/interpreter.py b/src/calibre/utils/pyconsole/interpreter.py deleted file mode 100644 index bce157cc63..0000000000 --- a/src/calibre/utils/pyconsole/interpreter.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -import sys, cPickle, os, binascii -from code import InteractiveInterpreter -from Queue import Queue, Empty -from threading import Thread -from binascii import unhexlify -from multiprocessing.connection import Client -from repr import repr as safe_repr - -from calibre.utils.pyconsole import preferred_encoding, isbytestring, \ - POLL_TIMEOUT - -''' -Messages sent by client: - - (stdout, unicode) - (stderr, unicode) - (syntaxerror, unicode) - (traceback, unicode) - (done, True iff incomplete command) - -Messages that can be received by client: - (quit, return code) - (run, unicode) - -''' - -def tounicode(raw): # {{{ - if isbytestring(raw): - try: - raw = raw.decode(preferred_encoding, 'replace') - except: - raw = safe_repr(raw) - - if isbytestring(raw): - try: - raw.decode('utf-8', 'replace') - except: - raw = u'Undecodable bytestring' - return raw -# }}} - -class DummyFile(object): # {{{ - - def __init__(self, what, out_queue): - self.closed = False - self.name = 'console' - self.softspace = 0 - self.what = what - self.out_queue = out_queue - - def flush(self): - pass - - def close(self): - pass - - def write(self, raw): - self.out_queue.put((self.what, tounicode(raw))) -# }}} - -class Comm(Thread): # {{{ - - def __init__(self, conn, out_queue, in_queue): - Thread.__init__(self) - self.daemon = True - self.conn = conn - self.out_queue = out_queue - self.in_queue = in_queue - self.keep_going = True - - def run(self): - while self.keep_going: - try: - self.communicate() - except KeyboardInterrupt: - pass - except EOFError: - pass - - def communicate(self): - if self.conn.poll(POLL_TIMEOUT): - try: - obj = self.conn.recv() - except: - pass - else: - self.in_queue.put(obj) - try: - obj = self.out_queue.get_nowait() - except Empty: - pass - else: - try: - self.conn.send(obj) - except: - raise EOFError('interpreter failed to send') -# }}} - -class Interpreter(InteractiveInterpreter): # {{{ - - def __init__(self, queue, local={}): - if '__name__' not in local: - local['__name__'] = '__console__' - if '__doc__' not in local: - local['__doc__'] = None - self.out_queue = queue - sys.stdout = DummyFile('stdout', queue) - sys.stderr = DummyFile('sdterr', queue) - InteractiveInterpreter.__init__(self, locals=local) - - def showtraceback(self, *args, **kwargs): - self.is_syntax_error = False - InteractiveInterpreter.showtraceback(self, *args, **kwargs) - - def showsyntaxerror(self, *args, **kwargs): - self.is_syntax_error = True - InteractiveInterpreter.showsyntaxerror(self, *args, **kwargs) - - def write(self, raw): - what = 'syntaxerror' if self.is_syntax_error else 'traceback' - self.out_queue.put((what, tounicode(raw))) - -# }}} - -def connect(): - os.chdir(cPickle.loads(binascii.unhexlify(os.environ['ORIGWD']))) - address = cPickle.loads(unhexlify(os.environ['CALIBRE_WORKER_ADDRESS'])) - key = unhexlify(os.environ['CALIBRE_WORKER_KEY']) - return Client(address, authkey=key) - -def main(): - out_queue = Queue() - in_queue = Queue() - conn = connect() - comm = Comm(conn, out_queue, in_queue) - comm.start() - interpreter = Interpreter(out_queue) - - ret = 0 - - while True: - try: - try: - cmd, data = in_queue.get(1) - except Empty: - pass - else: - if cmd == 'quit': - ret = data - comm.keep_going = False - comm.join() - break - elif cmd == 'run': - if not comm.is_alive(): - ret = 1 - break - ret = False - try: - ret = interpreter.runsource(data) - except KeyboardInterrupt: - pass - except SystemExit: - out_queue.put(('stderr', 'SystemExit ignored\n')) - out_queue.put(('done', ret)) - except KeyboardInterrupt: - pass - - return ret - -if __name__ == '__main__': - main() diff --git a/src/calibre/utils/pyconsole/main.py b/src/calibre/utils/pyconsole/main.py deleted file mode 100644 index 77d727f663..0000000000 --- a/src/calibre/utils/pyconsole/main.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' -__version__ = '0.1.0' - -from functools import partial - -from PyQt5.Qt import QDialog, QToolBar, QStatusBar, QLabel, QFont, Qt, \ - QApplication, QIcon, QVBoxLayout, QAction - -from calibre.utils.pyconsole import dynamic, __appname__, __version__ -from calibre.utils.pyconsole.console import Console - -class MainWindow(QDialog): - - def __init__(self, - default_status_msg=_('Welcome to') + ' ' + __appname__+' console', - parent=None): - QDialog.__init__(self, parent) - - self.restart_requested = False - self.l = QVBoxLayout() - self.setLayout(self.l) - - self.resize(800, 600) - geom = dynamic.get('console_window_geometry', None) - if geom is not None: - self.restoreGeometry(geom) - - # Setup tool bar {{{ - self.tool_bar = QToolBar(self) - self.tool_bar.setToolButtonStyle(Qt.ToolButtonTextOnly) - self.l.addWidget(self.tool_bar) - # }}} - - # Setup status bar {{{ - self.status_bar = QStatusBar(self) - self.status_bar.defmsg = QLabel(__appname__ + _(' console ') + - __version__) - self.status_bar._font = QFont() - self.status_bar._font.setBold(True) - self.status_bar.defmsg.setFont(self.status_bar._font) - self.status_bar.addWidget(self.status_bar.defmsg) - # }}} - - self.console = Console(parent=self) - self.console.running.connect(partial(self.status_bar.showMessage, - _('Code is running'))) - self.console.running_done.connect(self.status_bar.clearMessage) - self.l.addWidget(self.console) - self.l.addWidget(self.status_bar) - self.setWindowTitle(__appname__ + ' console') - self.setWindowIcon(QIcon(I('console.png'))) - - self.restart_action = QAction(_('Restart console'), self) - self.restart_action.setShortcut(_('Ctrl+R')) - self.addAction(self.restart_action) - self.restart_action.triggered.connect(self.restart) - self.console.context_menu.addAction(self.restart_action) - - def restart(self): - self.restart_requested = True - self.reject() - - def closeEvent(self, *args): - dynamic.set('console_window_geometry', - bytearray(self.saveGeometry())) - self.console.shutdown() - return QDialog.closeEvent(self, *args) - - -def show(): - while True: - m = MainWindow() - m.exec_() - if not m.restart_requested: - break - -def main(): - QApplication.setApplicationName(__appname__+' console') - QApplication.setOrganizationName('Kovid Goyal') - app = QApplication([]) - app - show() - -if __name__ == '__main__': - main() - diff --git a/src/calibre/utils/pyparsing.py b/src/calibre/utils/pyparsing.py deleted file mode 100644 index 33b0afffdf..0000000000 --- a/src/calibre/utils/pyparsing.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=utf-8 -from __future__ import (unicode_literals, division, absolute_import, - print_function) - -__license__ = 'GPL v3' -__copyright__ = '2013, Kovid Goyal ' - -# Dummy file for backwards compatibility with older plugins -from calibre.utils.search_query_parser import ParseException # noqa -