Skip to content

Commit 509fed5

Browse files
authored
Packaging (#26)
* Migrate to `pyproject.toml` and `ruff` * Run `pre-commit run --all-files` * Add GitHub Actions workflows
1 parent 62aa9c9 commit 509fed5

File tree

12 files changed

+310
-122
lines changed

12 files changed

+310
-122
lines changed

.github/workflows/ci.yml

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
name: CI
2+
3+
# yamllint disable-line rule:truthy
4+
on:
5+
push:
6+
pull_request: ~
7+
8+
env:
9+
CACHE_VERSION: 1
10+
DEFAULT_PYTHON: 3.8
11+
PRE_COMMIT_HOME: ~/.cache/pre-commit
12+
13+
jobs:
14+
# Separate job to pre-populate the base dependency cache
15+
# This prevent upcoming jobs to do the same individually
16+
prepare-base:
17+
name: Prepare base dependencies
18+
runs-on: ubuntu-latest
19+
strategy:
20+
matrix:
21+
python-version: [3.8, 3.9, "3.10", "3.11"]
22+
steps:
23+
- name: Check out code from GitHub
24+
uses: actions/checkout@v3
25+
- name: Set up Python ${{ matrix.python-version }}
26+
id: python
27+
uses: actions/setup-python@v4
28+
with:
29+
python-version: ${{ matrix.python-version }}
30+
- name: Restore base Python virtual environment
31+
id: cache-venv
32+
uses: actions/cache@v3
33+
with:
34+
path: venv
35+
key: ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }}
36+
restore-keys: ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-
37+
- name: Create Python virtual environment
38+
if: steps.cache-venv.outputs.cache-hit != 'true'
39+
run: |
40+
python -m venv venv
41+
. venv/bin/activate
42+
pip install -U pip setuptools pre-commit
43+
pip install -e '.[testing]'
44+
45+
pre-commit:
46+
name: Prepare pre-commit environment
47+
runs-on: ubuntu-latest
48+
needs: prepare-base
49+
steps:
50+
- name: Check out code from GitHub
51+
uses: actions/checkout@v3
52+
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
53+
uses: actions/setup-python@v4
54+
id: python
55+
with:
56+
python-version: ${{ env.DEFAULT_PYTHON }}
57+
- name: Restore base Python virtual environment
58+
id: cache-venv
59+
uses: actions/cache@v3
60+
with:
61+
path: venv
62+
key: ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }}
63+
- name: Fail job if Python cache restore failed
64+
if: steps.cache-venv.outputs.cache-hit != 'true'
65+
run: |
66+
echo "Failed to restore Python virtual environment from cache"
67+
exit 1
68+
- name: Restore pre-commit environment from cache
69+
id: cache-precommit
70+
uses: actions/cache@v3
71+
with:
72+
path: ${{ env.PRE_COMMIT_HOME }}
73+
key: ${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
74+
restore-keys: ${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-
75+
- name: Install pre-commit dependencies
76+
if: steps.cache-precommit.outputs.cache-hit != 'true'
77+
run: |
78+
. venv/bin/activate
79+
pre-commit install-hooks
80+
81+
lint-pre-commit:
82+
name: Check pre-commit
83+
runs-on: ubuntu-latest
84+
needs: pre-commit
85+
steps:
86+
- name: Check out code from GitHub
87+
uses: actions/checkout@v3
88+
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
89+
uses: actions/setup-python@v4
90+
id: python
91+
with:
92+
python-version: ${{ env.DEFAULT_PYTHON }}
93+
- name: Restore base Python virtual environment
94+
id: cache-venv
95+
uses: actions/cache@v3
96+
with:
97+
path: venv
98+
key: ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }}
99+
- name: Fail job if Python cache restore failed
100+
if: steps.cache-venv.outputs.cache-hit != 'true'
101+
run: |
102+
echo "Failed to restore Python virtual environment from cache"
103+
exit 1
104+
- name: Restore pre-commit environment from cache
105+
id: cache-precommit
106+
uses: actions/cache@v3
107+
with:
108+
path: ${{ env.PRE_COMMIT_HOME }}
109+
key: ${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
110+
- name: Fail job if cache restore failed
111+
if: steps.cache-venv.outputs.cache-hit != 'true'
112+
run: |
113+
echo "Failed to restore Python virtual environment from cache"
114+
exit 1
115+
- name: Run pre-commit
116+
run: |
117+
. venv/bin/activate
118+
pre-commit run --all-files --show-diff-on-failure
119+
120+
pytest:
121+
runs-on: ubuntu-latest
122+
needs: prepare-base
123+
strategy:
124+
matrix:
125+
python-version: [3.8, 3.9, "3.10", "3.11"]
126+
name: >-
127+
Run tests Python ${{ matrix.python-version }}
128+
steps:
129+
- name: Check out code from GitHub
130+
uses: actions/checkout@v3
131+
- name: Set up Python ${{ matrix.python-version }}
132+
uses: actions/setup-python@v4
133+
id: python
134+
with:
135+
python-version: ${{ matrix.python-version }}
136+
- name: Restore base Python virtual environment
137+
id: cache-venv
138+
uses: actions/cache@v3
139+
with:
140+
path: venv
141+
key: ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }}
142+
- name: Fail job if Python cache restore failed
143+
if: steps.cache-venv.outputs.cache-hit != 'true'
144+
run: |
145+
echo "Failed to restore Python virtual environment from cache"
146+
exit 1
147+
- name: Register Python problem matcher
148+
run: |
149+
echo "::add-matcher::.github/workflows/matchers/python.json"
150+
- name: Install Pytest Annotation plugin
151+
run: |
152+
. venv/bin/activate
153+
# Ideally this should be part of our dependencies
154+
# However this plugin is fairly new and doesn't run correctly
155+
# on a non-GitHub environment.
156+
pip install pytest-github-actions-annotate-failures
157+
- name: Run pytest
158+
run: |
159+
. venv/bin/activate
160+
pytest \
161+
-qq \
162+
--timeout=20 \
163+
--durations=10 \
164+
--cov zigpy_cli \
165+
--cov-config pyproject.toml \
166+
-o console_output_style=count \
167+
-p no:sugar \
168+
tests
169+
- name: Upload coverage artifact
170+
uses: actions/upload-artifact@v3
171+
with:
172+
name: coverage-${{ matrix.python-version }}
173+
path: .coverage
174+
175+
176+
coverage:
177+
name: Process test coverage
178+
runs-on: ubuntu-latest
179+
needs: pytest
180+
steps:
181+
- name: Check out code from GitHub
182+
uses: actions/checkout@v3
183+
- name: Set up Python ${{ matrix.python-version }}
184+
uses: actions/setup-python@v4
185+
id: python
186+
with:
187+
python-version: ${{ env.DEFAULT_PYTHON }}
188+
- name: Restore base Python virtual environment
189+
id: cache-venv
190+
uses: actions/cache@v3
191+
with:
192+
path: venv
193+
key: ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }}
194+
- name: Fail job if Python cache restore failed
195+
if: steps.cache-venv.outputs.cache-hit != 'true'
196+
run: |
197+
echo "Failed to restore Python virtual environment from cache"
198+
exit 1
199+
- name: Download all coverage artifacts
200+
uses: actions/download-artifact@v3
201+
- name: Combine coverage results
202+
run: |
203+
. venv/bin/activate
204+
coverage combine coverage*/.coverage*
205+
coverage report --fail-under=98
206+
coverage xml
207+
- name: Upload coverage to Codecov
208+
uses: codecov/codecov-action@v3
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Publish distributions to PyPI and TestPyPI
2+
on:
3+
push:
4+
tags:
5+
- "*"
6+
7+
jobs:
8+
build-and-publish:
9+
name: Build and publish distributions to PyPI and TestPyPI
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v3
13+
- name: Set up Python 3.8
14+
uses: actions/setup-python@v4
15+
with:
16+
python-version: 3.8
17+
- name: Install wheel
18+
run: >-
19+
pip install wheel build
20+
- name: Build
21+
run: >-
22+
python3 -m build
23+
- name: Publish distribution to PyPI
24+
uses: pypa/gh-action-pypi-publish@master
25+
with:
26+
password: ${{ secrets.PYPI_TOKEN }}

.pre-commit-config.yaml

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
repos:
22
- repo: https://github.com/psf/black
3-
rev: 22.3.0
3+
rev: 23.1.0
44
hooks:
55
- id: black
6-
args:
7-
- --safe
8-
- --quiet
9-
- repo: https://gitlab.com/pycqa/flake8
10-
rev: 4.0.1
6+
args: ["--safe", "--quiet"]
7+
- repo: https://github.com/charliermarsh/ruff-pre-commit
8+
rev: 'v0.0.244'
119
hooks:
12-
- id: flake8
13-
- repo: https://github.com/PyCQA/isort
14-
rev: 5.10.1
15-
hooks:
16-
- id: isort
10+
- id: ruff
11+
args: ["--fix"]

pyproject.toml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "zigpy-cli"
7+
description = "Unified command line interface for zigpy radios"
8+
urls = {repository = "https://github.com/zigpy/zigpy-cli"}
9+
authors = [
10+
{name = "puddly", email = "puddly3@gmail.com"}
11+
]
12+
license = {text = "GPL-3.0"}
13+
requires-python = ">=3.8"
14+
dependencies = [
15+
"zigpy>=0.52.0",
16+
"async_timeout",
17+
"voluptuous",
18+
"coloredlogs",
19+
"jsonschema",
20+
]
21+
dynamic = ["version", "readme"]
22+
23+
[tool.setuptools.dynamic]
24+
version = {attr = "zigpy_cli.__version__"}
25+
readme = {file = "README.md"}
26+
27+
[tool.setuptools.packages.find]
28+
exclude = ["tests", "tests.*"]
29+
30+
[project.optional-dependencies]
31+
testing = [
32+
"pytest>=7.1.2",
33+
"pytest-asyncio>=0.19.0",
34+
"pytest-timeout>=2.1.0",
35+
"pytest-mock>=3.8.2",
36+
"pytest-cov>=3.0.0",
37+
]
38+
39+
[project.scripts]
40+
zigpy = "zigpy_cli.__main__:cli"
41+
42+
43+
[tool.ruff]
44+
select = [
45+
# Pyflakes
46+
"F",
47+
# Pycodestyle
48+
"E",
49+
"W",
50+
# isort
51+
"I001"
52+
]
53+
src = ["zigpy_cli", "tests"]
54+
55+
[tool.ruff.isort]
56+
known-first-party = ["zigpy_cli", "tests"]

setup.cfg

Lines changed: 0 additions & 34 deletions
This file was deleted.

setup.py

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,4 @@
1-
import pathlib
1+
import setuptools
22

3-
from setuptools import setup, find_packages
4-
5-
import zigpy_cli
6-
7-
setup(
8-
name="zigpy-cli",
9-
version=zigpy_cli.__version__,
10-
description="Unified command line interface for zigpy radios",
11-
long_description=(pathlib.Path(__file__).parent / "README.md").read_text(),
12-
long_description_content_type="text/markdown",
13-
url="https://github.com/zigpy/zigpy-cli",
14-
author="puddly",
15-
author_email="puddly3@gmail.com",
16-
license="GPL-3.0",
17-
entry_points={"console_scripts": ["zigpy=zigpy_cli.__main__:cli"]},
18-
packages=find_packages(exclude=["tests", "tests.*"]),
19-
install_requires=[
20-
"click",
21-
"coloredlogs",
22-
"scapy",
23-
"zigpy>=0.48.1",
24-
"bellows>=0.34.3",
25-
"zigpy-deconz>=0.18.0",
26-
"zigpy-znp>=0.8.0",
27-
],
28-
extras_require={
29-
# [all] pulls in all radio libraries
30-
"testing": [
31-
"pytest>=5.4.5",
32-
"pytest-asyncio>=0.12.0",
33-
"pytest-timeout",
34-
"pytest-mock",
35-
"pytest-cov",
36-
"coveralls",
37-
'asynctest; python_version < "3.8.0"',
38-
],
39-
},
40-
)
3+
if __name__ == "__main__":
4+
setuptools.setup()

0 commit comments

Comments
 (0)