##// END OF EJS Templates
Merge pull request #13719 from balval/gh-13666...
Matthias Bussonnier -
r27745:3df473c5 merge
parent child Browse files
Show More
@@ -202,7 +202,6 b' class HistoryAccessor(HistoryAccessorBase):'
202 config : :class:`~traitlets.config.loader.Config`
202 config : :class:`~traitlets.config.loader.Config`
203 Config object. hist_file can also be set through this.
203 Config object. hist_file can also be set through this.
204 """
204 """
205 # We need a pointer back to the shell for various tasks.
206 super(HistoryAccessor, self).__init__(**traits)
205 super(HistoryAccessor, self).__init__(**traits)
207 # defer setting hist_file from kwarg until after init,
206 # defer setting hist_file from kwarg until after init,
208 # otherwise the default kwarg value would clobber any value
207 # otherwise the default kwarg value would clobber any value
@@ -344,11 +343,6 b' class HistoryAccessor(HistoryAccessorBase):'
344 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
343 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
345 """Get the last n lines from the history database.
344 """Get the last n lines from the history database.
346
345
347 Most recent entry last.
348
349 Completion will be reordered so that that the last ones are when
350 possible from current session.
351
352 Parameters
346 Parameters
353 ----------
347 ----------
354 n : int
348 n : int
@@ -367,31 +361,12 b' class HistoryAccessor(HistoryAccessorBase):'
367 self.writeout_cache()
361 self.writeout_cache()
368 if not include_latest:
362 if not include_latest:
369 n += 1
363 n += 1
370 # cursor/line/entry
364 cur = self._run_sql(
371 this_cur = list(
365 "ORDER BY session DESC, line DESC LIMIT ?", (n,), raw=raw, output=output
372 self._run_sql(
373 "WHERE session == ? ORDER BY line DESC LIMIT ? ",
374 (self.session_number, n),
375 raw=raw,
376 output=output,
377 )
378 )
379 other_cur = list(
380 self._run_sql(
381 "WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
382 (self.session_number, n),
383 raw=raw,
384 output=output,
385 )
386 )
366 )
387
388 everything = this_cur + other_cur
389
390 everything = everything[:n]
391
392 if not include_latest:
367 if not include_latest:
393 return list(everything)[:0:-1]
368 return reversed(list(cur)[1:])
394 return list(everything)[::-1]
369 return reversed(list(cur))
395
370
396 @catch_corrupt_db
371 @catch_corrupt_db
397 def search(self, pattern="*", raw=True, search_raw=True,
372 def search(self, pattern="*", raw=True, search_raw=True,
@@ -560,7 +535,6 b' class HistoryManager(HistoryAccessor):'
560 def __init__(self, shell=None, config=None, **traits):
535 def __init__(self, shell=None, config=None, **traits):
561 """Create a new history manager associated with a shell instance.
536 """Create a new history manager associated with a shell instance.
562 """
537 """
563 # We need a pointer back to the shell for various tasks.
564 super(HistoryManager, self).__init__(shell=shell, config=config,
538 super(HistoryManager, self).__init__(shell=shell, config=config,
565 **traits)
539 **traits)
566 self.save_flag = threading.Event()
540 self.save_flag = threading.Event()
@@ -656,6 +630,59 b' class HistoryManager(HistoryAccessor):'
656
630
657 return super(HistoryManager, self).get_session_info(session=session)
631 return super(HistoryManager, self).get_session_info(session=session)
658
632
633 @catch_corrupt_db
634 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
635 """Get the last n lines from the history database.
636
637 Most recent entry last.
638
639 Completion will be reordered so that that the last ones are when
640 possible from current session.
641
642 Parameters
643 ----------
644 n : int
645 The number of lines to get
646 raw, output : bool
647 See :meth:`get_range`
648 include_latest : bool
649 If False (default), n+1 lines are fetched, and the latest one
650 is discarded. This is intended to be used where the function
651 is called by a user command, which it should not return.
652
653 Returns
654 -------
655 Tuples as :meth:`get_range`
656 """
657 self.writeout_cache()
658 if not include_latest:
659 n += 1
660 # cursor/line/entry
661 this_cur = list(
662 self._run_sql(
663 "WHERE session == ? ORDER BY line DESC LIMIT ? ",
664 (self.session_number, n),
665 raw=raw,
666 output=output,
667 )
668 )
669 other_cur = list(
670 self._run_sql(
671 "WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
672 (self.session_number, n),
673 raw=raw,
674 output=output,
675 )
676 )
677
678 everything = this_cur + other_cur
679
680 everything = everything[:n]
681
682 if not include_latest:
683 return list(everything)[:0:-1]
684 return list(everything)[::-1]
685
659 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
686 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
660 """Get input and output history from the current session. Called by
687 """Get input and output history from the current session. Called by
661 get_range, and takes similar parameters."""
688 get_range, and takes similar parameters."""
@@ -17,7 +17,7 b' from tempfile import TemporaryDirectory'
17 # our own packages
17 # our own packages
18 from traitlets.config.loader import Config
18 from traitlets.config.loader import Config
19
19
20 from IPython.core.history import HistoryManager, extract_hist_ranges
20 from IPython.core.history import HistoryAccessor, HistoryManager, extract_hist_ranges
21
21
22
22
23 def test_proper_default_encoding():
23 def test_proper_default_encoding():
@@ -227,3 +227,81 b' def test_histmanager_disabled():'
227
227
228 # hist_file should not be created
228 # hist_file should not be created
229 assert hist_file.exists() is False
229 assert hist_file.exists() is False
230
231
232 def test_get_tail_session_awareness():
233 """Test .get_tail() is:
234 - session specific in HistoryManager
235 - session agnostic in HistoryAccessor
236 same for .get_last_session_id()
237 """
238 ip = get_ipython()
239 with TemporaryDirectory() as tmpdir:
240 tmp_path = Path(tmpdir)
241 hist_file = tmp_path / "history.sqlite"
242 get_source = lambda x: x[2]
243 hm1 = None
244 hm2 = None
245 ha = None
246 try:
247 # hm1 creates a new session and adds history entries,
248 # ha catches up
249 hm1 = HistoryManager(shell=ip, hist_file=hist_file)
250 hm1_last_sid = hm1.get_last_session_id
251 ha = HistoryAccessor(hist_file=hist_file)
252 ha_last_sid = ha.get_last_session_id
253
254 hist1 = ["a=1", "b=1", "c=1"]
255 for i, h in enumerate(hist1 + [""], start=1):
256 hm1.store_inputs(i, h)
257 assert list(map(get_source, hm1.get_tail())) == hist1
258 assert list(map(get_source, ha.get_tail())) == hist1
259 sid1 = hm1_last_sid()
260 assert sid1 is not None
261 assert ha_last_sid() == sid1
262
263 # hm2 creates a new session and adds entries,
264 # ha catches up
265 hm2 = HistoryManager(shell=ip, hist_file=hist_file)
266 hm2_last_sid = hm2.get_last_session_id
267
268 hist2 = ["a=2", "b=2", "c=2"]
269 for i, h in enumerate(hist2 + [""], start=1):
270 hm2.store_inputs(i, h)
271 tail = hm2.get_tail(n=3)
272 assert list(map(get_source, tail)) == hist2
273 tail = ha.get_tail(n=3)
274 assert list(map(get_source, tail)) == hist2
275 sid2 = hm2_last_sid()
276 assert sid2 is not None
277 assert ha_last_sid() == sid2
278 assert sid2 != sid1
279
280 # but hm1 still maintains its point of reference
281 # and adding more entries to it doesn't change others
282 # immediate perspective
283 assert hm1_last_sid() == sid1
284 tail = hm1.get_tail(n=3)
285 assert list(map(get_source, tail)) == hist1
286
287 hist3 = ["a=3", "b=3", "c=3"]
288 for i, h in enumerate(hist3 + [""], start=5):
289 hm1.store_inputs(i, h)
290 tail = hm1.get_tail(n=7)
291 assert list(map(get_source, tail)) == hist1 + [""] + hist3
292 tail = hm2.get_tail(n=3)
293 assert list(map(get_source, tail)) == hist2
294 tail = ha.get_tail(n=3)
295 assert list(map(get_source, tail)) == hist2
296 assert hm1_last_sid() == sid1
297 assert hm2_last_sid() == sid2
298 assert ha_last_sid() == sid2
299 finally:
300 if hm1:
301 hm1.save_thread.stop()
302 hm1.db.close()
303 if hm2:
304 hm2.save_thread.stop()
305 hm2.db.close()
306 if ha:
307 ha.db.close()
General Comments 0
You need to be logged in to leave comments. Login now