diff --git a/Doc/library/site.rst b/Doc/library/site.rst index 44f90a3b9e496f..0996f6f5f2ee96 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -144,15 +144,25 @@ Readline configuration On systems that support :mod:`readline`, this module will also import and configure the :mod:`rlcompleter` module, if Python is started in :ref:`interactive mode ` and without the :option:`-S` option. -The default behavior is enable tab-completion and to use -:file:`~/.python_history` as the history save file. To disable it, delete (or -override) the :data:`sys.__interactivehook__` attribute in your +The default behavior is enable tab-completion and to use history file from +platform defined directory. +For Windows, it is :file:`%APPDATA%\\Python\\history`; +for Mac OS, it is :file:`~/Library/Application Support/Python/history`; +for other POSIX platforms, it is :file:`$XDG_STATE_HOME/python/history` or +:file:`~/.local/state/python/history`; +otherwise, it is :file:`~/.python_history`. +Note that for compatibility, if :file:`~/.python_history` is readable, it will +always be taken as default and other paths are ignored. To disable it, delete +(or override) the :data:`sys.__interactivehook__` attribute in your :mod:`sitecustomize` or :mod:`usercustomize` module or your :envvar:`PYTHONSTARTUP` file. .. versionchanged:: 3.4 Activation of rlcompleter and history was made automatic. +.. versionchanged:: 3.13 + Prefer platform defined data directory instead of :file:`~/.python_history`. + Module contents --------------- diff --git a/Doc/tutorial/interactive.rst b/Doc/tutorial/interactive.rst index c0eb1feec4eb4d..208421a8c303d2 100644 --- a/Doc/tutorial/interactive.rst +++ b/Doc/tutorial/interactive.rst @@ -25,7 +25,11 @@ the expression up to the final ``'.'`` and then suggest completions from the attributes of the resulting object. Note that this may execute application-defined code if an object with a :meth:`__getattr__` method is part of the expression. The default configuration also saves your -history into a file named :file:`.python_history` in your user directory. +history into a file under platform defined data directory ( +:file:`%APPDATA%\\Python\\history` for Windows; +:file:`~/Library/Application Support/Python/history` for Mac OS; +:file:`$XDG_STATE_HOME/python/history` or +:file:`~/.local/state/python/history` for other POSIX platforms like Linux). The history will be available again during the next interactive interpreter session. diff --git a/Lib/site.py b/Lib/site.py index 672fa7b000ad02..b2e300296804cc 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -430,7 +430,7 @@ def enablerlcompleter(): registering a sys.__interactivehook__. If the readline module can be imported, the hook will set the Tab key - as completion key and register ~/.python_history as history file. + as completion key and register history file. This can be overridden in the sitecustomize or usercustomize module, or in a PYTHONSTARTUP file. """ @@ -460,14 +460,18 @@ def register_readline(): pass if readline.get_current_history_length() == 0: - # If no history was loaded, default to .python_history. + # If no history was loaded, load history file from + # platform defined directories. # The guard is necessary to avoid doubling history size at # each interpreter exit when readline was already configured # through a PYTHONSTARTUP hook, see: # http://bugs.python.org/issue5845#msg198636 - history = os.path.join(os.path.expanduser('~'), - '.python_history') + + history = get_readline_history_path() + history = os.path.abspath(history) try: + _dir, _ = os.path.split(history) + os.makedirs(_dir, exist_ok=True) readline.read_history_file(history) except OSError: pass @@ -482,6 +486,30 @@ def write_history(): atexit.register(write_history) + def get_readline_history_path(): + def joinuser(*args): + return os.path.expanduser(os.path.join(*args)) + + # If the legacy path "~/.python_history" is readable, always use it. + legacy = joinuser('~', '.python_history') + if os.access(legacy, os.R_OK): + return legacy + + # Otherwise, use platform defined data directory. + if os.name == 'nt': + base = os.environ.get('APPDATA') or '~' + return joinuser(base, 'Python', 'history') + + if sys.platform == 'darwin': + return joinuser('~', 'Library', 'Application Support', 'Python', 'history') + + if os.name == 'posix': + base = os.environ.get('XDG_STATE_HOME') or joinuser('~', '.local', 'state') + return joinuser(base, 'python', 'history') + + # Unknown platform, use the legacy path. + return legacy + sys.__interactivehook__ = register_readline def venv(known_paths): diff --git a/Misc/NEWS.d/next/Library/2021-05-26-19-13-49.bpo-44239.AN0IcD.rst b/Misc/NEWS.d/next/Library/2021-05-26-19-13-49.bpo-44239.AN0IcD.rst new file mode 100644 index 00000000000000..966aab117a2829 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-05-26-19-13-49.bpo-44239.AN0IcD.rst @@ -0,0 +1 @@ +Use platform defined data directories instead of :file:`~/.python_history`