Skip to content

Commit 861a52b

Browse files
committed
Update README and add PyPI publish workflow
README: refresh to reflect current test suite, CI matrix, security notes, type annotations, and improved API reference tables. publish.yml: new workflow that triggers on GitHub Release publish, builds the sdist+wheel with python-build, then publishes to PyPI via OIDC trusted publishing (no API token secret required). https://claude.ai/code/session_01M3Tg4vggVzAnLvc38jnBK3
1 parent aab4732 commit 861a52b

File tree

2 files changed

+153
-70
lines changed

2 files changed

+153
-70
lines changed

.github/workflows/publish.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
build:
9+
name: Build distribution
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Set up Python
16+
uses: actions/setup-python@v5
17+
with:
18+
python-version: "3.12"
19+
20+
- name: Install build dependencies
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install build
24+
25+
- name: Build package
26+
run: python -m build
27+
28+
- name: Upload distribution artifacts
29+
uses: actions/upload-artifact@v4
30+
with:
31+
name: dist
32+
path: dist/
33+
34+
publish:
35+
name: Publish to PyPI
36+
needs: build
37+
runs-on: ubuntu-latest
38+
39+
environment:
40+
name: pypi
41+
url: https://pypi.org/p/vudials_client
42+
43+
permissions:
44+
id-token: write # required for OIDC trusted publishing
45+
46+
steps:
47+
- name: Download distribution artifacts
48+
uses: actions/download-artifact@v4
49+
with:
50+
name: dist
51+
path: dist/
52+
53+
- name: Publish to PyPI
54+
uses: pypa/gh-action-pypi-publish@release/v1

README.md

Lines changed: 99 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,163 @@
11
# vudials_client
22

33
[![PyPI version](https://badge.fury.io/py/vudials_client.svg)](https://badge.fury.io/py/vudials_client)
4+
[![CI](https://github.com/erinlkolp/vu1-dial-python-module/actions/workflows/ci.yml/badge.svg)](https://github.com/erinlkolp/vu1-dial-python-module/actions/workflows/ci.yml)
45
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6+
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
57

6-
A Python client module for Streacom's VU1 Dial development hardware. This provides a simple interface to manipulate multiple dials.
8+
A Python client library for Streacom's VU1 Dial development hardware. Provides a simple, tested interface for controlling multiple dials and managing the VU1 server.
79

810
## Features
911

10-
- **Full Dial API**: Easily change your dial's value, color, name, background image, and more!
11-
- **Full Admin API**: Provides VU1 Dial Server API key management.
12+
- **Full Dial API**: Change a dial's value, backlight color, name, background image, and easing parameters
13+
- **Full Admin API**: VU1 Dial Server API key management and dial provisioning
14+
- **Type-annotated**: All public methods carry full parameter and return-type annotations
15+
- **Well tested**: Comprehensive test suite using `pytest` and `responses` — no live hardware required
16+
- **CI tested**: Passes on Python 3.11, 3.12, and 3.13 via GitHub Actions
1217

1318
## Installation
1419

1520
```bash
1621
pip install vudials-client
1722
```
1823

19-
For development installation:
24+
For development:
2025

2126
```bash
2227
git clone git@github.com:erinlkolp/vu1-dial-python-module.git
23-
cd vu1-dial-python-module/
28+
cd vu1-dial-python-module
2429
pip install -e ".[dev]"
2530
```
2631

2732
## Quick Start
2833

29-
Here's a simple example to get you started:
30-
3134
```python
35+
import os
3236
from vudials_client import vudialsclient
3337

34-
server_key = os.environ['API_KEY']
35-
admin_key = os.environ['ADMIN_API_KEY']
36-
server_address = os.environ['VU1_SERVER_ADDRESS']
37-
server_port = os.environ['VU1_SERVER_PORT']
38+
server_address = os.environ["VU1_SERVER_ADDRESS"]
39+
server_port = int(os.environ["VU1_SERVER_PORT"])
40+
server_key = os.environ["API_KEY"]
41+
admin_key = os.environ["ADMIN_API_KEY"]
3842

3943
vu_meter = vudialsclient.VUDial(server_address, server_port, server_key)
40-
admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key)
44+
admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key)
4145

46+
# List connected dials
4247
dial_list = vu_meter.list_dials()
43-
print(dial_list)
48+
print(dial_list.json())
49+
50+
# Set first dial to 75% with a blue backlight
51+
uid = dial_list.json()[0]["uid"]
52+
vu_meter.set_dial_value(uid, 75)
53+
vu_meter.set_dial_color(uid, 0, 0, 255)
4454

55+
# List API keys
4556
api_key_list = admin_api.list_api_keys()
46-
print(api_key_list)
57+
print(api_key_list.json())
4758
```
4859

49-
## Documentation
50-
51-
For detailed documentation, see [the official documentation](https://github.com/erinlkolp/vu1-dial-python-module/blob/main/docs/api.md).
60+
> **Note:** The VU1 server communicates over plain HTTP on your local network. Keep the server on a trusted interface and treat the API keys as secrets. Both keys are passed as URL query parameters and will appear in server access logs.
5261
53-
### Main Classes
62+
## API Reference
5463

55-
#### `VUDial`
64+
### `VUDial`
5665

57-
The primary class for interacting with the client-side module.
66+
Controls dial hardware. All methods return a `requests.Response`; HTTP 4xx/5xx errors raise `requests.exceptions.HTTPError`.
5867

5968
```python
60-
vu_meter = vudialsclient.VUDial(server_address, server_port, api_key)
69+
vu_meter = vudialsclient.VUDial(server_address, server_port, api_key)
6170
```
6271

63-
**Parameters:**
64-
- `server_address` (str): VU1 Dials Server host (ie. localhost)
65-
- `server_port` (int): VU1 Dials Server port (ie. 5340)
66-
- `api_key` (str): A valid API key for the VU1 Dials Server
72+
| Parameter | Type | Description |
73+
|---|---|---|
74+
| `server_address` | `str` | VU1 server hostname or IP (e.g. `"localhost"`) |
75+
| `server_port` | `int` | VU1 server port (e.g. `5340`) |
76+
| `api_key` | `str` | A valid API key for the VU1 server |
6777

6878
**Methods:**
69-
- `list_dials()`: Processes the given data and returns a result
70-
- `get_dial_info(uid)`: Saves the current state to a file
71-
- `set_dial_value(uid, value)`: Sets a dial's value (position)
72-
- `set_dial_color(uid, red, green, blue)`: Sets a dial's backlight color
73-
- `set_dial_background(uid, file)`: Sets a dial's background image
74-
- `get_dial_image_crc(uid)`: Obtains a dial's image CRC
75-
- `set_dial_name(uid, name)`: Sets a dial's name (no spaces)
76-
- `reload_hw_info(uid)`: Reloads dial hardware information
77-
- `set_dial_easing(uid, period, step)`: Sets dial easing
78-
- `set_backlight_easing(uid, period, step)`: Sets dial easing
79-
- `get_easing_config(uid)`: Gets easing config for dial (unsupported as of now)
80-
81-
#### `VUAdmin`
82-
83-
The primary class for interacting with the client-side module.
79+
80+
| Method | Description |
81+
|---|---|
82+
| `list_dials()` | List all connected dials |
83+
| `get_dial_info(uid)` | Get status/info for a specific dial |
84+
| `set_dial_value(uid, value)` | Set the dial position (0–100) |
85+
| `set_dial_color(uid, red, green, blue)` | Set the backlight color (0–255 each channel) |
86+
| `set_dial_background(uid, file)` | Upload a background image file |
87+
| `get_dial_image_crc(uid)` | Get the CRC of the current background image |
88+
| `set_dial_name(uid, name)` | Assign a name to a dial |
89+
| `reload_hw_info(uid)` | Reload hardware information for a dial |
90+
| `set_dial_easing(uid, period, step)` | Configure dial movement easing |
91+
| `set_backlight_easing(uid, period, step)` | Configure backlight easing |
92+
| `get_easing_config(uid)` | Retrieve current easing configuration |
93+
94+
### `VUAdmin`
95+
96+
Manages the VU1 server. All methods return a `requests.Response`; HTTP 4xx/5xx errors raise `requests.exceptions.HTTPError`.
8497

8598
```python
86-
admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key)
99+
admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key)
87100
```
88101

89-
**Parameters:**
90-
- `server_address` (str): VU1 Dials Server host (ie. localhost)
91-
- `server_port` (int): VU1 Dials Server port (ie. 5340)
92-
- `admin_key` (str): A valid Admin API key for the VU1 Dials Server
102+
| Parameter | Type | Description |
103+
|---|---|---|
104+
| `server_address` | `str` | VU1 server hostname or IP |
105+
| `server_port` | `int` | VU1 server port |
106+
| `admin_key` | `str` | A valid Admin API key for the VU1 server |
93107

94108
**Methods:**
95-
- `provision_dials()`: Provisions new dial hardware
96-
- `list_api_keys()`: Lists all VU Server API keys
97-
- `remove_api_key(target_key)`: Removes an API key
98-
- `create_api_key(name, dials)`: Creates an API key (see value in return)
99-
- `update_api_key(name, target_key, dials)`: Updates an API key
100109

101-
## Contributing
110+
| Method | Description |
111+
|---|---|
112+
| `provision_dials()` | Provision newly connected dial hardware |
113+
| `list_api_keys()` | List all configured API keys |
114+
| `create_api_key(name, dials)` | Create a new API key; the generated key is in the response |
115+
| `update_api_key(name, target_key, dials)` | Update an existing API key |
116+
| `remove_api_key(target_key)` | Remove an API key |
102117

103-
Contributions are welcome! Please feel free to submit a Pull Request.
118+
## Testing
104119

105-
1. Fork the repository
106-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
107-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
108-
4. Push to the branch (`git push origin feature/amazing-feature`)
109-
5. Open a Pull Request
120+
The test suite uses [`responses`](https://github.com/getsentry/responses) to mock all HTTP calls — no VU1 hardware or running server is required.
110121

111-
Please make sure to update tests as appropriate and follow the code style guide.
122+
```bash
123+
# Run all tests with coverage report
124+
pytest tests/ -v --cov=vudials_client --cov-report=term-missing
112125

113-
## License
126+
# Run a specific test class
127+
pytest tests/test_vudialsclient.py::TestVUDialSetDialColor -v
128+
```
129+
130+
CI runs automatically on every push and pull request via GitHub Actions across Python 3.11, 3.12, and 3.13.
114131

115-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
132+
## Documentation
116133

117-
## Acknowledgements
134+
Full API documentation can be regenerated from docstrings:
118135

119-
- Many thanks to Aaron D. and Christopher K.!
136+
```bash
137+
pip install pydoc-markdown
138+
pydoc-markdown
139+
```
120140

121-
## License & Author
141+
This writes `docs/api.md` using the configuration in `pydoc-markdown.yml`.
122142

123-
- Author:: Erin L. Kolp (<erinlkolpfoss@gmail.com>)
143+
## Contributing
124144

125-
Copyright (c) 2025 Erin L. Kolp
145+
Contributions are welcome! Please open a pull request.
146+
147+
1. Fork the repository
148+
2. Create a feature branch (`git checkout -b feature/my-feature`)
149+
3. Make your changes and add tests for any new or modified behaviour
150+
4. Ensure the test suite passes: `pytest tests/ -v`
151+
5. Open a pull request against `main`
152+
153+
Please follow the existing code style: type-annotate all public methods, URL-encode user-supplied path segments with `quote(value, safe="")`, and keep library code free of `logging.basicConfig()` calls.
154+
155+
## License
126156

127-
Licensed under the MIT License
157+
MIT — see [LICENSE](LICENSE).
128158

129-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
130-
permit persons to whom the Software is furnished to do so, subject to the following conditions:
159+
## Author
131160

132-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
161+
Erin L. Kolp (<erinlkolpfoss@gmail.com>)
133162

134-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
163+
Many thanks to Aaron D. and Christopher K.!

0 commit comments

Comments
 (0)