From 9fa40ff7cc53e8f5262b982d80b98c3447d60cc0 2014-11-14 01:02:29 From: Doug Blank Date: 2014-11-14 01:02:29 Subject: [PATCH] Addressed issues: renamed ZMQHistoryManager (appears to do need to do more than just an Accessor) in IPython/terminal/console/zmqhistory.py; added abc methods; rewrote access methods to load the history from the kernel client; works with 'ipython console' and with 'ipython console --kernel' --- diff --git a/IPython/core/history.py b/IPython/core/history.py index 64c0e16..92c1a5d 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -15,6 +15,7 @@ from __future__ import print_function # Stdlib imports import atexit import datetime +import abc import os import re try: @@ -26,17 +27,13 @@ except ImportError: sqlite3 = None import threading -try: - from queue import Empty # Py 3 -except ImportError: - from Queue import Empty # Py 2 - # Our own packages from IPython.config.configurable import Configurable from IPython.external.decorator import decorator from IPython.utils.decorators import undoc from IPython.utils.path import locate_profile from IPython.utils import py3compat +from IPython.utils.py3compat import with_metaclass from IPython.utils.traitlets import ( Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError, ) @@ -104,52 +101,23 @@ def catch_corrupt_db(f, self, *a, **kw): raise class HistoryAccessorBase(Configurable): - input_hist_parsed = List([""]) - input_hist_raw = List([""]) - output_hist = Dict() - dir_hist = List() - output_hist_reprs = Dict() - - def end_session(self): - pass - - def reset(self, new_session=True): - """Clear the session history, releasing all object references, and - optionally open a new session.""" - self.output_hist.clear() - # The directory history can't be completely empty - self.dir_hist[:] = [py3compat.getcwd()] - - if new_session: - if self.session_number: - self.end_session() - self.input_hist_parsed[:] = [""] - self.input_hist_raw[:] = [""] - self.new_session() - - def new_session(self, conn=None): - pass - - def writeout_cache(self): - pass + """An abstract class for History Accessors """ + @abc.abstractmethod def get_tail(self, n=10, raw=True, output=False, include_latest=False): - return [] + pass + @abc.abstractmethod def search(self, pattern="*", raw=True, search_raw=True, output=False, n=None, unique=False): - return [] + pass + @abc.abstractmethod def get_range(self, session, start=1, stop=None, raw=True,output=False): - return [] - - def get_range_by_str(self, rangestr, raw=True, output=False): - return [] - - def store_inputs(self, line_num, source, source_raw=None): pass - def store_output(self, line_num): + @abc.abstractmethod + def get_range_by_str(self, rangestr, raw=True, output=False): pass class HistoryAccessor(HistoryAccessorBase): @@ -800,54 +768,6 @@ class HistoryManager(HistoryAccessor): finally: self.db_output_cache = [] -class KernelHistoryManager(HistoryAccessorBase): - def __init__(self, client): - self.client = client - self._load_history() - - def _load_history(self): - msg_id = self.client.history() - while True: - try: - reply = self.client.get_shell_msg(timeout=1) - except Empty: - break - else: - if reply['parent_header'].get('msg_id') == msg_id: - history = reply['content'].get('history', []) - break - self.history = history - print("_load_history:", self.history) - - def writeout_cache(self): - """dump cache before certain database lookups.""" - print("write_cache") - - def get_tail(self, n=10, raw=True, output=False, include_latest=False): - print("get_tail: ", n) - return self.history[-n:] - - def search(self, pattern="*", raw=True, search_raw=True, - output=False, n=None, unique=False): - print("search: ", pattern) - return [] - - def get_range(self, session, start=1, stop=None, raw=True,output=False): - print("get_range: ", start, stop) - if stop is None: - stop = -1 - return self.history[start:stop] - - def get_range_by_str(self, rangestr, raw=True, output=False): - print("get_range_by_str: " + rangestr) - return [] - - def store_inputs(self, line_num, source, source_raw=None): - print("store_inputs") - - def store_output(self, line_num): - print("store_output") - class HistorySavingThread(threading.Thread): """This thread takes care of writing history to the database, so that diff --git a/IPython/terminal/console/interactiveshell.py b/IPython/terminal/console/interactiveshell.py index 3a68cb4..7f1d333 100644 --- a/IPython/terminal/console/interactiveshell.py +++ b/IPython/terminal/console/interactiveshell.py @@ -23,7 +23,7 @@ except ImportError: from IPython.core import page from IPython.core import release -from IPython.core.history import KernelHistoryManager +from IPython.terminal.console.zmqhistory import ZMQHistoryManager from IPython.utils.warn import warn, error from IPython.utils import io from IPython.utils.py3compat import string_types, input @@ -573,6 +573,6 @@ class ZMQTerminalInteractiveShell(TerminalInteractiveShell): def init_history(self): """Sets up the command history. """ - self.history_manager = KernelHistoryManager(client=self.client) + self.history_manager = ZMQHistoryManager(client=self.client) self.configurables.append(self.history_manager) diff --git a/IPython/terminal/console/zmqhistory.py b/IPython/terminal/console/zmqhistory.py new file mode 100644 index 0000000..a2059b2 --- /dev/null +++ b/IPython/terminal/console/zmqhistory.py @@ -0,0 +1,111 @@ +""" ZMQ Kernel History accessor and manager. """ +#----------------------------------------------------------------------------- +# Copyright (C) 2010-2011 The IPython Development Team. +# +# Distributed under the terms of the BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +from IPython.core.history import HistoryAccessorBase +from IPython.utils import py3compat +from IPython.utils.traitlets import Dict, List + +try: + from queue import Empty # Py 3 +except ImportError: + from Queue import Empty # Py 2 + +class ZMQHistoryManager(HistoryAccessorBase): + """History accessor and manager for ZMQ-based kernels""" + input_hist_parsed = List([""]) + output_hist = Dict() + dir_hist = List() + output_hist_reprs = Dict() + + def __init__(self, client): + """ + Class to load the command-line history from a ZMQ-based kernel, + and access the history. + + Parameters + ---------- + + client: `IPython.kernel.KernelClient` + The kernel client in order to request the history. + """ + self.client = client + + def _load_history(self, raw=True, output=False, hist_access_type='range', + **kwargs): + """ + Load the history over ZMQ from the kernel. Wraps the history + messaging with loop to wait to get history results. + """ + # 'range' (fill in session, start and stop params), + # 'tail' (fill in n) + # 'search' (fill in pattern param). + msg_id = self.client.history(raw=raw, output=output, + hist_access_type=hist_access_type, + **kwargs) + history = [] + while True: + try: + reply = self.client.get_shell_msg(timeout=1) + except Empty: + break + else: + if reply['parent_header'].get('msg_id') == msg_id: + history = reply['content'].get('history', []) + break + return history + + def writeout_cache(self): + """ + Not needed for ZMQ-based histories. + """ + pass + + def get_tail(self, n=10, raw=True, output=False, include_latest=False): + return self._load_history(hist_access_type='tail', n=n, raw=raw, + output=output) + + def search(self, pattern="*", raw=True, search_raw=True, + output=False, n=None, unique=False): + return self._load_history(hist_access_type='search', pattern=pattern, + raw=raw, search_raw=search_raw, + output=output, n=n, unique=unique) + + def get_range(self, session, start=1, stop=None, raw=True,output=False): + return self._load_history(hist_access_type='range', raw=raw, + output=output, start=start, stop=stop, + session=session) + + def get_range_by_str(self, rangestr, raw=True, output=False): + return self._load_history(hist_access_type='range', raw=raw, + output=output, rangestr=rangetr) + + def end_session(self): + """ + Nothing to do for ZMQ-based histories. + """ + pass + + def reset(self, new_session=True): + """Clear the session history, releasing all object references, and + optionally open a new session.""" + self.output_hist.clear() + # The directory history can't be completely empty + self.dir_hist[:] = [py3compat.getcwd()] + + if new_session: + if self.session_number: + self.end_session() + self.input_hist_parsed[:] = [""] + self.input_hist_raw[:] = [""] + self.new_session() +