diff --git a/kasa/cli.py b/kasa/cli.py index 53c68adb..ab65c448 100755 --- a/kasa/cli.py +++ b/kasa/cli.py @@ -1081,5 +1081,26 @@ async def update_credentials(dev, username, password): return await dev.update_credentials(username, password) +@cli.command() +@pass_dev +async def shell(dev: Device): + """Open interactive shell.""" + echo("Opening shell for %s" % dev) + from ptpython.repl import embed + + logging.getLogger("parso").setLevel(logging.WARNING) # prompt parsing + logging.getLogger("asyncio").setLevel(logging.WARNING) + loop = asyncio.get_event_loop() + try: + await embed( + globals=globals(), + locals=locals(), + return_asyncio_coroutine=True, + patch_stdout=True, + ) + except EOFError: + loop.stop() + + if __name__ == "__main__": cli() diff --git a/kasa/tests/test_cli.py b/kasa/tests/test_cli.py index 2aa07382..84f016c0 100644 --- a/kasa/tests/test_cli.py +++ b/kasa/tests/test_cli.py @@ -558,3 +558,21 @@ async def test_type_param(device_type, mocker): ) assert res.exit_code == 0 assert isinstance(result_device, expected_type) + + +@pytest.mark.skip( + "Skip until pytest-asyncio supports pytest 8.0, https://github.com/pytest-dev/pytest-asyncio/issues/737" +) +async def test_shell(dev: Device, mocker): + """Test that the shell commands tries to embed a shell.""" + mocker.patch("kasa.Discover.discover", return_value=[dev]) + # repl = mocker.patch("ptpython.repl") + mocker.patch.dict( + "sys.modules", + {"ptpython": mocker.MagicMock(), "ptpython.repl": mocker.MagicMock()}, + ) + embed = mocker.patch("ptpython.repl.embed") + runner = CliRunner() + res = await runner.invoke(cli, ["shell"], obj=dev) + assert res.exit_code == 0 + embed.assert_called() diff --git a/pyproject.toml b/pyproject.toml index 70fbe07a..f4c640d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,9 @@ sphinxcontrib-programoutput = { version = "^0", optional = true } myst-parser = { version = "*", optional = true } docutils = { version = ">=0.17", optional = true } +# shell support +# ptpython = { version = "*", optional = true } + [tool.poetry.group.dev.dependencies] pytest = "*" pytest-cov = "*" @@ -57,6 +60,7 @@ coverage = {version = "*", extras = ["toml"]} [tool.poetry.extras] docs = ["sphinx", "sphinx_rtd_theme", "sphinxcontrib-programoutput", "myst-parser", "docutils"] speedups = ["orjson", "kasa-crypt"] +# shell = ["ptpython"] [tool.coverage.run] source = ["kasa"]