diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 6c07f536..46372c2a 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -11,8 +11,8 @@ jobs: mypy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 # https://github.com/actions/checkout - - uses: actions/setup-python@v5 # https://github.com/actions/setup-python + - uses: actions/checkout@v4 # https://github.com/actions/checkout + - uses: actions/setup-python@v5 # https://github.com/actions/setup-python with: python-version: 3.13 allow-prereleases: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 417d9b42..c7a0dcd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 2.5.1 (November TBD, 2024) +* Bug Fixes + * Fixed readline bug when using `ipy` command with `gnureadline` and Python 3.13 + ## 2.5.0 (October 23, 2024) * Breaking Change * `cmd2` 2.5 supports Python 3.8+ (removed support for Python 3.6 and 3.7) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index dbd99349..a508f305 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -128,6 +128,13 @@ StatementParser, shlex_split, ) + +# NOTE: When using gnureadline with Python 3.13, start_ipython needs to be imported before any readline-related stuff +try: + from IPython import start_ipython # type: ignore[import] +except ImportError: + pass + from .rl_utils import ( RlType, rl_escape_prompt, @@ -4629,9 +4636,13 @@ def do_ipy(self, _: argparse.Namespace) -> Optional[bool]: # pragma: no cover # Detect whether IPython is installed try: import traitlets.config.loader as TraitletsLoader # type: ignore[import] - from IPython import ( # type: ignore[import] - start_ipython, - ) + + # Allow users to install ipython from a cmd2 prompt when needed and still have ipy command work + try: + start_ipython # noqa F823 + except NameError: + from IPython import start_ipython # type: ignore[import] + from IPython.terminal.interactiveshell import ( # type: ignore[import] TerminalInteractiveShell, ) diff --git a/cmd2/parsing.py b/cmd2/parsing.py old mode 100755 new mode 100644 diff --git a/examples/argparse_completion.py b/examples/argparse_completion.py old mode 100644 new mode 100755 diff --git a/examples/default_categories.py b/examples/default_categories.py old mode 100644 new mode 100755 diff --git a/examples/modular_commands_basic.py b/examples/modular_commands_basic.py old mode 100644 new mode 100755 diff --git a/examples/modular_commands_dynamic.py b/examples/modular_commands_dynamic.py old mode 100644 new mode 100755 diff --git a/examples/modular_commands_main.py b/examples/modular_commands_main.py old mode 100644 new mode 100755 diff --git a/examples/modular_subcommands.py b/examples/modular_subcommands.py old mode 100644 new mode 100755 diff --git a/examples/read_input.py b/examples/read_input.py old mode 100644 new mode 100755 diff --git a/tasks.py b/tasks.py index 1226c6bf..2fa88cf5 100644 --- a/tasks.py +++ b/tasks.py @@ -365,3 +365,13 @@ def format(context): namespace.add_task(format) + + +@invoke.task() +def ruff_clean(context): + """Remove .ruff_cache directory""" + with context.cd(TASK_ROOT_STR): + context.run("ruff clean") + + +namespace_clean.add_task(ruff_clean, 'ruff')