-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #72 from ludwigschwardt/override-readline
Override default readline via `python -m override_readline`
- Loading branch information
Showing
9 changed files
with
360 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# | ||
# Install readline override code and explain what happened. | ||
# | ||
# Run this as `python -m override_readline`, picking the appropriate Python | ||
# executable. This runs on both Python 2.7 and 3.x, hence the use of `io`, | ||
# `os.path` and explicit Unicode. | ||
# | ||
# First target sitecustomize.py (better for venvs and system-wide overrides) | ||
# and then fall back to usercustomize.py if we don't have permission. | ||
# | ||
# Based on the script in https://stackoverflow.com/a/38606990. Thanks, Alastair! | ||
# | ||
|
||
import importlib | ||
import io | ||
import os | ||
import os.path | ||
import site | ||
import sys | ||
|
||
|
||
_HEADER = """ | ||
This script will attempt to install an override in Python's site customization | ||
modules that replaces the default readline module with gnureadline. | ||
First check the existing readline module and its replacement | ||
------------------------------------------------------------ | ||
""" | ||
|
||
_REPORT = """ | ||
The following override was added to {filename}: | ||
(full path: {full_path}) | ||
{padded_override} | ||
Feel free to remove this{or_even_file} if not needed anymore | ||
(It is also pretty harmless to leave it in there...) | ||
""" | ||
|
||
OVERRIDE = u""" | ||
# Added by override_readline script in gnureadline package | ||
import sys | ||
def add_override_message_to_hook(): | ||
try: | ||
old_hook = sys.__interactivehook__ | ||
except AttributeError: | ||
return | ||
def hook(): | ||
old_hook() | ||
print("Using GNU readline instead of the default readline (see {filename})") | ||
sys.__interactivehook__ = hook | ||
try: | ||
import gnureadline as readline | ||
add_override_message_to_hook() | ||
except ImportError: | ||
import readline | ||
sys.modules["readline"] = readline | ||
# End of override_readline block | ||
""" | ||
|
||
|
||
def check_module(module_name): | ||
"""Attempt to import `module_name` and report basic features.""" | ||
try: | ||
module = importlib.import_module(module_name) | ||
except ImportError: | ||
print("Module {name}: not found".format(name=module_name)) | ||
return None | ||
style = "libedit" if "libedit" in module.__doc__ else "GNU readline" | ||
kwargs = dict(name=module_name, style=style, path=module.__file__) | ||
print("Module {name}: based on {style}, {path}".format(**kwargs)) | ||
return module | ||
|
||
|
||
def install_override(customize_path): | ||
"""Add override to specified customization module and report back.""" | ||
site_directory, customize_filename = os.path.split(customize_path) | ||
banner = "\nAdd override to {filename}\n--------------------------------\n" | ||
print(banner.format(filename=customize_filename)) | ||
if not os.path.exists(site_directory): | ||
os.makedirs(site_directory) | ||
print("Created site directory at {dir}".format(dir=site_directory)) | ||
file_mode = "r+t" if os.path.exists(customize_path) else "w+t" | ||
with io.open(customize_path, file_mode) as customize_file: | ||
if file_mode == "w+t": | ||
print("Created customize module at {path}".format(path=customize_path)) | ||
existing_text = customize_file.read() | ||
override = OVERRIDE.format(filename=customize_filename) | ||
if override in existing_text: | ||
print("Readline override already enabled, nothing to do") | ||
else: | ||
# File pointer should already be at the end of the file after read() | ||
customize_file.write(override) | ||
kwargs = dict( | ||
filename=customize_filename, | ||
full_path=customize_path, | ||
padded_override="\n ".join(override.split("\n")), | ||
or_even_file=" (or even the entire file)" if file_mode == "w+t" else "", | ||
) | ||
print(_REPORT.format(**kwargs)) | ||
|
||
|
||
def override_usercustomize(): | ||
if not site.ENABLE_USER_SITE: | ||
print( | ||
"Could not override usercustomize.py because user site " | ||
"directory is not enabled (maybe you are in a virtualenv?)" | ||
) | ||
return False | ||
try: | ||
import usercustomize | ||
except ImportError: | ||
path = os.path.join(site.getusersitepackages(), "usercustomize.py") | ||
else: | ||
path = usercustomize.__file__ | ||
try: | ||
install_override(path) | ||
except OSError: | ||
print("Could not override usercustomize.py because file open/write failed") | ||
return False | ||
else: | ||
return True | ||
|
||
|
||
def override_sitecustomize(): | ||
try: | ||
import sitecustomize | ||
except ImportError: | ||
path = os.path.join(site.getsitepackages()[0], "sitecustomize.py") | ||
else: | ||
path = sitecustomize.__file__ | ||
try: | ||
install_override(path) | ||
except OSError: | ||
print("Could not override sitecustomize.py because file open/write failed") | ||
return False | ||
else: | ||
return True | ||
|
||
|
||
def main(): | ||
print(_HEADER) | ||
readline = check_module("readline") | ||
gnureadline = check_module("gnureadline") | ||
if not gnureadline: | ||
raise RuntimeError("Please install gnureadline first") | ||
if readline == gnureadline: | ||
print("It looks like readline is already overridden, but let's make sure") | ||
success = override_usercustomize() | ||
if not success: | ||
success = override_sitecustomize() | ||
return 0 if success else 1 | ||
|
||
|
||
if __name__ == '__main__': | ||
sys.exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,19 @@ | ||
# | ||
# WARNING | ||
# ------- | ||
# | ||
# This module is meant for distributions like ActiveState Python that have | ||
# no default readline module at all. Since there is no builtin readline that | ||
# clashes with this, it is straightforward to enable readline support: | ||
# simply install gnureadline and you are done. | ||
# | ||
# If your Python ships with readline, please don't see this module as an | ||
# encouragement to move site-packages higher up in `sys.path` or to perform | ||
# any other PYTHONPATH shenanigans in order to override the system readline. | ||
# That decision will come back to haunt you. | ||
# | ||
# Instead, run the override_readline script that only overrides readline and | ||
# nothing else, using site customization. Run `python -m override_readline`. | ||
# | ||
from gnureadline import * | ||
from gnureadline import __doc__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.