Skip to content

Commit

Permalink
Fix history: do not nuke on errors, fix encoding for py3 (#4)
Browse files Browse the repository at this point in the history
* write_history_file: do not nuke history on errors

* Pick write_history_file encoding fix from PyPy (py3.6)
  • Loading branch information
blueyed authored Apr 24, 2019
1 parent baf30dd commit 9df1fcb
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 7 deletions.
20 changes: 13 additions & 7 deletions pyrepl/readline.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,21 @@ def read_history_file(self, filename='~/.history'):
def write_history_file(self, filename='~/.history'):
maxlength = self.saved_history_length
history = self.get_reader().get_trimmed_history(maxlength)
f = open(os.path.expanduser(filename), 'w')
entries = ''
for entry in history:
if isinstance(entry, unicode):
try:
entry = entry.encode(ENCODING)
except UnicodeEncodeError: # bah, silently fall back...
entry = entry.encode('utf-8')
# if we are on py3k, we don't need to encode strings before
# writing it to a file
if isinstance(entry, unicode) and sys.version_info < (3,):
entry = entry.encode('utf-8')
entry = entry.replace('\n', '\r\n') # multiline history support
f.write(entry + '\n')
entries += entry + '\n'

fname = os.path.expanduser(filename)
if PY3:
f = open(fname, 'w', encoding='utf-8')
else:
f = open(fname, 'w')
f.write(entries)
f.close()

def clear_history(self):
Expand Down
37 changes: 37 additions & 0 deletions testing/test_readline.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,40 @@ def test_read_history_file(readline_wrapper, tmp_path):
histfile.write_bytes(b"foo\nbar\n")
readline_wrapper.read_history_file(str(histfile))
assert readline_wrapper.reader.history == ["foo", "bar"]


def test_write_history_file(readline_wrapper, tmp_path):
histfile = tmp_path / "history"

reader = readline_wrapper.get_reader()
history = reader.history
assert history == []
history.extend(["foo", "bar"])

readline_wrapper.write_history_file(str(histfile))

assert open(str(histfile), "r").readlines() == ["foo\n", "bar\n"]


def test_write_history_file_with_exception(readline_wrapper, tmp_path):
"""The history file should not get nuked on inner exceptions.
This was the case with unicode decoding previously."""
histfile = tmp_path / "history"
histfile.write_bytes(b"foo\nbar\n")

class BadEntryException(Exception):
pass

class BadEntry(object):
@classmethod
def replace(cls, *args):
raise BadEntryException

history = readline_wrapper.get_reader().history
history.extend([BadEntry])

with pytest.raises(BadEntryException):
readline_wrapper.write_history_file(str(histfile))

assert open(str(histfile), "r").readlines() == ["foo\n", "bar\n"]

0 comments on commit 9df1fcb

Please sign in to comment.