Thanks to visit codestin.com
Credit goes to github.com

Skip to content

readline.set_history_length corrupts history files when used in a libedit build #121160

Closed
@whitequark

Description

@whitequark

Bug report

Bug description:

Since the libedit transition (correction: If an end user switches from a GNU readline build of Python to an editline build of Python), several important functions related to history files are broken.

  1. It is inconvenient enough that history files written by GNU readline based readline module are unreadable and result in a rather confusing OSError with exc.errno == errno.EINVAL (without a corresponding operating system routine that returns such an error), but a workaround intercepting this OSError can be written that converts the old format to the new one. This has been covered before, e.g. in The New REPL Does Not Load My Command History #120766.
  2. More importantly, history files written by libedit based readline module are unreadable by itself when set_history_length is used, as demonstrated by the code below.
  3. While a workaround for that is also possible (also below), as far as I can tell, until 3.13, so until a year from now (?) (whenever Add readline.backend for the backend readline uses #112510 becomes available in a release), your only option is "libedit" in readline.__doc__, which I expect will be what many people will leave in the codebase even once readline.backend becomes available.

Reproducer:

import readline

readline.add_history("foo bar")
readline.add_history("nope nope")
readline.write_history_file("history-works")

# this works:
readline.read_history_file("history-works")

readline.set_history_length(2)
readline.write_history_file("history-breaks")

# this breaks:
readline.read_history_file("history-breaks")

Workaround:

def _is_using_libedit():
    if hasattr(readline, "backend"):
        return readline.backend == "editline"
    else:
        return "libedit" in readline.__doc__

readline.set_history_length(1000)
if _is_using_libedit():
    readline.replace_history_item(
        max(0, readline.get_current_history_length() - readline.get_history_length()),
        "_HiStOrY_V2_")

CPython versions tested on:

3.12

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic-replRelated to the interactive shelltype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions