Show More
@@ -13,6 +13,7 b'' | |||
|
13 | 13 | from __future__ import print_function |
|
14 | 14 | |
|
15 | 15 | # Stdlib imports |
|
16 | import atexit | |
|
16 | 17 | import fnmatch |
|
17 | 18 | import json |
|
18 | 19 | import os |
@@ -105,6 +106,14 b' class HistoryManager(object):' | |||
|
105 | 106 | |
|
106 | 107 | # Fill the history zero entry, user counter starts at 1 |
|
107 | 108 | self.store_inputs('\n', '\n') |
|
109 | ||
|
110 | # Create and start the autosaver. | |
|
111 | self.autosave_flag = threading.Event() | |
|
112 | self.autosave_timer = HistorySaveThread(self.autosave_flag, 60) | |
|
113 | self.autosave_timer.start() | |
|
114 | # Register the autosave handler to be triggered as a post execute | |
|
115 | # callback. | |
|
116 | self.shell.register_post_execute(self.autosave_if_due) | |
|
108 | 117 | |
|
109 | 118 | def _init_shadow_hist(self): |
|
110 | 119 | try: |
@@ -142,12 +151,22 b' class HistoryManager(object):' | |||
|
142 | 151 | with open(self.hist_file,'wt') as hfile: |
|
143 | 152 | json.dump(hist, hfile, |
|
144 | 153 | sort_keys=True, indent=4) |
|
154 | ||
|
155 | def autosave_if_due(self): | |
|
156 | """Check if the autosave event is set; if so, save history. We do it | |
|
157 | this way so that the save takes place in the main thread.""" | |
|
158 | if self.autosave_flag.is_set(): | |
|
159 | self.save_history() | |
|
160 | self.autosave_flag.clear() | |
|
145 | 161 | |
|
146 | 162 | def reload_history(self): |
|
147 | 163 | """Reload the input history from disk file.""" |
|
148 | 164 | |
|
149 | 165 | with open(self.hist_file,'rt') as hfile: |
|
150 | hist = json.load(hfile) | |
|
166 | try: | |
|
167 | hist = json.load(hfile) | |
|
168 | except ValueError: # Ignore it if JSON is corrupt. | |
|
169 | return | |
|
151 | 170 | self.input_hist_parsed = hist['parsed'] |
|
152 | 171 | self.input_hist_raw = hist['raw'] |
|
153 | 172 | if self.shell.has_readline: |
@@ -254,25 +273,37 b' class HistoryManager(object):' | |||
|
254 | 273 | self.dir_hist[:] = [os.getcwd()] |
|
255 | 274 | |
|
256 | 275 | class HistorySaveThread(threading.Thread): |
|
257 |
"""Thread to save history periodically |
|
|
276 | """This thread makes IPython save history periodically. | |
|
258 | 277 |
|
|
259 | def __init__(self, IPython_object, time_interval, exit_now): | |
|
278 | Without this class, IPython would only save the history on a clean exit. | |
|
279 | This saves the history periodically (the current default is once per | |
|
280 | minute), so that it is not lost in the event of a crash. | |
|
281 | ||
|
282 | The implementation sets an event to indicate that history should be saved. | |
|
283 | The actual save is carried out after executing a user command, to avoid | |
|
284 | thread issues. | |
|
285 | """ | |
|
286 | daemon = True | |
|
287 | ||
|
288 | def __init__(self, autosave_flag, time_interval=60): | |
|
260 | 289 | threading.Thread.__init__(self) |
|
261 | self.IPython_object = IPython_object | |
|
262 | 290 | self.time_interval = time_interval |
|
263 | self.exit_now = exit_now | |
|
264 |
self. |
|
|
291 | self.autosave_flag = autosave_flag | |
|
292 | self.exit_now = threading.Event() | |
|
293 | # Ensure the thread is stopped tidily when exiting normally | |
|
294 | atexit.register(self.stop) | |
|
265 | 295 | |
|
266 | 296 | def run(self): |
|
267 |
while |
|
|
268 | self.cond.acquire() | |
|
269 | self.cond.wait(self.time_interval) | |
|
270 | self.cond.release() | |
|
271 | if self.exit_now==True: | |
|
297 | while True: | |
|
298 | self.exit_now.wait(self.time_interval) | |
|
299 | if self.exit_now.is_set(): | |
|
272 | 300 | break |
|
273 | #printing for debug | |
|
274 | #print("Saving...") | |
|
275 | self.IPython_object.save_history() | |
|
301 | self.autosave_flag.set() | |
|
302 | ||
|
303 | def stop(self): | |
|
304 | """Safely and quickly stop the autosave timer thread.""" | |
|
305 | self.exit_now.set() | |
|
306 | self.join() | |
|
276 | 307 | |
|
277 | 308 | def magic_history(self, parameter_s = ''): |
|
278 | 309 | """Print input history (_i<n> variables), with most recent last. |
@@ -45,7 +45,6 b' from IPython.core.error import TryNext, UsageError' | |||
|
45 | 45 | from IPython.core.extensions import ExtensionManager |
|
46 | 46 | from IPython.core.fakemodule import FakeModule, init_fakemod_dict |
|
47 | 47 | from IPython.core.history import HistoryManager |
|
48 | from IPython.core.history import HistorySaveThread | |
|
49 | 48 | from IPython.core.inputsplitter import IPythonInputSplitter |
|
50 | 49 | from IPython.core.logger import Logger |
|
51 | 50 | from IPython.core.magic import Magic |
@@ -294,8 +293,6 b' class InteractiveShell(Configurable, Magic):' | |||
|
294 | 293 | self.init_payload() |
|
295 | 294 | self.hooks.late_startup_hook() |
|
296 | 295 | atexit.register(self.atexit_operations) |
|
297 | self.history_thread = HistorySaveThread(self, 60, False) | |
|
298 | self.history_thread.start() | |
|
299 | 296 | |
|
300 | 297 | # While we're trying to have each part of the code directly access what it |
|
301 | 298 | # needs without keeping redundant references to objects, we have too much |
@@ -1238,6 +1235,7 b' class InteractiveShell(Configurable, Magic):' | |||
|
1238 | 1235 | #------------------------------------------------------------------------- |
|
1239 | 1236 | |
|
1240 | 1237 | def init_history(self): |
|
1238 | """Sets up the command history, and starts regular autosaves.""" | |
|
1241 | 1239 | self.history_manager = HistoryManager(shell=self) |
|
1242 | 1240 | |
|
1243 | 1241 | def save_history(self): |
@@ -24,7 +24,6 b' import sys' | |||
|
24 | 24 | from IPython.core.error import TryNext |
|
25 | 25 | from IPython.core.usage import interactive_usage, default_banner |
|
26 | 26 | from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC |
|
27 | from IPython.core.history import HistorySaveThread | |
|
28 | 27 | from IPython.lib.inputhook import enable_gui |
|
29 | 28 | from IPython.lib.pylabtools import pylab_activate |
|
30 | 29 | from IPython.utils.terminal import toggle_set_term_title, set_term_title |
@@ -499,10 +498,6 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
499 | 498 | This method calls the ask_exit callback.""" |
|
500 | 499 | if self.confirm_exit: |
|
501 | 500 | if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'): |
|
502 | self.shell.history_thread.exit_now=True | |
|
503 | self.shell.history_thread.cond.acquire() | |
|
504 | self.shell.history_thread.cond.notify() | |
|
505 | self.shell.history_thread.cond.release() | |
|
506 | 501 | self.ask_exit() |
|
507 | 502 | else: |
|
508 | 503 | self.ask_exit() |
General Comments 0
You need to be logged in to leave comments.
Login now