From 91edec49c865c8a6ae43418990e917b65944a3ac Mon Sep 17 00:00:00 2001 From: Michael Shields Date: Thu, 18 Jun 2026 19:31:33 -0700 Subject: [PATCH] fix: move CLI dependencies from `dev` to `cli` The roborock CLI imports click, click-shell, pyyaml and pyshark, but pyyaml and pyshark were only in the dev dependency group, so a plain `pip install python-roborock` or `uvx --from python-roborock roborock` would fail. Also, click/click-shell were in the main deps but are used only by the CLI. --- README.md | 5 +++++ pyproject.toml | 16 ++++++++++++---- roborock/cli.py | 18 ++++++++++++------ uv.lock | 24 +++++++++++++++--------- 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 912e3909..bb784fff 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,11 @@ Install this via pip (or your favourite package manager): `pip install python-roborock` +To use the `roborock` command line tool, install the `cli` extra, which pulls in +its additional dependencies (click, pyyaml, pyshark): + +`pip install python-roborock[cli]` + ## Example Usage See [examples/example.py](examples/example.py) for a more full featured example, diff --git a/pyproject.toml b/pyproject.toml index e5bc0ebd..938f814a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,6 @@ classifiers = [ "Topic :: Software Development :: Libraries", ] dependencies = [ - "click>=8", "aiohttp>=3.8.2,<4", "pycryptodome~=3.18", "pycryptodomex~=3.18 ; sys_platform == 'darwin'", @@ -29,7 +28,16 @@ dependencies = [ "vacuum-map-parser-roborock", "pyrate-limiter>=4.0.0,<5", "aiomqtt>=2.5.0,<3", +] + +[project.optional-dependencies] +# Dependencies required by the `roborock` command line tool (roborock.cli). +# Install with: pip install python-roborock[cli] +cli = [ + "click>=8", "click-shell~=2.1", + "pyyaml>=6.0.3", + "pyshark>=0.6,<0.7", ] [project.urls] @@ -41,20 +49,20 @@ roborock = "roborock.cli:main" [dependency-groups] dev = [ + # Pull in the CLI dependencies so maintainers can run the `roborock` + # command and pdoc can import roborock.cli for docs generation. + "python-roborock[cli]", "pytest-asyncio>=1.1.0", "pytest", "pre-commit>=3.5,<5.0", "mypy", "ruff==0.14.11", "codespell", - "pyshark>=0.6,<0.7", "aioresponses>=0.7.7,<0.8", "freezegun>=1.5.1,<2", "pytest-timeout>=2.3.1,<3", "syrupy>=4.9.1,<6", "pdoc>=15.0.4,<17", - "pyyaml>=6.0.3", - "pyshark>=0.6", "pytest-cov>=7.0.0", ] diff --git a/roborock/cli.py b/roborock/cli.py index b36b11ce..6ae92b3a 100644 --- a/roborock/cli.py +++ b/roborock/cli.py @@ -34,12 +34,18 @@ from pathlib import Path from typing import Any, cast -import click -import click_shell -import yaml -from pyshark import FileCapture # type: ignore -from pyshark.capture.live_capture import LiveCapture, UnknownInterfaceException # type: ignore -from pyshark.packet.packet import Packet # type: ignore +try: + import click + import click_shell + import yaml + from pyshark import FileCapture # type: ignore + from pyshark.capture.live_capture import LiveCapture, UnknownInterfaceException # type: ignore + from pyshark.packet.packet import Packet # type: ignore +except ImportError as err: + raise SystemExit( + f"The 'roborock' command line tool requires extra dependencies that are not installed ({err.name}).\n" + "Install them with:\n\n pip install python-roborock[cli]\n" + ) from err from roborock import RoborockCommand from roborock.data import RoborockBase, UserData diff --git a/uv.lock b/uv.lock index 7ab97af1..3502d7c0 100644 --- a/uv.lock +++ b/uv.lock @@ -1340,8 +1340,6 @@ source = { editable = "." } dependencies = [ { name = "aiohttp" }, { name = "aiomqtt" }, - { name = "click" }, - { name = "click-shell" }, { name = "construct" }, { name = "paho-mqtt" }, { name = "protobuf" }, @@ -1351,6 +1349,14 @@ dependencies = [ { name = "vacuum-map-parser-roborock" }, ] +[package.optional-dependencies] +cli = [ + { name = "click" }, + { name = "click-shell" }, + { name = "pyshark" }, + { name = "pyyaml" }, +] + [package.dev-dependencies] dev = [ { name = "aioresponses" }, @@ -1359,12 +1365,11 @@ dev = [ { name = "mypy" }, { name = "pdoc" }, { name = "pre-commit" }, - { name = "pyshark" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-timeout" }, - { name = "pyyaml" }, + { name = "python-roborock", extra = ["cli"] }, { name = "ruff" }, { name = "syrupy" }, ] @@ -1373,16 +1378,19 @@ dev = [ requires-dist = [ { name = "aiohttp", specifier = ">=3.8.2,<4" }, { name = "aiomqtt", specifier = ">=2.5.0,<3" }, - { name = "click", specifier = ">=8" }, - { name = "click-shell", specifier = "~=2.1" }, + { name = "click", marker = "extra == 'cli'", specifier = ">=8" }, + { name = "click-shell", marker = "extra == 'cli'", specifier = "~=2.1" }, { name = "construct", specifier = ">=2.10.57,<3" }, { name = "paho-mqtt", specifier = ">=1.6.1,<3.0.0" }, { name = "protobuf", specifier = ">=6.31.1,<8" }, { name = "pycryptodome", specifier = "~=3.18" }, { name = "pycryptodomex", marker = "sys_platform == 'darwin'", specifier = "~=3.18" }, { name = "pyrate-limiter", specifier = ">=4.0.0,<5" }, + { name = "pyshark", marker = "extra == 'cli'", specifier = ">=0.6,<0.7" }, + { name = "pyyaml", marker = "extra == 'cli'", specifier = ">=6.0.3" }, { name = "vacuum-map-parser-roborock" }, ] +provides-extras = ["cli"] [package.metadata.requires-dev] dev = [ @@ -1392,13 +1400,11 @@ dev = [ { name = "mypy" }, { name = "pdoc", specifier = ">=15.0.4,<17" }, { name = "pre-commit", specifier = ">=3.5,<5.0" }, - { name = "pyshark", specifier = ">=0.6" }, - { name = "pyshark", specifier = ">=0.6,<0.7" }, { name = "pytest" }, { name = "pytest-asyncio", specifier = ">=1.1.0" }, { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "pyyaml", specifier = ">=6.0.3" }, + { name = "python-roborock", extras = ["cli"] }, { name = "ruff", specifier = "==0.14.11" }, { name = "syrupy", specifier = ">=4.9.1,<6" }, ]