Show More
@@ -202,7 +202,6 class HistoryAccessor(HistoryAccessorBase): | |||
|
202 | 202 | config : :class:`~traitlets.config.loader.Config` |
|
203 | 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 | 205 | super(HistoryAccessor, self).__init__(**traits) |
|
207 | 206 | # defer setting hist_file from kwarg until after init, |
|
208 | 207 | # otherwise the default kwarg value would clobber any value |
@@ -344,11 +343,6 class HistoryAccessor(HistoryAccessorBase): | |||
|
344 | 343 | def get_tail(self, n=10, raw=True, output=False, include_latest=False): |
|
345 | 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 | 346 | Parameters |
|
353 | 347 | ---------- |
|
354 | 348 | n : int |
@@ -367,31 +361,12 class HistoryAccessor(HistoryAccessorBase): | |||
|
367 | 361 | self.writeout_cache() |
|
368 | 362 | if not include_latest: |
|
369 | 363 | n += 1 |
|
370 | # cursor/line/entry | |
|
371 | this_cur = list( | |
|
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 | ) | |
|
364 | cur = self._run_sql( | |
|
365 | "ORDER BY session DESC, line DESC LIMIT ?", (n,), raw=raw, output=output | |
|
386 | 366 | ) |
|
387 | ||
|
388 | everything = this_cur + other_cur | |
|
389 | ||
|
390 | everything = everything[:n] | |
|
391 | ||
|
392 | 367 | if not include_latest: |
|
393 |
return list( |
|
|
394 |
return list( |
|
|
368 | return reversed(list(cur)[1:]) | |
|
369 | return reversed(list(cur)) | |
|
395 | 370 | |
|
396 | 371 | @catch_corrupt_db |
|
397 | 372 | def search(self, pattern="*", raw=True, search_raw=True, |
@@ -560,7 +535,6 class HistoryManager(HistoryAccessor): | |||
|
560 | 535 | def __init__(self, shell=None, config=None, **traits): |
|
561 | 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 | 538 | super(HistoryManager, self).__init__(shell=shell, config=config, |
|
565 | 539 | **traits) |
|
566 | 540 | self.save_flag = threading.Event() |
@@ -656,6 +630,59 class HistoryManager(HistoryAccessor): | |||
|
656 | 630 | |
|
657 | 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 | 686 | def _get_range_session(self, start=1, stop=None, raw=True, output=False): |
|
660 | 687 | """Get input and output history from the current session. Called by |
|
661 | 688 | get_range, and takes similar parameters.""" |
@@ -17,7 +17,7 from tempfile import TemporaryDirectory | |||
|
17 | 17 | # our own packages |
|
18 | 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 | 23 | def test_proper_default_encoding(): |
@@ -227,3 +227,81 def test_histmanager_disabled(): | |||
|
227 | 227 | |
|
228 | 228 | # hist_file should not be created |
|
229 | 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