Skip to content

Commit 4621b05

Browse files
committed
cmd2 now uses pyreadline3 when running any version of Python on Windows
1 parent 07f059c commit 4621b05

File tree

9 files changed

+23
-58
lines changed

9 files changed

+23
-58
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Enhancements
66
* Added broader exception handling when enabling clipboard functionality via `pyperclip`.
77
* Added `PassThroughException` to `__init__.py` imports.
8+
* cmd2 now uses pyreadline3 when running any version of Python on Windows
89
* Deletions (potentially breaking changes)
910
* Deleted `cmd2.fg` and `cmd2.bg` which were deprecated in 2.3.0. Use `cmd2.Fg` and `cmd2.Bg` instead.
1011

Pipfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ ipython = "*"
2222
isort = "*"
2323
mock = {version = "*",markers = "python_version < '3.6'"}
2424
mypy = "*"
25-
pyreadline = {version = "*",sys_platform = "== 'win32'",markers = "python_version < '3.8'"}
26-
pyreadline3 = {version = "*",sys_platform = "== 'win32'",markers = "python_version >= '3.8'"}
25+
pyreadline3 = {version = ">=3.4",sys_platform = "== 'win32'"}
2726
pytest = "*"
2827
pytest-cov = "*"
2928
pytest-mock = "*"

cmd2/cmd2.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155

156156
if rl_type == RlType.PYREADLINE:
157157

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

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

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

17531753
else:
@@ -1820,7 +1820,7 @@ def _display_matches_gnu_readline(
18201820
rl_force_redisplay()
18211821

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

1844-
# Otherwise use pyreadline's formatter
1844+
# Otherwise use pyreadline3's formatter
18451845
else:
18461846
# Check if we should show display_matches
18471847
if self.display_matches:

cmd2/rl_utils.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@
2626
# The workaround for Python environments using libedit is to install the gnureadline Python library.
2727
#########################################################################################################################
2828

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

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

6463
import atexit
@@ -109,7 +108,7 @@ def enable_win_vt100(handle: HANDLE) -> bool:
109108
vt100_support = vt100_stdout_support and vt100_stderr_support
110109

111110
############################################################################################################
112-
# pyreadline is incomplete in terms of the Python readline API. Add the missing functions we need.
111+
# pyreadline3 is incomplete in terms of the Python readline API. Add the missing functions we need.
113112
############################################################################################################
114113
# readline.redisplay()
115114
try:
@@ -125,7 +124,7 @@ def enable_win_vt100(handle: HANDLE) -> bool:
125124
# noinspection PyProtectedMember,PyUnresolvedReferences
126125
def pyreadline_remove_history_item(pos: int) -> None:
127126
"""
128-
An implementation of remove_history_item() for pyreadline
127+
An implementation of remove_history_item() for pyreadline3
129128
:param pos: The 0-based position in history to remove
130129
"""
131130
# Save of the current location of the history cursor
@@ -162,7 +161,7 @@ def pyreadline_remove_history_item(pos: int) -> None:
162161
if not _rl_warn_reason:
163162
_rl_warn_reason = (
164163
"no supported version of readline was found. To resolve this, install\n"
165-
"pyreadline on Windows or gnureadline on Linux/Mac."
164+
"pyreadline3 on Windows or gnureadline on Linux/Mac."
166165
)
167166
rl_warning = "Readline features including tab completion have been disabled because\n" + _rl_warn_reason + '\n\n'
168167
else:

docs/overview/integrating.rst

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,10 @@ Windows Considerations
2626

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

3232
install_requires=[
3333
'cmd2>=1,<2',
34-
":sys_platform=='win32'": [
35-
"pyreadline ; python_version<'3.8'",
36-
"pyreadline3 ; python_version>='3.8'", # pyreadline3 is a drop-in replacement for Python 3.8 and above
37-
],
34+
":sys_platform=='win32'": ['pyreadline3'],
3835
]

setup.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@
5151
]
5252

5353
EXTRAS_REQUIRE = {
54-
# Windows also requires pyreadline or the replacement, pyreadline3, to ensure tab completion works
55-
":sys_platform=='win32' and python_version<'3.8'": ["pyreadline"],
56-
":sys_platform=='win32' and python_version>='3.8'": ["pyreadline3"],
54+
# Windows also requires pyreadline3 to ensure tab completion works
55+
":sys_platform=='win32'": ['pyreadline3'],
5756
# Extra dependencies for running unit tests
5857
'test': [
5958
"gnureadline; sys_platform=='darwin'", # include gnureadline on macOS to ensure it is available in nox env

tests/conftest.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,13 @@
2121
)
2222

2323
import cmd2
24+
from cmd2.rl_utils import (
25+
readline,
26+
)
2427
from cmd2.utils import (
2528
StdSim,
2629
)
2730

28-
# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit)
29-
try:
30-
import gnureadline as readline
31-
except ImportError:
32-
# Try to import readline, but allow failure for convenience in Windows unit testing
33-
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
34-
try:
35-
# noinspection PyUnresolvedReferences
36-
import readline
37-
except ImportError:
38-
pass
39-
4031

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

tests/test_argparse.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,6 @@
1616
run_cmd,
1717
)
1818

19-
# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit)
20-
try:
21-
import gnureadline as readline
22-
except ImportError:
23-
# Try to import readline, but allow failure for convenience in Windows unit testing
24-
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
25-
try:
26-
# noinspection PyUnresolvedReferences
27-
import readline
28-
except ImportError:
29-
pass
30-
3119

3220
class ArgparseApp(cmd2.Cmd):
3321
def __init__(self):

tests_isolated/test_commandset/conftest.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,13 @@
2424
)
2525

2626
import cmd2
27+
from cmd2.rl_utils import (
28+
readline,
29+
)
2730
from cmd2.utils import (
2831
StdSim,
2932
)
3033

31-
# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit)
32-
try:
33-
import gnureadline as readline
34-
except ImportError:
35-
# Try to import readline, but allow failure for convenience in Windows unit testing
36-
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
37-
try:
38-
# noinspection PyUnresolvedReferences
39-
import readline
40-
except ImportError:
41-
pass
42-
4334

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

0 commit comments

Comments
 (0)