Skip to content

Instantly share code, notes, and snippets.

@viliampucik
Created January 11, 2021 22:02
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viliampucik/8713b09ff7e4d984b29bfcd7804dc1f4 to your computer and use it in GitHub Desktop.
Save viliampucik/8713b09ff7e4d984b29bfcd7804dc1f4 to your computer and use it in GitHub Desktop.
XDG compliant ~/.python_history
# Store interactive Python shell history in ~/.cache/python_history
# instead of ~/.python_history.
#
# Create the following .config/pythonstartup.py file
# and export its path using PYTHONSTARTUP environment variable:
#
# export PYTHONSTARTUP="${XDG_CONFIG_HOME:-$HOME/.config}/pythonstartup.py"
import atexit
import os
import readline
histfile = os.path.join(os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache")), "python_history")
try:
readline.read_history_file(histfile)
# default history len is -1 (infinite), which may grow unruly
readline.set_history_length(1000)
except FileNotFoundError:
pass
atexit.register(readline.write_history_file, histfile)
@TirtharajPramanik
Copy link

TirtharajPramanik commented May 3, 2023

COOL🎢

‼️ Error Handling:

import pathlib
...
except FileNotFoundError:
    pathlib.Path(histfile).parent.mkdir(parents=True, exist_ok=True)

@alichtman
Copy link

alichtman commented May 28, 2023

I modified your gist to use pathlib, and used the patch from @TirtharajPramanik for error handling.

$XDG_CACHE_HOME/python_history does now contain the history, however, the file ~/.python_history is still created and written to. I'm pretty sure this is because we never disable the hook to write the default history file. After disabling that, the code works as expected:

try:
    import atexit
    import os
    import sys
    from pathlib import Path
    import readline
except ImportError as e:
    print(f"Couldn't load module. {e}")
    sys.exit(1)


################
# TAB COMPLETION #
##################

try:
    readline.parse_and_bind("tab: complete")
except ImportError:
    pass


### XDG Compliant History File
# See https://gist.github.com/viliampucik/8713b09ff7e4d984b29bfcd7804dc1f4

# Destroy default history file writing hook (and also tab completion, which is why we manually added it)
if hasattr(sys, '__interactivehook__'):
    del sys.__interactivehook__


histfile = Path(os.getenv("XDG_CACHE_HOME", Path.home() / ".cache")) / "python_history"
try:
    histfile.touch(exist_ok=True)
except FileNotFoundError: # Probably the parent directory doesn't exist
    histfile.parent.mkdir(parents=True, exist_ok=True)

readline.read_history_file(histfile)
# Don't store an obscene amount of history
readline.set_history_length(5000)
atexit.register(readline.write_history_file, histfile)

@smahm006
Copy link

@alichtman the script works ty. I just changed histfile to be in XDG_STATE_HOME as that is where I keep my less and bash history.

histfile = Path(os.getenv("XDG_STATE_HOME", Path.home() / ".local" / "state")) / "python" / "python_history"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment