Skip to content

Commit ad77a81

Browse files
authored
Merge pull request #3 from NRB-Tech/uv-switch
Added uv support
2 parents adf6dfe + 65c6f54 commit ad77a81

16 files changed

Lines changed: 1968 additions & 238 deletions

.github/workflows/python-package.yml

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@ jobs:
1818

1919
steps:
2020
- uses: actions/checkout@v4
21-
- name: Set up Python ${{ matrix.python-version }}
22-
uses: actions/setup-python@v5
21+
- name: Install uv and set up python ${{ matrix.python-version }}
22+
uses: astral-sh/setup-uv@v5
2323
with:
2424
python-version: ${{ matrix.python-version }}
25-
- name: Install dependencies
26-
run: |
27-
python -m pip install --upgrade pip
28-
pip install -e ".[test,lint]"
25+
enable-cache: true
26+
cache-dependency-glob: "uv.lock"
27+
- name: Install the project
28+
run: uv sync --only-group check
2929
- name: Lint
30-
run: |
31-
make lint
30+
run: make lint
31+
- name: Type check
32+
run: make typecheck
3233
- name: Test
33-
run: |
34-
make test
34+
run: make test
3535

3636
deploy:
3737
needs: test
@@ -43,34 +43,31 @@ jobs:
4343

4444
steps:
4545
- uses: actions/checkout@v4
46-
- name: Set up Python
47-
uses: actions/setup-python@v5
46+
- name: Set up uv
47+
uses: astral-sh/setup-uv@v5
4848
with:
49-
python-version: '3.13'
50-
- name: Install dependencies
51-
run: |
52-
python -m pip install --upgrade pip
53-
pip install -e ".[build]"
49+
enable-cache: true
50+
cache-dependency-glob: "uv.lock"
51+
- name: Install the project
52+
run: uv sync --no-dev
5453
- name: Build package
55-
run: python -m build
54+
run: make build
5655
- name: Publish package
5756
uses: pypa/gh-action-pypi-publish@release/v1
5857

5958
security:
6059
runs-on: ubuntu-latest
6160
steps:
6261
- uses: actions/checkout@v4
63-
- name: Set up Python
64-
uses: actions/setup-python@v5
62+
- name: Set up uv
63+
uses: astral-sh/setup-uv@v5
6564
with:
66-
python-version: '3.13'
67-
- name: Install dependencies
68-
run: |
69-
python -m pip install --upgrade pip
70-
pip install -e ".[security]"
65+
enable-cache: true
66+
cache-dependency-glob: "uv.lock"
67+
- name: Install the project
68+
run: uv sync --only-group security
7169
- name: Run Bandit security checks
72-
run: |
73-
bandit -c pyproject.toml -r .
70+
run: make bandit
7471
- name: Run Safety CLI to check for vulnerabilities
7572
uses: pyupio/safety-action@v1
7673
with:

Makefile

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
.PHONY: clean clean-test clean-pyc clean-build docs help
22
.DEFAULT_GOAL := help
33

4+
# If NO_UV is set, don't use uv to run commands
5+
ifdef NO_UV
6+
PY_CMD_PREFIX :=
7+
else
8+
PY_CMD_PREFIX := uv run
9+
endif
10+
411
define BROWSER_PYSCRIPT
512
import os, webbrowser, sys
613

@@ -24,10 +31,10 @@ for line in sys.stdin:
2431
endef
2532
export PRINT_HELP_PYSCRIPT
2633

27-
BROWSER := python -c "$$BROWSER_PYSCRIPT"
34+
BROWSER := $(PY_CMD_PREFIX) python -c "$$BROWSER_PYSCRIPT"
2835

2936
help:
30-
@python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
37+
@$(PY_CMD_PREFIX) python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
3138

3239
clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
3340

@@ -52,31 +59,38 @@ clean-test: ## remove test and coverage artifacts
5259
rm -fr .pytest_cache/
5360

5461
lint: ## check style
55-
black --check .
56-
isort --check .
57-
flake8 .
62+
$(PY_CMD_PREFIX) black --check .
63+
$(PY_CMD_PREFIX) isort --check .
64+
$(PY_CMD_PREFIX) flake8 .
5865

5966
format: ## format code
60-
black .
61-
isort .
67+
$(PY_CMD_PREFIX) black .
68+
$(PY_CMD_PREFIX) isort .
69+
70+
typecheck: ## type check code
71+
$(PY_CMD_PREFIX) mypy
72+
73+
bandit: ## run bandit security checks
74+
$(PY_CMD_PREFIX) bandit -c pyproject.toml -r .
6275

63-
security: ## run security checks
64-
bandit -c pyproject.toml -r .
65-
safety scan
76+
safety: ## run safety checks
77+
$(PY_CMD_PREFIX) safety scan
78+
79+
security: bandit safety ## run security checks
6680

6781
pre-commit: ## run pre-commit checks
68-
pre-commit run --all-files
82+
$(PY_CMD_PREFIX) pre-commit run --all-files
6983

7084
test: ## run tests quickly with the default Python
71-
pytest
85+
$(PY_CMD_PREFIX) pytest
7286

73-
test-all: ## run tests on every Python version with tox
74-
tox
87+
check: ## run all checks
88+
$(PY_CMD_PREFIX) tox
7589

7690
coverage: ## check code coverage quickly with the default Python
77-
coverage run --source test_a_ble -m pytest
78-
coverage report -m
79-
coverage html
91+
$(PY_CMD_PREFIX) coverage run --source test_a_ble -m pytest
92+
$(PY_CMD_PREFIX) coverage report -m
93+
$(PY_CMD_PREFIX) coverage html
8094
$(BROWSER) htmlcov/index.html
8195

8296
docs: ## generate Sphinx HTML documentation, including API docs
@@ -85,17 +99,21 @@ docs: ## generate Sphinx HTML documentation, including API docs
8599
$(BROWSER) docs/build/html/index.html
86100

87101
servedocs: docs ## compile the docs watching for changes
88-
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
89-
90-
release: dist ## package and upload a release
91-
twine upload dist/*
102+
$(PY_CMD_PREFIX) watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
92103

93-
dist: clean ## builds source and wheel package
94-
python -m build
95-
ls -l dist
104+
build: clean ## builds source and wheel package
105+
$(PY_CMD_PREFIX) python -m build
96106

97107
install: clean ## install the package to the active Python's site-packages
108+
ifdef USE_UV
109+
uv sync --no-default-groups
110+
else
98111
pip install -e .
112+
endif
99113

100-
dev-install: clean ## install the package and development dependencies
114+
dev-install: clean ## install the package and development dependencies. When using uv, dev dependencies are installed by default.
115+
ifdef USE_UV
116+
uv sync
117+
else
101118
pip install -e ".[dev]"
119+
endif

docs/Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,20 @@ SPHINXBUILD ?= sphinx-build
88
SOURCEDIR = source
99
BUILDDIR = build
1010

11+
# If NO_UV is set, don't use uv to run commands
12+
ifdef NO_UV
13+
PY_CMD_PREFIX :=
14+
else
15+
PY_CMD_PREFIX := uv run
16+
endif
17+
1118
# Put it first so that "make" without argument is like "make help".
1219
help:
13-
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
20+
@$(PY_CMD_PREFIX) $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
1421

1522
.PHONY: help Makefile
1623

1724
# Catch-all target: route all unknown targets to Sphinx using the new
1825
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
1926
%: Makefile
20-
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
27+
@$(PY_CMD_PREFIX) $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

docs/source/conf.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
]
2929

3030
templates_path = ["_templates"]
31-
exclude_patterns = []
3231

3332
# -- Options for HTML output -------------------------------------------------
3433
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

pyproject.toml

Lines changed: 105 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,77 @@
11
[build-system]
2-
requires = ["setuptools>=42", "wheel"]
3-
build-backend = "setuptools.build_meta"
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "test-a-ble"
7+
version = "0.1.0"
8+
description = "Framework for testing BLE IoT devices"
9+
authors = [
10+
{name = "Nick Brook", email = "[email protected]"}
11+
]
12+
readme = "README.md"
13+
requires-python = ">=3.12"
14+
classifiers = [
15+
"Development Status :: 3 - Alpha",
16+
"Intended Audience :: Developers",
17+
"License :: OSI Approved :: MIT License",
18+
"Programming Language :: Python :: 3",
19+
"Programming Language :: Python :: 3.12",
20+
"Programming Language :: Python :: 3.13",
21+
"Topic :: Software Development :: Testing",
22+
"Topic :: System :: Hardware",
23+
]
24+
keywords = ["bluetooth", "ble", "iot", "testing", "automation"]
25+
dependencies = [
26+
"bleak>=0.22.3",
27+
"rich>=13.9.4",
28+
"packaging",
29+
"prompt_toolkit>=3.0.0",
30+
]
31+
32+
[project.scripts]
33+
test-a-ble = "test_a_ble.cli:main"
34+
35+
[dependency-groups]
36+
test = [
37+
"pytest>=8.3.5",
38+
"pytest-cov>=6.0.0",
39+
"pytest-asyncio>=0.22.0",
40+
"tox>=4.24.2",
41+
"tox-uv>=1.25.0",
42+
]
43+
lint = [
44+
"black>=25.1.0",
45+
"isort>=6.0.1",
46+
"flake8>=7.1.2",
47+
"flake8-docstrings>=1.7.0",
48+
"flake8-pyproject>=1.2.3",
49+
]
50+
type = [
51+
"mypy>=1.15.0",
52+
]
53+
check = [
54+
{include-group = "test"},
55+
{include-group = "lint"},
56+
{include-group = "type"},
57+
]
58+
security = [
59+
"bandit>=1.8.3",
60+
"safety>=3.3.1",
61+
]
62+
docs = [
63+
"sphinx>=8.2.3",
64+
"sphinx-rtd-theme>=3.0.2",
65+
"myst-parser>=4.0.1",
66+
]
67+
dev = [
68+
"pre-commit>=4.1.0",
69+
{include-group = "check"},
70+
{include-group = "security"},
71+
{include-group = "docs"},
72+
]
73+
74+
# Formatting and linting
475

576
[tool.black]
677
line-length = 120
@@ -16,7 +87,10 @@ exclude = [
1687
# No need to traverse our git directory
1788
".git",
1889
# There's no value in checking cache directories
19-
"__pycache__"
90+
"__pycache__",
91+
"*.pyc",
92+
".venv",
93+
".tox",
2094
]
2195
# Use extend-ignore to add to already ignored checks which are anti-patterns like W503.
2296
extend-ignore = [
@@ -30,6 +104,9 @@ extend-ignore = [
30104
"D202"
31105
]
32106

107+
[tool.mypy]
108+
files = ["test_a_ble", "docs", "tests"]
109+
33110
[tool.pytest.ini_options]
34111
testpaths = ["tests"]
35112
python_files = "test_*.py"
@@ -40,42 +117,44 @@ python_classes = "Test[A-Z][a-zA-Z0-9]*(?<!Context|Status|Exception|Failure|Skip
40117
norecursedirs = ["examples","test_discovery_test_package"]
41118

42119
[tool.bandit]
43-
exclude_dirs = [".tox"]
120+
exclude_dirs = [".tox", ".venv"]
44121
skips = ["B101", "B404", "B607"]
45122

123+
# Tox
124+
46125
[tool.tox]
47126
min_version = "4.0"
48-
env_list = ["py312", "py313"]
127+
env_list = ["py312", "py313", "lint", "type"]
49128
isolated_build = true
50129
skip_missing_interpreters = false
51-
requires = ["virtualenv>=20.0.0"]
52130

53-
[tool.tox.env.default]
54-
deps = [".[lint,test]"]
55-
commands = [
56-
"black --check .",
57-
"isort --check .",
58-
"flake8 .",
59-
"pytest {posargs:tests}",
60-
]
131+
[tool.tox.env_run_base]
132+
runner = "uv-venv-lock-runner"
133+
description = "Run test under {base_python}"
134+
dependency_groups = ["test"]
135+
commands = [["pytest"]]
61136

62137
[tool.tox.env.lint]
63-
deps = [".[lint]"]
138+
runner = "uv-venv-lock-runner"
139+
description = "format code"
140+
dependency_groups = ["lint"]
64141
commands = [
65-
"black --check .",
66-
"isort --check .",
67-
"flake8 .",
142+
["black", "--check", "."],
143+
["isort", "--check", "."],
144+
["flake8", "."],
68145
]
69146

70147
[tool.tox.env.format]
71-
deps = [".[lint]"]
148+
runner = "uv-venv-lock-runner"
149+
description = "format code"
150+
dependency_groups = ["lint"]
72151
commands = [
73-
"black .",
74-
"isort .",
152+
["black", "."],
153+
["isort", "."],
75154
]
76155

77-
[tool.tox.env.py312]
78-
base_python = ["python3.12"]
79-
80-
[tool.tox.env.py313]
81-
base_python = ["python3.13"]
156+
[tool.tox.env.type]
157+
runner = "uv-venv-lock-runner"
158+
description = "type check code"
159+
dependency_groups = ["type"]
160+
commands = [["mypy"]]

0 commit comments

Comments
 (0)