##// END OF EJS Templates
Merge branch 'takowl-fix-terminal-exit' into trunk
Brian Granger -
r3274:6d136257 merge
parent child Browse files
Show More
@@ -13,6 +13,7 b''
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import fnmatch
17 import fnmatch
17 import json
18 import json
18 import os
19 import os
@@ -105,6 +106,14 b' class HistoryManager(object):'
105
106
106 # Fill the history zero entry, user counter starts at 1
107 # Fill the history zero entry, user counter starts at 1
107 self.store_inputs('\n', '\n')
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 def _init_shadow_hist(self):
118 def _init_shadow_hist(self):
110 try:
119 try:
@@ -142,12 +151,22 b' class HistoryManager(object):'
142 with open(self.hist_file,'wt') as hfile:
151 with open(self.hist_file,'wt') as hfile:
143 json.dump(hist, hfile,
152 json.dump(hist, hfile,
144 sort_keys=True, indent=4)
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 def reload_history(self):
162 def reload_history(self):
147 """Reload the input history from disk file."""
163 """Reload the input history from disk file."""
148
164
149 with open(self.hist_file,'rt') as hfile:
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 self.input_hist_parsed = hist['parsed']
170 self.input_hist_parsed = hist['parsed']
152 self.input_hist_raw = hist['raw']
171 self.input_hist_raw = hist['raw']
153 if self.shell.has_readline:
172 if self.shell.has_readline:
@@ -254,25 +273,37 b' class HistoryManager(object):'
254 self.dir_hist[:] = [os.getcwd()]
273 self.dir_hist[:] = [os.getcwd()]
255
274
256 class HistorySaveThread(threading.Thread):
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 threading.Thread.__init__(self)
289 threading.Thread.__init__(self)
261 self.IPython_object = IPython_object
262 self.time_interval = time_interval
290 self.time_interval = time_interval
263 self.exit_now = exit_now
291 self.autosave_flag = autosave_flag
264 self.cond = threading.Condition()
292 self.exit_now = threading.Event()
293 # Ensure the thread is stopped tidily when exiting normally
294 atexit.register(self.stop)
265
295
266 def run(self):
296 def run(self):
267 while 1:
297 while True:
268 self.cond.acquire()
298 self.exit_now.wait(self.time_interval)
269 self.cond.wait(self.time_interval)
299 if self.exit_now.is_set():
270 self.cond.release()
271 if self.exit_now==True:
272 break
300 break
273 #printing for debug
301 self.autosave_flag.set()
274 #print("Saving...")
302
275 self.IPython_object.save_history()
303 def stop(self):
304 """Safely and quickly stop the autosave timer thread."""
305 self.exit_now.set()
306 self.join()
276
307
277 def magic_history(self, parameter_s = ''):
308 def magic_history(self, parameter_s = ''):
278 """Print input history (_i<n> variables), with most recent last.
309 """Print input history (_i<n> variables), with most recent last.
@@ -45,7 +45,6 b' from IPython.core.error import TryNext, UsageError'
45 from IPython.core.extensions import ExtensionManager
45 from IPython.core.extensions import ExtensionManager
46 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
46 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
47 from IPython.core.history import HistoryManager
47 from IPython.core.history import HistoryManager
48 from IPython.core.history import HistorySaveThread
49 from IPython.core.inputsplitter import IPythonInputSplitter
48 from IPython.core.inputsplitter import IPythonInputSplitter
50 from IPython.core.logger import Logger
49 from IPython.core.logger import Logger
51 from IPython.core.magic import Magic
50 from IPython.core.magic import Magic
@@ -294,8 +293,6 b' class InteractiveShell(Configurable, Magic):'
294 self.init_payload()
293 self.init_payload()
295 self.hooks.late_startup_hook()
294 self.hooks.late_startup_hook()
296 atexit.register(self.atexit_operations)
295 atexit.register(self.atexit_operations)
297 self.history_thread = HistorySaveThread(self, 60, False)
298 self.history_thread.start()
299
296
300 # While we're trying to have each part of the code directly access what it
297 # While we're trying to have each part of the code directly access what it
301 # needs without keeping redundant references to objects, we have too much
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 def init_history(self):
1237 def init_history(self):
1238 """Sets up the command history, and starts regular autosaves."""
1241 self.history_manager = HistoryManager(shell=self)
1239 self.history_manager = HistoryManager(shell=self)
1242
1240
1243 def save_history(self):
1241 def save_history(self):
@@ -24,7 +24,6 b' import sys'
24 from IPython.core.error import TryNext
24 from IPython.core.error import TryNext
25 from IPython.core.usage import interactive_usage, default_banner
25 from IPython.core.usage import interactive_usage, default_banner
26 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
26 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
27 from IPython.core.history import HistorySaveThread
28 from IPython.lib.inputhook import enable_gui
27 from IPython.lib.inputhook import enable_gui
29 from IPython.lib.pylabtools import pylab_activate
28 from IPython.lib.pylabtools import pylab_activate
30 from IPython.utils.terminal import toggle_set_term_title, set_term_title
29 from IPython.utils.terminal import toggle_set_term_title, set_term_title
@@ -499,10 +498,6 b' class TerminalInteractiveShell(InteractiveShell):'
499 This method calls the ask_exit callback."""
498 This method calls the ask_exit callback."""
500 if self.confirm_exit:
499 if self.confirm_exit:
501 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
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 self.ask_exit()
501 self.ask_exit()
507 else:
502 else:
508 self.ask_exit()
503 self.ask_exit()
General Comments 0
You need to be logged in to leave comments. Login now