[Python-checkins] cpython: add readline.append_history_file (closes #22940)
benjamin.peterson
python-checkins at python.org
Wed Nov 26 20:58:41 CET 2014
https://hg.python.org/cpython/rev/ff00588791be
changeset: 93601:ff00588791be
parent: 93597:21d1571c0533
user: Benjamin Peterson <benjamin at python.org>
date: Wed Nov 26 13:58:16 2014 -0600
summary:
add readline.append_history_file (closes #22940)
patch by "bru"
files:
Doc/library/readline.rst | 29 ++++++++++++++++++-
Lib/test/test_readline.py | 40 ++++++++++++++++++++++++++-
Misc/NEWS | 2 +
Modules/readline.c | 37 ++++++++++++++++++++++++
4 files changed, 106 insertions(+), 2 deletions(-)
diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst
--- a/Doc/library/readline.rst
+++ b/Doc/library/readline.rst
@@ -59,6 +59,14 @@
Save a readline history file. The default filename is :file:`~/.history`.
+.. function:: append_history_file(nelements[, filename])
+
+ Append the last *nelements* of history to a file. The default filename is
+ :file:`~/.history`. The file must already exist.
+
+ .. versionadded:: 3.5
+
+
.. function:: clear_history()
Clear the current history. (Note: this function is not available if the
@@ -209,6 +217,26 @@
This code is actually automatically run when Python is run in
:ref:`interactive mode <tut-interactive>` (see :ref:`rlcompleter-config`).
+The following example achieves the same goal but supports concurrent interactive
+sessions, by only appending the new history. ::
+
+ import atexit
+ import os
+ import realine
+ histfile = os.path.join(os.path.expanduser("~"), ".python_history")
+
+ try:
+ readline.read_history_file(histfile)
+ h_len = readline.get_history_length()
+ except FileNotFoundError:
+ open(histfile, 'wb').close()
+ h_len = 0
+
+ def save(prev_h_len, histfile):
+ new_h_len = readline.get_history_length()
+ readline.append_history_file(new_h_len - prev_h_len, histfile)
+ atexit.register(save, h_len, histfile)
+
The following example extends the :class:`code.InteractiveConsole` class to
support history save/restore. ::
@@ -234,4 +262,3 @@
def save_history(self, histfile):
readline.write_history_file(histfile)
-
diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py
--- a/Lib/test/test_readline.py
+++ b/Lib/test/test_readline.py
@@ -2,8 +2,9 @@
Very minimal unittests for parts of the readline module.
"""
import os
+import tempfile
import unittest
-from test.support import run_unittest, import_module
+from test.support import run_unittest, import_module, unlink
from test.script_helper import assert_python_ok
# Skip tests if there is no readline module
@@ -42,6 +43,43 @@
self.assertEqual(readline.get_current_history_length(), 1)
+ def test_write_read_append(self):
+ hfile = tempfile.NamedTemporaryFile(delete=False)
+ hfile.close()
+ hfilename = hfile.name
+ self.addCleanup(unlink, hfilename)
+
+ # test write-clear-read == nop
+ readline.clear_history()
+ readline.add_history("first line")
+ readline.add_history("second line")
+ readline.write_history_file(hfilename)
+
+ readline.clear_history()
+ self.assertEqual(readline.get_current_history_length(), 0)
+
+ readline.read_history_file(hfilename)
+ self.assertEqual(readline.get_current_history_length(), 2)
+ self.assertEqual(readline.get_history_item(1), "first line")
+ self.assertEqual(readline.get_history_item(2), "second line")
+
+ # test append
+ readline.append_history_file(1, hfilename)
+ readline.clear_history()
+ readline.read_history_file(hfilename)
+ self.assertEqual(readline.get_current_history_length(), 3)
+ self.assertEqual(readline.get_history_item(1), "first line")
+ self.assertEqual(readline.get_history_item(2), "second line")
+ self.assertEqual(readline.get_history_item(3), "second line")
+
+ # test 'no such file' behaviour
+ os.unlink(hfilename)
+ with self.assertRaises(FileNotFoundError):
+ readline.append_history_file(1, hfilename)
+
+ # write_history_file can create the target
+ readline.write_history_file(hfilename)
+
class TestReadline(unittest.TestCase):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -191,6 +191,8 @@
Library
-------
+- Issue #22940: Add readline.append_history_file.
+
- Issue #19676: Added the "namereplace" error handler.
- Issue #22788: Add *context* parameter to logging.handlers.HTTPHandler.
diff --git a/Modules/readline.c b/Modules/readline.c
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -237,6 +237,41 @@
The default filename is ~/.history.");
+/* Exported function to save part of a readline history file */
+
+static PyObject *
+append_history_file(PyObject *self, PyObject *args)
+{
+ int nelements;
+ PyObject *filename_obj = Py_None, *filename_bytes;
+ char *filename;
+ int err;
+ if (!PyArg_ParseTuple(args, "i|O:append_history_file", &nelements, &filename_obj))
+ return NULL;
+ if (filename_obj != Py_None) {
+ if (!PyUnicode_FSConverter(filename_obj, &filename_bytes))
+ return NULL;
+ filename = PyBytes_AsString(filename_bytes);
+ } else {
+ filename_bytes = NULL;
+ filename = NULL;
+ }
+ errno = err = append_history(nelements, filename);
+ if (!err && _history_length >= 0)
+ history_truncate_file(filename, _history_length);
+ Py_XDECREF(filename_bytes);
+ errno = err;
+ if (errno)
+ return PyErr_SetFromErrno(PyExc_IOError);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(doc_append_history_file,
+"append_history_file(nelements[, filename]) -> None\n\
+Append the last nelements of the history list to file.\n\
+The default filename is ~/.history.");
+
+
/* Set history length */
static PyObject*
@@ -747,6 +782,8 @@
METH_VARARGS, doc_read_history_file},
{"write_history_file", write_history_file,
METH_VARARGS, doc_write_history_file},
+ {"append_history_file", append_history_file,
+ METH_VARARGS, doc_append_history_file},
{"get_history_item", get_history_item,
METH_VARARGS, doc_get_history_item},
{"get_current_history_length", (PyCFunction)get_current_history_length,
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list