Skip to content

Commit d5e1929

Browse files
committed
Refine dependencies
1 parent 4af65b3 commit d5e1929

9 files changed

Lines changed: 82 additions & 64 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
// Use 'postCreateCommand' to run commands after the container is created.
1414
"postCreateCommand":
15-
"python -m pip install '.[build,test,development,documentation]'",
15+
"python -m pip install '.[all]' --group all",
1616

1717
// Configure tool-specific properties.
1818
"customizations": {

.github/workflows/code-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
- name: Install dependencies
3636
run: |
3737
python -m pip install --upgrade pip
38-
python -m pip install ".[build,test,development]"
38+
python -m pip install ".[all]" --group all
3939
- name: Check
4040
run: |
4141
invoke project.pre-commit

.github/workflows/python-avatar.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- name: Install
3535
run: |
3636
python -m pip install --upgrade pip
37-
python -m pip install .[avatar]
37+
python -m pip install .[all,avatar]
3838
- name: Rootcanal
3939
run: nohup python -m rootcanal > rootcanal.log &
4040
- name: Test

.github/workflows/python-build-test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
- name: Install dependencies
3636
run: |
3737
python -m pip install --upgrade pip
38-
python -m pip install ".[build,test,development,documentation]"
38+
python -m pip install ".[all]" --group all
3939
- name: Test
4040
run: |
4141
invoke test
@@ -62,7 +62,7 @@ jobs:
6262
- name: Install Python dependencies
6363
run: |
6464
python -m pip install --upgrade pip
65-
python -m pip install ".[build,test,development,documentation]"
65+
python -m pip install ".[all]" --group all
6666
- name: Install Rust toolchain
6767
uses: actions-rust-lang/setup-rust-toolchain@v1
6868
with:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ To install package dependencies needed to run the bumble examples, execute the f
3333

3434
```
3535
python -m pip install --upgrade pip
36-
python -m pip install ".[test,development,documentation]"
36+
python -m pip install ".[all]" --group dev
3737
```
3838

3939
### Examples

apps/auracast.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@
4040
try:
4141
import lc3 # type: ignore # pylint: disable=E0401
4242
except ImportError as e:
43-
raise ImportError(
44-
"Try `python -m pip install \"git+https://github.com/google/liblc3.git\"`."
45-
) from e
43+
raise ImportError("Try `python -m pip install '.[auracast]'`.") from e
4644

4745
import bumble.device
4846
import bumble.logging

apps/lea_unicast/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
try:
3131
import lc3 # type: ignore # pylint: disable=E0401
3232
except ImportError as e:
33-
raise ImportError("Try `python -m pip install \".[lc3]\"`.") from e
33+
raise ImportError("Try `python -m pip install \".[auracast]\"`.") from e
3434

3535
import aiohttp.web
3636
import click

bumble/keys.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import json
2828
import logging
2929
import os
30+
import pathlib
3031
from typing import TYPE_CHECKING, Any
3132

3233
from typing_extensions import Self
@@ -248,29 +249,26 @@ class without a namespace. With the default namespace, reading from a file will
248249
DEFAULT_NAMESPACE = '__DEFAULT__'
249250
DEFAULT_BASE_NAME = "keys"
250251

251-
def __init__(self, namespace, filename=None):
252-
self.namespace = namespace if namespace is not None else self.DEFAULT_NAMESPACE
252+
def __init__(
253+
self, namespace: str | None = None, filename: str | None = None
254+
) -> None:
255+
self.namespace = namespace or self.DEFAULT_NAMESPACE
253256

254-
if filename is None:
255-
# Use a default for the current user
257+
if filename:
258+
self.filename = pathlib.Path(filename).resolve()
259+
self.directory_name = self.filename.parent
260+
else:
261+
import platformdirs # Deferred import
256262

257-
# Import here because this may not exist on all platforms
258-
# pylint: disable=import-outside-toplevel
259-
import appdirs
263+
base_dir = platformdirs.user_data_path(self.APP_NAME, self.APP_AUTHOR)
264+
self.directory_name = base_dir / self.KEYS_DIR
260265

261-
self.directory_name = os.path.join(
262-
appdirs.user_data_dir(self.APP_NAME, self.APP_AUTHOR), self.KEYS_DIR
263-
)
264-
base_name = self.DEFAULT_BASE_NAME if namespace is None else self.namespace
265-
json_filename = (
266-
f'{base_name}.json'.lower().replace(':', '-').replace('/p', '-p')
267-
)
268-
self.filename = os.path.join(self.directory_name, json_filename)
269-
else:
270-
self.filename = filename
271-
self.directory_name = os.path.dirname(os.path.abspath(self.filename))
266+
base_name = self.namespace if namespace else self.DEFAULT_BASE_NAME
267+
safe_name = base_name.lower().replace(':', '-').replace('/', '-')
268+
269+
self.filename = self.directory_name / f"{safe_name}.json"
272270

273-
logger.debug(f'JSON keystore: {self.filename}')
271+
logger.debug('JSON keystore: %s', self.filename)
274272

275273
@classmethod
276274
def from_device(
@@ -293,7 +291,9 @@ def from_device(
293291

294292
return cls(namespace, filename)
295293

296-
async def load(self):
294+
async def load(
295+
self,
296+
) -> tuple[dict[str, dict[str, dict[str, Any]]], dict[str, dict[str, Any]]]:
297297
# Try to open the file, without failing. If the file does not exist, it
298298
# will be created upon saving.
299299
try:
@@ -312,17 +312,17 @@ async def load(self):
312312
return next(iter(db.items()))
313313

314314
# Finally, just create an empty key map for the namespace
315-
key_map = {}
315+
key_map: dict[str, dict[str, Any]] = {}
316316
db[self.namespace] = key_map
317317
return (db, key_map)
318318

319-
async def save(self, db):
319+
async def save(self, db: dict[str, dict[str, dict[str, Any]]]) -> None:
320320
# Create the directory if it doesn't exist
321321
if not os.path.exists(self.directory_name):
322322
os.makedirs(self.directory_name, exist_ok=True)
323323

324324
# Save to a temporary file
325-
temp_filename = self.filename + '.tmp'
325+
temp_filename = self.filename.with_name(self.filename.name + ".tmp")
326326
with open(temp_filename, 'w', encoding='utf-8') as output:
327327
json.dump(db, output, sort_keys=True, indent=4)
328328

@@ -334,16 +334,16 @@ async def delete(self, name: str) -> None:
334334
del key_map[name]
335335
await self.save(db)
336336

337-
async def update(self, name, keys):
337+
async def update(self, name: str, keys: PairingKeys) -> None:
338338
db, key_map = await self.load()
339339
key_map.setdefault(name, {}).update(keys.to_dict())
340340
await self.save(db)
341341

342-
async def get_all(self):
342+
async def get_all(self) -> list[tuple[str, PairingKeys]]:
343343
_, key_map = await self.load()
344344
return [(name, PairingKeys.from_dict(keys)) for (name, keys) in key_map.items()]
345345

346-
async def delete_all(self):
346+
async def delete_all(self) -> None:
347347
db, key_map = await self.load()
348348
key_map.clear()
349349
await self.save(db)

pyproject.toml

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ license-files = ["LICENSE"]
1212
authors = [{ name = "Google", email = "bumble-dev@google.com" }]
1313
requires-python = ">=3.10"
1414
dependencies = [
15-
"aiohttp ~= 3.8; platform_system!='Emscripten'",
16-
"appdirs >= 1.4; platform_system!='Emscripten'",
17-
"click >= 8.1.3; platform_system!='Emscripten'",
1815
"cryptography >= 44.0.3; platform_system!='Emscripten' and platform_system!='Android'",
1916
# Pyodide bundles a version of cryptography that is built for wasm, which may not match the
2017
# versions available on PyPI. Relax the version requirement since it's better than being
@@ -25,31 +22,52 @@ dependencies = [
2522
# updated. Relax the version requirement since it's better than being completely unable
2623
# to import the package in case of version mismatch.
2724
"cryptography >= 42.0.8; platform_system=='Android'",
28-
"grpcio >= 1.62.1; platform_system!='Emscripten'",
29-
"humanize >= 4.6.0; platform_system!='Emscripten'",
30-
"libusb1 >= 2.0.1; platform_system!='Emscripten'",
31-
"libusb-package == 1.0.26.1; platform_system!='Emscripten' and platform_system!='Android'",
32-
"platformdirs >= 3.10.0; platform_system!='Emscripten'",
33-
"prompt_toolkit >= 3.0.16; platform_system!='Emscripten'",
34-
"prettytable >= 3.6.0; platform_system!='Emscripten'",
35-
"protobuf >= 3.12.4; platform_system!='Emscripten'",
3625
"pyee >= 13.0.0",
37-
"pyserial-asyncio >= 0.5; platform_system!='Emscripten'",
38-
"pyserial >= 3.5; platform_system!='Emscripten'",
39-
"pyusb >= 1.2; platform_system!='Emscripten'",
40-
"tomli ~= 2.2.1; platform_system!='Emscripten' and python_version<'3.11'",
41-
"websockets >= 15.0.1; platform_system!='Emscripten'",
26+
"platformdirs >= 3.10.0; platform_system!='Emscripten'",
4227
]
4328

4429
[project.optional-dependencies]
45-
build = ["build >= 0.7"]
46-
test = [
30+
avatar = [
31+
"pandora-avatar == 0.0.10",
32+
"rootcanal == 1.11.1 ; python_version>='3.10'",
33+
]
34+
pandora = ["bt-test-interfaces >= 0.0.6"]
35+
auracast = [
36+
"lc3py >= 1.1.3; python_version>='3.10' and ((platform_system=='Linux' and platform_machine=='x86_64') or (platform_system=='Darwin' and platform_machine=='arm64'))",
37+
"sounddevice >= 0.5.1",
38+
]
39+
app = [
40+
"aiohttp ~= 3.8",
41+
"click >= 8.1.3",
42+
"humanize >= 4.6.0",
43+
"prompt_toolkit >= 3.0.16",
44+
"prettytable >= 3.6.0",
45+
"tomli ~= 2.2.1; python_version<'3.11'",
46+
]
47+
transport = [
48+
"grpcio >= 1.62.1",
49+
"libusb1 >= 2.0.1",
50+
"libusb-package == 1.0.26.1; platform_system!='Android'",
51+
"protobuf >= 3.12.4",
52+
"pyserial-asyncio >= 0.5",
53+
"pyserial >= 3.5",
54+
"pyusb >= 1.2",
55+
"websockets >= 15.0.1",
56+
]
57+
all = [
58+
"bumble[auracast]",
59+
"bumble[app]",
60+
"bumble[transport]",
61+
]
62+
63+
64+
[dependency-groups]
65+
dev = [
66+
"build >= 0.7",
4767
"pytest >= 8.2",
4868
"pytest-asyncio >= 0.23.5",
4969
"pytest-html >= 3.2.0",
5070
"coverage >= 6.4",
51-
]
52-
development = [
5371
"black ~= 25.1",
5472
"bt-test-interfaces >= 0.0.6",
5573
"grpcio-tools >= 1.62.1",
@@ -64,21 +82,23 @@ development = [
6482
"types-invoke >= 1.7.3",
6583
"types-protobuf >= 4.21.0",
6684
]
67-
avatar = [
68-
"pandora-avatar == 0.0.10",
69-
"rootcanal == 1.11.1 ; python_version>='3.10'",
70-
]
71-
pandora = ["bt-test-interfaces >= 0.0.6"]
7285
documentation = [
7386
"mkdocs >= 1.6.0",
7487
"mkdocs-material >= 9.6",
7588
"mkdocstrings[python] >= 0.27.0",
7689
]
77-
auracast = [
78-
"lc3py >= 1.1.3; python_version>='3.10' and ((platform_system=='Linux' and platform_machine=='x86_64') or (platform_system=='Darwin' and platform_machine=='arm64'))",
79-
"sounddevice >= 0.5.1",
90+
all = [
91+
{include-group = "dev"},
92+
{include-group = "documentation"},
8093
]
8194

95+
[tool.uv]
96+
default-groups = [
97+
"dev",
98+
"documentation",
99+
]
100+
101+
82102
[project.scripts]
83103
bumble-auracast = "bumble.apps.auracast:main"
84104
bumble-ble-rpa-tool = "bumble.apps.ble_rpa_tool:main"

0 commit comments

Comments
 (0)