Skip to content

Commit

Permalink
cmd2 now uses pyreadline3 when running any version of Python on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
kmvanbrunt committed Feb 17, 2022
1 parent 07f059c commit 4621b05
Show file tree
Hide file tree
Showing 9 changed files with 23 additions and 58 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Enhancements
* Added broader exception handling when enabling clipboard functionality via `pyperclip`.
* Added `PassThroughException` to `__init__.py` imports.
* cmd2 now uses pyreadline3 when running any version of Python on Windows
* Deletions (potentially breaking changes)
* Deleted `cmd2.fg` and `cmd2.bg` which were deprecated in 2.3.0. Use `cmd2.Fg` and `cmd2.Bg` instead.

Expand Down
3 changes: 1 addition & 2 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ ipython = "*"
isort = "*"
mock = {version = "*",markers = "python_version < '3.6'"}
mypy = "*"
pyreadline = {version = "*",sys_platform = "== 'win32'",markers = "python_version < '3.8'"}
pyreadline3 = {version = "*",sys_platform = "== 'win32'",markers = "python_version >= '3.8'"}
pyreadline3 = {version = ">=3.4",sys_platform = "== 'win32'"}
pytest = "*"
pytest-cov = "*"
pytest-mock = "*"
Expand Down
8 changes: 4 additions & 4 deletions cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@

if rl_type == RlType.PYREADLINE:

# Save the original pyreadline display completion function since we need to override it and restore it
# Save the original pyreadline3 display completion function since we need to override it and restore it
# noinspection PyProtectedMember,PyUnresolvedReferences
orig_pyreadline_display = readline.rl.mode._display_completions

Expand Down Expand Up @@ -1747,7 +1747,7 @@ def _pad_matches_to_display(matches_to_display: List[str]) -> Tuple[List[str], i
padding = 2 * ' '

elif rl_type == RlType.PYREADLINE:
# Add 3 to the padding of 1 that pyreadline uses for a total of 4.
# Add 3 to the padding of 1 that pyreadline3 uses for a total of 4.
padding = 3 * ' '

else:
Expand Down Expand Up @@ -1820,7 +1820,7 @@ def _display_matches_gnu_readline(
rl_force_redisplay()

def _display_matches_pyreadline(self, matches: List[str]) -> None: # pragma: no cover
"""Prints a match list using pyreadline's _display_completions()
"""Prints a match list using pyreadline3's _display_completions()
:param matches: the tab completion matches to display
"""
Expand All @@ -1841,7 +1841,7 @@ def _display_matches_pyreadline(self, matches: List[str]) -> None: # pragma: no
# Redraw the prompt and input lines
rl_force_redisplay()

# Otherwise use pyreadline's formatter
# Otherwise use pyreadline3's formatter
else:
# Check if we should show display_matches
if self.display_matches:
Expand Down
15 changes: 7 additions & 8 deletions cmd2/rl_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@
# The workaround for Python environments using libedit is to install the gnureadline Python library.
#########################################################################################################################

# Prefer statically linked gnureadline if available due to issues with libedit
# Prefer statically linked gnureadline if installed due to compatibility issues with libedit
try:
# noinspection PyPackageRequirements
import gnureadline as readline # type: ignore[import]
except ImportError:
# Try to import readline, but allow failure for convenience in Windows unit testing.
# Note: If this actually fails, you should install gnureadline on Linux/Mac or pyreadline on Windows.
# Note: If this actually fails, you should install gnureadline on Linux/Mac or pyreadline3 on Windows.
try:
# noinspection PyUnresolvedReferences
import readline # type: ignore[no-redef]
Expand All @@ -57,8 +56,8 @@ class RlType(Enum):
# Explanation for why Readline wasn't loaded
_rl_warn_reason = ''

# The order of this check matters since importing pyreadline/pyreadline3 will also show readline in the modules list
if 'pyreadline' in sys.modules or 'pyreadline3' in sys.modules:
# The order of this check matters since importing pyreadline3 will also show readline in the modules list
if 'pyreadline3' in sys.modules:
rl_type = RlType.PYREADLINE

import atexit
Expand Down Expand Up @@ -109,7 +108,7 @@ def enable_win_vt100(handle: HANDLE) -> bool:
vt100_support = vt100_stdout_support and vt100_stderr_support

############################################################################################################
# pyreadline is incomplete in terms of the Python readline API. Add the missing functions we need.
# pyreadline3 is incomplete in terms of the Python readline API. Add the missing functions we need.
############################################################################################################
# readline.redisplay()
try:
Expand All @@ -125,7 +124,7 @@ def enable_win_vt100(handle: HANDLE) -> bool:
# noinspection PyProtectedMember,PyUnresolvedReferences
def pyreadline_remove_history_item(pos: int) -> None:
"""
An implementation of remove_history_item() for pyreadline
An implementation of remove_history_item() for pyreadline3
:param pos: The 0-based position in history to remove
"""
# Save of the current location of the history cursor
Expand Down Expand Up @@ -162,7 +161,7 @@ def pyreadline_remove_history_item(pos: int) -> None:
if not _rl_warn_reason:
_rl_warn_reason = (
"no supported version of readline was found. To resolve this, install\n"
"pyreadline on Windows or gnureadline on Linux/Mac."
"pyreadline3 on Windows or gnureadline on Linux/Mac."
)
rl_warning = "Readline features including tab completion have been disabled because\n" + _rl_warn_reason + '\n\n'
else:
Expand Down
7 changes: 2 additions & 5 deletions docs/overview/integrating.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,10 @@ Windows Considerations

If you would like to use :ref:`features/completion:Completion`, and you want
your application to run on Windows, you will need to ensure you install the
``pyreadline3`` or ``pyreadline`` package. Make sure to include the following
``pyreadline3`` package. Make sure to include the following
in your ``setup.py``::

install_requires=[
'cmd2>=1,<2',
":sys_platform=='win32'": [
"pyreadline ; python_version<'3.8'",
"pyreadline3 ; python_version>='3.8'", # pyreadline3 is a drop-in replacement for Python 3.8 and above
],
":sys_platform=='win32'": ['pyreadline3'],
]
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@
]

EXTRAS_REQUIRE = {
# Windows also requires pyreadline or the replacement, pyreadline3, to ensure tab completion works
":sys_platform=='win32' and python_version<'3.8'": ["pyreadline"],
":sys_platform=='win32' and python_version>='3.8'": ["pyreadline3"],
# Windows also requires pyreadline3 to ensure tab completion works
":sys_platform=='win32'": ['pyreadline3'],
# Extra dependencies for running unit tests
'test': [
"gnureadline; sys_platform=='darwin'", # include gnureadline on macOS to ensure it is available in nox env
Expand Down
15 changes: 3 additions & 12 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,13 @@
)

import cmd2
from cmd2.rl_utils import (
readline,
)
from cmd2.utils import (
StdSim,
)

# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit)
try:
import gnureadline as readline
except ImportError:
# Try to import readline, but allow failure for convenience in Windows unit testing
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
try:
# noinspection PyUnresolvedReferences
import readline
except ImportError:
pass


def verify_help_text(
cmd2_app: cmd2.Cmd, help_output: Union[str, List[str]], verbose_strings: Optional[List[str]] = None
Expand Down
12 changes: 0 additions & 12 deletions tests/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,6 @@
run_cmd,
)

# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit)
try:
import gnureadline as readline
except ImportError:
# Try to import readline, but allow failure for convenience in Windows unit testing
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
try:
# noinspection PyUnresolvedReferences
import readline
except ImportError:
pass


class ArgparseApp(cmd2.Cmd):
def __init__(self):
Expand Down
15 changes: 3 additions & 12 deletions tests_isolated/test_commandset/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,13 @@
)

import cmd2
from cmd2.rl_utils import (
readline,
)
from cmd2.utils import (
StdSim,
)

# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit)
try:
import gnureadline as readline
except ImportError:
# Try to import readline, but allow failure for convenience in Windows unit testing
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
try:
# noinspection PyUnresolvedReferences
import readline
except ImportError:
pass


def verify_help_text(
cmd2_app: cmd2.Cmd, help_output: Union[str, List[str]], verbose_strings: Optional[List[str]] = None
Expand Down

0 comments on commit 4621b05

Please sign in to comment.