pybricks-cli 1.0.0b1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 The Pybricks Authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: pybricks-cli
3
+ Version: 1.0.0b1
4
+ Summary: The Pybricks command line interface
5
+ Keywords: pybricks,lego,micropython,bluetooth,robotics
6
+ Author: The Pybricks Authors
7
+ Author-email: The Pybricks Authors <dev@pybricks.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Education
14
+ Classifier: Natural Language :: English
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Topic :: Software Development :: Embedded Systems
17
+ Classifier: Typing :: Typed
18
+ Requires-Dist: pybricks-core>=1.0.0b1
19
+ Requires-Dist: pybricks-client>=1.0.0b1
20
+ Requires-Dist: pybricks-service>=1.0.0b1
21
+ Requires-Dist: anyio>=4.14
22
+ Requires-Dist: cyclopts>=4.22
23
+ Requires-Dist: rich>=13.7
24
+ Requires-Dist: typing-extensions>=4.15
25
+ Requires-Dist: watchfiles>=1.2
26
+ Maintainer: David Lechner
27
+ Maintainer-email: David Lechner <david@pybricks.com>
28
+ Requires-Python: >=3.11
29
+ Project-URL: homepage, https://pybricks.com
30
+ Project-URL: repository, https://github.com/pybricks/pybricks-tools
31
+ Project-URL: documentation, https://pybricks.com/pybricks-tools/cli/
32
+ Project-URL: Changelog, https://github.com/pybricks/pybricks-tools/blob/main/packages/pb-cli/CHANGELOG.md
33
+ Project-URL: Support, https://github.com/pybricks/support/discussions
34
+ Project-URL: Issues, https://github.com/pybricks/support/issues
35
+ Description-Content-Type: text/markdown
36
+
37
+ # pybricks-cli
38
+
39
+ The `pb` command: run Python programs on a [Pybricks](https://pybricks.com) hub
40
+ from your computer.
41
+
42
+ ```bash
43
+ uv tool install pybricks-cli
44
+ ```
45
+
46
+ Then switch a hub on:
47
+
48
+ ```bash
49
+ pb connect # find a hub and connect to it
50
+ pb run demo.py # compile the script, send it, and run it
51
+ ```
52
+
53
+ **The hub stays connected after the command finishes**, so the second `pb run`
54
+ starts instantly, and so does the hundredth.
55
+
56
+ `pb repl` talks to the hub's interpreter a line at a time, and `pb run -c` runs
57
+ a line or two of Python without a file. `pb --help` lists the rest.
58
+
59
+ > **Status:** beta. Commands and APIs may still change before 1.0.0.
@@ -0,0 +1,23 @@
1
+ # pybricks-cli
2
+
3
+ The `pb` command: run Python programs on a [Pybricks](https://pybricks.com) hub
4
+ from your computer.
5
+
6
+ ```bash
7
+ uv tool install pybricks-cli
8
+ ```
9
+
10
+ Then switch a hub on:
11
+
12
+ ```bash
13
+ pb connect # find a hub and connect to it
14
+ pb run demo.py # compile the script, send it, and run it
15
+ ```
16
+
17
+ **The hub stays connected after the command finishes**, so the second `pb run`
18
+ starts instantly, and so does the hundredth.
19
+
20
+ `pb repl` talks to the hub's interpreter a line at a time, and `pb run -c` runs
21
+ a line or two of Python without a file. `pb --help` lists the rest.
22
+
23
+ > **Status:** beta. Commands and APIs may still change before 1.0.0.
@@ -0,0 +1,70 @@
1
+ [project]
2
+ name = "pybricks-cli"
3
+ version = "1.0.0b1"
4
+ description = "The Pybricks command line interface"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.11"
9
+ keywords = [
10
+ "pybricks",
11
+ "lego",
12
+ "micropython",
13
+ "bluetooth",
14
+ "robotics",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: Education",
21
+ "Natural Language :: English",
22
+ "Operating System :: OS Independent",
23
+ "Topic :: Software Development :: Embedded Systems",
24
+ "Typing :: Typed",
25
+ ]
26
+ dependencies = [
27
+ "pybricks-core>=1.0.0b1",
28
+ "pybricks-client>=1.0.0b1",
29
+ "pybricks-service>=1.0.0b1",
30
+ "anyio>=4.14",
31
+ "cyclopts>=4.22",
32
+ "rich>=13.7",
33
+ "typing-extensions>=4.15",
34
+ "watchfiles>=1.2",
35
+ ]
36
+
37
+ [[project.authors]]
38
+ name = "The Pybricks Authors"
39
+ email = "dev@pybricks.com"
40
+
41
+ [[project.maintainers]]
42
+ name = "David Lechner"
43
+ email = "david@pybricks.com"
44
+
45
+ [project.scripts]
46
+ pb = "pb_cli.cli:main"
47
+
48
+ [project.urls]
49
+ homepage = "https://pybricks.com"
50
+ repository = "https://github.com/pybricks/pybricks-tools"
51
+ documentation = "https://pybricks.com/pybricks-tools/cli/"
52
+ Changelog = "https://github.com/pybricks/pybricks-tools/blob/main/packages/pb-cli/CHANGELOG.md"
53
+ Support = "https://github.com/pybricks/support/discussions"
54
+ Issues = "https://github.com/pybricks/support/issues"
55
+
56
+ [build-system]
57
+ requires = ["uv_build>=0.12.7,<0.13.0"]
58
+ build-backend = "uv_build"
59
+
60
+ [tool.uv.build-backend]
61
+ module-name = "pb_cli"
62
+
63
+ [tool.uv.sources.pybricks-core]
64
+ workspace = true
65
+
66
+ [tool.uv.sources.pybricks-client]
67
+ workspace = true
68
+
69
+ [tool.uv.sources.pybricks-service]
70
+ workspace = true
@@ -0,0 +1,54 @@
1
+ [project]
2
+ name = "pybricks-cli"
3
+ version = "1.0.0b1"
4
+ description = "The Pybricks command line interface"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "The Pybricks Authors", email = "dev@pybricks.com" }]
9
+ maintainers = [{ name = "David Lechner", email = "david@pybricks.com" }]
10
+ requires-python = ">=3.11"
11
+ keywords = ["pybricks", "lego", "micropython", "bluetooth", "robotics"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Environment :: Console",
15
+ "Intended Audience :: Developers",
16
+ "Intended Audience :: Education",
17
+ "Natural Language :: English",
18
+ "Operating System :: OS Independent",
19
+ "Topic :: Software Development :: Embedded Systems",
20
+ "Typing :: Typed",
21
+ ]
22
+ dependencies = [
23
+ "pybricks-core>=1.0.0b1",
24
+ "pybricks-client>=1.0.0b1",
25
+ "pybricks-service>=1.0.0b1",
26
+ "anyio>=4.14",
27
+ "cyclopts>=4.22",
28
+ "rich>=13.7",
29
+ "typing-extensions>=4.15",
30
+ "watchfiles>=1.2",
31
+ ]
32
+
33
+ [project.scripts]
34
+ pb = "pb_cli.cli:main"
35
+
36
+ [project.urls]
37
+ homepage = "https://pybricks.com"
38
+ repository = "https://github.com/pybricks/pybricks-tools"
39
+ documentation = "https://pybricks.com/pybricks-tools/cli/"
40
+ "Changelog" = "https://github.com/pybricks/pybricks-tools/blob/main/packages/pb-cli/CHANGELOG.md"
41
+ "Support" = "https://github.com/pybricks/support/discussions"
42
+ "Issues" = "https://github.com/pybricks/support/issues"
43
+
44
+ [build-system]
45
+ requires = ["uv_build>=0.12.7,<0.13.0"]
46
+ build-backend = "uv_build"
47
+
48
+ [tool.uv.build-backend]
49
+ module-name = "pb_cli"
50
+
51
+ [tool.uv.sources]
52
+ pybricks-core = { workspace = true }
53
+ pybricks-client = { workspace = true }
54
+ pybricks-service = { workspace = true }
@@ -0,0 +1,8 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 The Pybricks Authors
3
+
4
+ """The Pybricks command line interface."""
5
+
6
+ __version__ = "1.0.0b1"
7
+
8
+ __all__ = ["__version__"]
@@ -0,0 +1,7 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 The Pybricks Authors
3
+
4
+ from pb_cli.cli import main
5
+
6
+ if __name__ == "__main__":
7
+ raise SystemExit(main())
@@ -0,0 +1,127 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 The Pybricks Authors
3
+
4
+ """The command line's shape: the app itself, its groups, and shared options.
5
+
6
+ Separate from the commands so that the command modules can all import it
7
+ without importing each other. :mod:`pb_cli.cli` pulls those modules in, which is
8
+ what registers them.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+ import sys
15
+ from collections.abc import Sequence
16
+ from typing import Annotated
17
+
18
+ import cyclopts
19
+
20
+ from pb_cli import __version__
21
+ from pb_cli.config import config_sources
22
+ from pb_core.logging import TRACE, setup_logging
23
+
24
+ __all__ = [
25
+ "HUB_COMMANDS",
26
+ "PROGRAM_COMMANDS",
27
+ "SERVICE_COMMANDS",
28
+ "Verbose",
29
+ "app",
30
+ "configure_logging",
31
+ "service_app",
32
+ ]
33
+
34
+ app = cyclopts.App(
35
+ name="pb",
36
+ version=__version__,
37
+ help=(
38
+ "Talk to Pybricks hubs.\n\n"
39
+ "A hub stays connected between commands, so you only need to run "
40
+ "pb connect once."
41
+ ),
42
+ # Every command is in a group of its own, so what is left in the default
43
+ # panel is --help and --version. Calling that panel "Commands" would be a
44
+ # lie, and putting it last keeps the commands at the top where someone
45
+ # reading the help is looking.
46
+ group_commands=cyclopts.Group("Options", sort_key=3),
47
+ config=config_sources(),
48
+ )
49
+
50
+ HUB_COMMANDS = cyclopts.Group("Hubs", sort_key=0)
51
+ """Finding a hub, holding on to one, and asking what it is doing.
52
+
53
+ Ordered by what someone actually has to do, which is why each command carries
54
+ an explicit ``sort_key`` rather than falling back to alphabetical. ``connect``
55
+ comes first, because it is the one command nobody gets anywhere without, with
56
+ its opposite ``disconnect`` beside it.
57
+
58
+ The rest are things a user may want rather than steps they must take, so they
59
+ come after: ``status`` and ``list`` report on what is already connected, and
60
+ ``scan`` comes last because nobody has to run it at all -- ``connect`` does its
61
+ own looking, and ``connect --scan`` shows the same list when the choice
62
+ matters.
63
+ """
64
+
65
+ PROGRAM_COMMANDS = cyclopts.Group("Programs", sort_key=1)
66
+ """Getting a program onto a hub and controlling it once it is there."""
67
+
68
+ SERVICE_COMMANDS = cyclopts.Group("Background service", sort_key=2)
69
+ """The thing holding the connections open. Rarely needed, so it comes last."""
70
+
71
+ service_app = cyclopts.App(
72
+ name="service",
73
+ help="Manage the background service that keeps hubs connected.",
74
+ group=SERVICE_COMMANDS,
75
+ # Not inherited from the root app, where the default panel holds only the
76
+ # flags: down here it really is the list of commands.
77
+ group_commands=cyclopts.Group("Commands"),
78
+ )
79
+ app.command(service_app)
80
+
81
+
82
+ Verbose = Annotated[
83
+ Sequence[bool],
84
+ cyclopts.Parameter(
85
+ name=["-v", "--verbose"],
86
+ help="Increase log detail. Repeat for more (-v, -vv, -vvv).",
87
+ show_default=False,
88
+ # No --no-verbose: there is nothing to turn off, and offering it
89
+ # would be one more thing in every command's help for no reason.
90
+ negative=(),
91
+ ),
92
+ ]
93
+ """How loud to be, counted rather than measured.
94
+
95
+ A sequence of flags rather than a number, because that is what makes the help
96
+ true. As an ``int`` this took a value -- ``-v 1`` worked and ``-v`` was an
97
+ error saying it "requires an argument", while every command's help said to
98
+ repeat it. Collecting the flags gives ``-v``, ``-v -v`` and the stacked
99
+ ``-vv``, which is what anybody typing it expects.
100
+ """
101
+
102
+
103
+ def configure_logging(verbose: Verbose | int = ()) -> None:
104
+ """Map repeated ``-v`` flags onto log levels.
105
+
106
+ Args:
107
+ verbose: The flags as they were given, or how many there
108
+ were. Both, because the commands hand over what they
109
+ were passed and a count reads better everywhere else.
110
+ """
111
+ count = verbose if isinstance(verbose, int) else len(verbose)
112
+ if count <= 0:
113
+ level = logging.WARNING
114
+ elif count == 1:
115
+ level = logging.INFO
116
+ elif count == 2:
117
+ level = logging.DEBUG
118
+ else:
119
+ level = TRACE
120
+
121
+ setup_logging(
122
+ level=level,
123
+ style="rich" if sys.stderr.isatty() else "plain",
124
+ # bleak is noisy enough to bury our own lines, and is only interesting
125
+ # once someone is debugging the radio itself.
126
+ quiet_loggers=("bleak", "asyncio") if count < 3 else (),
127
+ )