mirror of
				https://github.com/arcan1s/ahriman.git
				synced 2025-10-31 05:43:41 +00:00 
			
		
		
		
	fix: suppress traceback in shell if no ipython installed
Old implementation was showing import error, new implementation instead hides it behind separated call and if-else check
This commit is contained in:
		| @ -18,6 +18,7 @@ | |||||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| # | # | ||||||
| from code import InteractiveConsole | from code import InteractiveConsole | ||||||
|  | from importlib.util import find_spec | ||||||
| from typing import Any | from typing import Any | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -26,6 +27,19 @@ class InteractiveShell(InteractiveConsole): | |||||||
|     wrapper around :class:`code.InteractiveConsole` to pass :func:`interact()` to IPython shell |     wrapper around :class:`code.InteractiveConsole` to pass :func:`interact()` to IPython shell | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def has_ipython() -> bool: | ||||||
|  |         """ | ||||||
|  |         check if IPython shell is available | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             bool: ``True`` if IPython shell is available, ``False`` otherwise | ||||||
|  |         """ | ||||||
|  |         try: | ||||||
|  |             return find_spec("IPython.terminal.embed") is not None | ||||||
|  |         except ModuleNotFoundError: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|     def interact(self, *args: Any, **kwargs: Any) -> None: |     def interact(self, *args: Any, **kwargs: Any) -> None: | ||||||
|         """ |         """ | ||||||
|         pass controller to IPython shell |         pass controller to IPython shell | ||||||
| @ -34,13 +48,13 @@ class InteractiveShell(InteractiveConsole): | |||||||
|             *args(Any): positional arguments |             *args(Any): positional arguments | ||||||
|             **kwargs(Any): keyword arguments |             **kwargs(Any): keyword arguments | ||||||
|         """ |         """ | ||||||
|         try: |         if self.has_ipython(): | ||||||
|             from IPython.terminal.embed import InteractiveShellEmbed |             from IPython.terminal.embed import InteractiveShellEmbed | ||||||
|  |  | ||||||
|             shell = InteractiveShellEmbed(user_ns=self.locals)  # type: ignore[no-untyped-call] |             shell = InteractiveShellEmbed(user_ns=self.locals)  # type: ignore[no-untyped-call] | ||||||
|             shell.show_banner()  # type: ignore[no-untyped-call] |             shell.show_banner()  # type: ignore[no-untyped-call] | ||||||
|             shell.interact()  # type: ignore[no-untyped-call] |             shell.interact()  # type: ignore[no-untyped-call] | ||||||
|         except ImportError: |         else: | ||||||
|             # fallback to default |             # fallback to default | ||||||
|             import readline  # pylint: disable=unused-import |             import readline  # pylint: disable=unused-import | ||||||
|             InteractiveConsole.interact(self, *args, **kwargs) |             InteractiveConsole.interact(self, *args, **kwargs) | ||||||
|  | |||||||
| @ -1,14 +1,30 @@ | |||||||
| import pytest |  | ||||||
|  |  | ||||||
| from pytest_mock import MockerFixture | from pytest_mock import MockerFixture | ||||||
|  |  | ||||||
| from ahriman.application.interactive_shell import InteractiveShell | from ahriman.application.interactive_shell import InteractiveShell | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_has_ipython(mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must correctly check if IPython is installed | ||||||
|  |     """ | ||||||
|  |     find_spec_mock = mocker.patch("ahriman.application.interactive_shell.find_spec") | ||||||
|  |     assert InteractiveShell.has_ipython() | ||||||
|  |     find_spec_mock.assert_called_once_with("IPython.terminal.embed") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_has_ipython_module_not_found(mocker: MockerFixture) -> None: | ||||||
|  |     """ | ||||||
|  |     must return False if IPython is not installed | ||||||
|  |     """ | ||||||
|  |     mocker.patch("ahriman.application.interactive_shell.find_spec", side_effect=ModuleNotFoundError) | ||||||
|  |     assert not InteractiveShell.has_ipython() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_interact(mocker: MockerFixture) -> None: | def test_interact(mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must call IPython shell |     must call IPython shell | ||||||
|     """ |     """ | ||||||
|  |     mocker.patch("ahriman.application.interactive_shell.InteractiveShell.has_ipython", return_value=True) | ||||||
|     banner_mock = mocker.patch("IPython.terminal.embed.InteractiveShellEmbed.show_banner") |     banner_mock = mocker.patch("IPython.terminal.embed.InteractiveShellEmbed.show_banner") | ||||||
|     interact_mock = mocker.patch("IPython.terminal.embed.InteractiveShellEmbed.interact") |     interact_mock = mocker.patch("IPython.terminal.embed.InteractiveShellEmbed.interact") | ||||||
|  |  | ||||||
| @ -18,11 +34,11 @@ def test_interact(mocker: MockerFixture) -> None: | |||||||
|     interact_mock.assert_called_once_with() |     interact_mock.assert_called_once_with() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_interact_import_error(mocker: MockerFixture) -> None: | def test_interact_no_ipython(mocker: MockerFixture) -> None: | ||||||
|     """ |     """ | ||||||
|     must call builtin shell if no IPython available |     must call builtin shell if no IPython available | ||||||
|     """ |     """ | ||||||
|     pytest.helpers.import_error("IPython.terminal.embed", ["InteractiveShellEmbed"], mocker) |     mocker.patch("ahriman.application.interactive_shell.InteractiveShell.has_ipython", return_value=None) | ||||||
|     interact_mock = mocker.patch("code.InteractiveConsole.interact") |     interact_mock = mocker.patch("code.InteractiveConsole.interact") | ||||||
|  |  | ||||||
|     shell = InteractiveShell() |     shell = InteractiveShell() | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user