diff --git a/IPython/core/history.py b/IPython/core/history.py index c9b8435..c615ad8 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -98,9 +98,24 @@ def catch_corrupt_db(f, self, *a, **kw): # The hist_file is probably :memory: or something else. raise +class HistoryAccessorBase(Configurable): + """An abstract class for History Accessors """ + def get_tail(self, n=10, raw=True, output=False, include_latest=False): + raise NotImplementedError + + def search(self, pattern="*", raw=True, search_raw=True, + output=False, n=None, unique=False): + raise NotImplementedError + + def get_range(self, session, start=1, stop=None, raw=True,output=False): + raise NotImplementedError -class HistoryAccessor(Configurable): + def get_range_by_str(self, rangestr, raw=True, output=False): + raise NotImplementedError + + +class HistoryAccessor(HistoryAccessorBase): """Access the history database without adding to it. This is intended for use by standalone history tools. IPython shells use @@ -544,7 +559,7 @@ class HistoryManager(HistoryAccessor): self.input_hist_parsed[:] = [""] self.input_hist_raw[:] = [""] self.new_session() - + # ------------------------------ # Methods for retrieving history # ------------------------------ diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 2e27f80..06752ba 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -424,7 +424,7 @@ class InteractiveShell(SingletonConfigurable): display_trap = Instance('IPython.core.display_trap.DisplayTrap') extension_manager = Instance('IPython.core.extensions.ExtensionManager') payload_manager = Instance('IPython.core.payload.PayloadManager') - history_manager = Instance('IPython.core.history.HistoryManager') + history_manager = Instance('IPython.core.history.HistoryAccessorBase') magics_manager = Instance('IPython.core.magic.MagicsManager') profile_dir = Instance('IPython.core.application.ProfileDir') diff --git a/IPython/terminal/console/interactiveshell.py b/IPython/terminal/console/interactiveshell.py index f0d7b73..7f1d333 100644 --- a/IPython/terminal/console/interactiveshell.py +++ b/IPython/terminal/console/interactiveshell.py @@ -23,6 +23,7 @@ except ImportError: from IPython.core import page from IPython.core import release +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 @@ -32,7 +33,6 @@ from IPython.utils.tempdir import NamedFileInTemporaryDirectory from IPython.terminal.interactiveshell import TerminalInteractiveShell from IPython.terminal.console.completer import ZMQCompleter - class ZMQTerminalInteractiveShell(TerminalInteractiveShell): """A subclass of TerminalInteractiveShell that uses the 0MQ kernel""" _executing = False @@ -570,3 +570,9 @@ class ZMQTerminalInteractiveShell(TerminalInteractiveShell): # Turn off the exit flag, so the mainloop can be restarted if desired self.exit_now = False + + def init_history(self): + """Sets up the command history. """ + 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..9384a39 --- /dev/null +++ b/IPython/terminal/console/zmqhistory.py @@ -0,0 +1,95 @@ +""" 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.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. + """ + history = [] + if hasattr(self.client, "history"): + ## In tests, KernelClient may not have a history method + msg_id = self.client.history(raw=raw, output=output, + hist_access_type=hist_access_type, + **kwargs) + 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 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=rangestr) + + def end_session(self): + """ + Nothing to do for ZMQ-based histories. + """ + pass + + def reset(self, new_session=True): + """ + Nothing to do for ZMQ-based histories. + """ + pass +