##// END OF EJS Templates
Update history.py to use pathlib...
Jakub Klus -
Show More
@@ -6,7 +6,7 b''
6
6
7 import atexit
7 import atexit
8 import datetime
8 import datetime
9 import os
9 from pathlib import Path
10 import re
10 import re
11 import sqlite3
11 import sqlite3
12 import threading
12 import threading
@@ -16,8 +16,8 b' from decorator import decorator'
16 from IPython.utils.decorators import undoc
16 from IPython.utils.decorators import undoc
17 from IPython.paths import locate_profile
17 from IPython.paths import locate_profile
18 from traitlets import (
18 from traitlets import (
19 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
19 Any, Bool, Dict, Instance, Integer, List, Unicode, Union, TraitError,
20 default, observe,
20 default, observe
21 )
21 )
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
@@ -73,17 +73,18 b' def catch_corrupt_db(f, self, *a, **kw):'
73 if self._corrupt_db_counter > self._corrupt_db_limit:
73 if self._corrupt_db_counter > self._corrupt_db_limit:
74 self.hist_file = ':memory:'
74 self.hist_file = ':memory:'
75 self.log.error("Failed to load history too many times, history will not be saved.")
75 self.log.error("Failed to load history too many times, history will not be saved.")
76 elif os.path.isfile(self.hist_file):
76 elif self.hist_file.is_file():
77 # move the file out of the way
77 # move the file out of the way
78 base, ext = os.path.splitext(self.hist_file)
78 base = str(self.hist_file.parent / self.hist_file.stem)
79 size = os.stat(self.hist_file).st_size
79 ext = self.hist_file.suffix
80 size = self.hist_file.stat().st_size
80 if size >= _SAVE_DB_SIZE:
81 if size >= _SAVE_DB_SIZE:
81 # if there's significant content, avoid clobbering
82 # if there's significant content, avoid clobbering
82 now = datetime.datetime.now().isoformat().replace(':', '.')
83 now = datetime.datetime.now().isoformat().replace(':', '.')
83 newpath = base + '-corrupt-' + now + ext
84 newpath = base + '-corrupt-' + now + ext
84 # don't clobber previous corrupt backups
85 # don't clobber previous corrupt backups
85 for i in range(100):
86 for i in range(100):
86 if not os.path.isfile(newpath):
87 if not Path(newpath).exists():
87 break
88 break
88 else:
89 else:
89 newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
90 newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
@@ -91,7 +92,7 b' def catch_corrupt_db(f, self, *a, **kw):'
91 # not much content, possibly empty; don't worry about clobbering
92 # not much content, possibly empty; don't worry about clobbering
92 # maybe we should just delete it?
93 # maybe we should just delete it?
93 newpath = base + '-corrupt' + ext
94 newpath = base + '-corrupt' + ext
94 os.rename(self.hist_file, newpath)
95 self.hist_file.rename(newpath)
95 self.log.error("History file was moved to %s and a new file created.", newpath)
96 self.log.error("History file was moved to %s and a new file created.", newpath)
96 self.init_db()
97 self.init_db()
97 return []
98 return []
@@ -128,7 +129,7 b' class HistoryAccessor(HistoryAccessorBase):'
128 _corrupt_db_limit = 2
129 _corrupt_db_limit = 2
129
130
130 # String holding the path to the history file
131 # String holding the path to the history file
131 hist_file = Unicode(
132 hist_file = Union([Instance(Path), Unicode()],
132 help="""Path to file to use for SQLite history database.
133 help="""Path to file to use for SQLite history database.
133
134
134 By default, IPython will put the history database in the IPython
135 By default, IPython will put the history database in the IPython
@@ -144,7 +145,8 b' class HistoryAccessor(HistoryAccessorBase):'
144 you can also use the specific value `:memory:` (including the colon
145 you can also use the specific value `:memory:` (including the colon
145 at both end but not the back ticks), to avoid creating an history file.
146 at both end but not the back ticks), to avoid creating an history file.
146
147
147 """).tag(config=True)
148 """
149 ).tag(config=True)
148
150
149 enabled = Bool(True,
151 enabled = Bool(True,
150 help="""enable the SQLite history
152 help="""enable the SQLite history
@@ -176,7 +178,7 b' class HistoryAccessor(HistoryAccessorBase):'
176 (self.__class__.__name__, new)
178 (self.__class__.__name__, new)
177 raise TraitError(msg)
179 raise TraitError(msg)
178
180
179 def __init__(self, profile='default', hist_file=u'', **traits):
181 def __init__(self, profile='default', hist_file="", **traits):
180 """Create a new history accessor.
182 """Create a new history accessor.
181
183
182 Parameters
184 Parameters
@@ -197,7 +199,9 b' class HistoryAccessor(HistoryAccessorBase):'
197 if hist_file:
199 if hist_file:
198 self.hist_file = hist_file
200 self.hist_file = hist_file
199
201
200 if self.hist_file == u'':
202 try:
203 self.hist_file
204 except TraitError:
201 # No one has set the hist_file, yet.
205 # No one has set the hist_file, yet.
202 self.hist_file = self._get_hist_file_name(profile)
206 self.hist_file = self._get_hist_file_name(profile)
203
207
@@ -214,7 +218,7 b' class HistoryAccessor(HistoryAccessorBase):'
214 profile : str
218 profile : str
215 The name of a profile which has a history file.
219 The name of a profile which has a history file.
216 """
220 """
217 return os.path.join(locate_profile(profile), 'history.sqlite')
221 return Path(locate_profile(profile)) / 'history.sqlite'
218
222
219 @catch_corrupt_db
223 @catch_corrupt_db
220 def init_db(self):
224 def init_db(self):
@@ -461,7 +465,7 b' class HistoryManager(HistoryAccessor):'
461 @default('dir_hist')
465 @default('dir_hist')
462 def _dir_hist_default(self):
466 def _dir_hist_default(self):
463 try:
467 try:
464 return [os.getcwd()]
468 return [Path.cwd()]
465 except OSError:
469 except OSError:
466 return []
470 return []
467
471
@@ -531,7 +535,7 b' class HistoryManager(HistoryAccessor):'
531 The profile parameter is ignored, but must exist for compatibility with
535 The profile parameter is ignored, but must exist for compatibility with
532 the parent class."""
536 the parent class."""
533 profile_dir = self.shell.profile_dir.location
537 profile_dir = self.shell.profile_dir.location
534 return os.path.join(profile_dir, 'history.sqlite')
538 return Path(profile_dir)/'history.sqlite'
535
539
536 @only_when_enabled
540 @only_when_enabled
537 def new_session(self, conn=None):
541 def new_session(self, conn=None):
@@ -564,7 +568,7 b' class HistoryManager(HistoryAccessor):'
564 optionally open a new session."""
568 optionally open a new session."""
565 self.output_hist.clear()
569 self.output_hist.clear()
566 # The directory history can't be completely empty
570 # The directory history can't be completely empty
567 self.dir_hist[:] = [os.getcwd()]
571 self.dir_hist[:] = [Path.cwd()]
568
572
569 if new_session:
573 if new_session:
570 if self.session_number:
574 if self.session_number:
@@ -7,7 +7,7 b''
7
7
8 # stdlib
8 # stdlib
9 import io
9 import io
10 import os
10 from pathlib import Path
11 import sys
11 import sys
12 import tempfile
12 import tempfile
13 from datetime import datetime
13 from datetime import datetime
@@ -29,8 +29,9 b' def test_proper_default_encoding():'
29 def test_history():
29 def test_history():
30 ip = get_ipython()
30 ip = get_ipython()
31 with TemporaryDirectory() as tmpdir:
31 with TemporaryDirectory() as tmpdir:
32 tmp_path = Path(tmpdir)
32 hist_manager_ori = ip.history_manager
33 hist_manager_ori = ip.history_manager
33 hist_file = os.path.join(tmpdir, 'history.sqlite')
34 hist_file = tmp_path / 'history.sqlite'
34 try:
35 try:
35 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
36 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
36 hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"]
37 hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"]
@@ -55,10 +56,10 b' def test_history():'
55 ip.magic('%hist 2-500')
56 ip.magic('%hist 2-500')
56
57
57 # Check that we can write non-ascii characters to a file
58 # Check that we can write non-ascii characters to a file
58 ip.magic("%%hist -f %s" % os.path.join(tmpdir, "test1"))
59 ip.magic("%%hist -f %s" % (tmp_path / "test1"))
59 ip.magic("%%hist -pf %s" % os.path.join(tmpdir, "test2"))
60 ip.magic("%%hist -pf %s" % (tmp_path / "test2"))
60 ip.magic("%%hist -nf %s" % os.path.join(tmpdir, "test3"))
61 ip.magic("%%hist -nf %s" % (tmp_path / "test3"))
61 ip.magic("%%save %s 1-10" % os.path.join(tmpdir, "test4"))
62 ip.magic("%%save %s 1-10" % (tmp_path / "test4"))
62
63
63 # New session
64 # New session
64 ip.history_manager.reset()
65 ip.history_manager.reset()
@@ -126,8 +127,8 b' def test_history():'
126 nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
127 nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
127
128
128 # Cross testing: check that magic %save can get previous session.
129 # Cross testing: check that magic %save can get previous session.
129 testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
130 testfilename = (tmp_path /"test.py").resolve()
130 ip.magic("save " + testfilename + " ~1/1-3")
131 ip.magic("save " + str(testfilename) + " ~1/1-3")
131 with io.open(testfilename, encoding='utf-8') as testfile:
132 with io.open(testfilename, encoding='utf-8') as testfile:
132 nt.assert_equal(testfile.read(),
133 nt.assert_equal(testfile.read(),
133 u"# coding: utf-8\n" + u"\n".join(hist)+u"\n")
134 u"# coding: utf-8\n" + u"\n".join(hist)+u"\n")
@@ -176,13 +177,13 b' def test_timestamp_type():'
176 def test_hist_file_config():
177 def test_hist_file_config():
177 cfg = Config()
178 cfg = Config()
178 tfile = tempfile.NamedTemporaryFile(delete=False)
179 tfile = tempfile.NamedTemporaryFile(delete=False)
179 cfg.HistoryManager.hist_file = tfile.name
180 cfg.HistoryManager.hist_file = Path(tfile.name)
180 try:
181 try:
181 hm = HistoryManager(shell=get_ipython(), config=cfg)
182 hm = HistoryManager(shell=get_ipython(), config=cfg)
182 nt.assert_equal(hm.hist_file, cfg.HistoryManager.hist_file)
183 nt.assert_equal(hm.hist_file, cfg.HistoryManager.hist_file)
183 finally:
184 finally:
184 try:
185 try:
185 os.remove(tfile.name)
186 Path(tfile.name).unlink()
186 except OSError:
187 except OSError:
187 # same catch as in testing.tools.TempFileMixin
188 # same catch as in testing.tools.TempFileMixin
188 # On Windows, even though we close the file, we still can't
189 # On Windows, even though we close the file, we still can't
@@ -197,7 +198,7 b' def test_histmanager_disabled():'
197 ip = get_ipython()
198 ip = get_ipython()
198 with TemporaryDirectory() as tmpdir:
199 with TemporaryDirectory() as tmpdir:
199 hist_manager_ori = ip.history_manager
200 hist_manager_ori = ip.history_manager
200 hist_file = os.path.join(tmpdir, 'history.sqlite')
201 hist_file = Path(tmpdir) / 'history.sqlite'
201 cfg.HistoryManager.hist_file = hist_file
202 cfg.HistoryManager.hist_file = hist_file
202 try:
203 try:
203 ip.history_manager = HistoryManager(shell=ip, config=cfg)
204 ip.history_manager = HistoryManager(shell=ip, config=cfg)
@@ -211,4 +212,4 b' def test_histmanager_disabled():'
211 ip.history_manager = hist_manager_ori
212 ip.history_manager = hist_manager_ori
212
213
213 # hist_file should not be created
214 # hist_file should not be created
214 nt.assert_false(os.path.exists(hist_file))
215 nt.assert_false(hist_file.exists())
@@ -10,6 +10,7 b' Authors'
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import os
12 import os
13 from pathlib import Path
13 import re
14 import re
14 import sys
15 import sys
15 import tempfile
16 import tempfile
@@ -142,7 +143,7 b' def default_config():'
142 config.TerminalTerminalInteractiveShell.term_title = False,
143 config.TerminalTerminalInteractiveShell.term_title = False,
143 config.TerminalInteractiveShell.autocall = 0
144 config.TerminalInteractiveShell.autocall = 0
144 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
145 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
145 config.HistoryManager.hist_file = f.name
146 config.HistoryManager.hist_file = Path(f.name)
146 f.close()
147 f.close()
147 config.HistoryManager.db_cache_size = 10000
148 config.HistoryManager.db_cache_size = 10000
148 return config
149 return config
General Comments 0
You need to be logged in to leave comments. Login now