barbara-api-sdk 0.1.0__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.
Files changed (43) hide show
  1. barbara_api_sdk-0.1.0/.github/workflows/ci.yml +39 -0
  2. barbara_api_sdk-0.1.0/.github/workflows/publish.yml +36 -0
  3. barbara_api_sdk-0.1.0/.gitignore +11 -0
  4. barbara_api_sdk-0.1.0/CHANGELOG.md +23 -0
  5. barbara_api_sdk-0.1.0/CONTRIBUTING.md +37 -0
  6. barbara_api_sdk-0.1.0/LICENSE +21 -0
  7. barbara_api_sdk-0.1.0/PKG-INFO +335 -0
  8. barbara_api_sdk-0.1.0/README.md +301 -0
  9. barbara_api_sdk-0.1.0/RELEASING.md +25 -0
  10. barbara_api_sdk-0.1.0/examples/quickstart.py +19 -0
  11. barbara_api_sdk-0.1.0/pyproject.toml +64 -0
  12. barbara_api_sdk-0.1.0/src/barbara/__init__.py +28 -0
  13. barbara_api_sdk-0.1.0/src/barbara/_http.py +42 -0
  14. barbara_api_sdk-0.1.0/src/barbara/auth.py +105 -0
  15. barbara_api_sdk-0.1.0/src/barbara/client.py +135 -0
  16. barbara_api_sdk-0.1.0/src/barbara/config.py +57 -0
  17. barbara_api_sdk-0.1.0/src/barbara/exceptions.py +26 -0
  18. barbara_api_sdk-0.1.0/src/barbara/models.py +211 -0
  19. barbara_api_sdk-0.1.0/src/barbara/py.typed +0 -0
  20. barbara_api_sdk-0.1.0/src/barbara/resources/__init__.py +0 -0
  21. barbara_api_sdk-0.1.0/src/barbara/resources/alerts.py +74 -0
  22. barbara_api_sdk-0.1.0/src/barbara/resources/appconfig.py +124 -0
  23. barbara_api_sdk-0.1.0/src/barbara/resources/applications.py +230 -0
  24. barbara_api_sdk-0.1.0/src/barbara/resources/clusters.py +231 -0
  25. barbara_api_sdk-0.1.0/src/barbara/resources/devices.py +303 -0
  26. barbara_api_sdk-0.1.0/src/barbara/resources/groups.py +115 -0
  27. barbara_api_sdk-0.1.0/src/barbara/resources/models.py +214 -0
  28. barbara_api_sdk-0.1.0/src/barbara/resources/stacks.py +403 -0
  29. barbara_api_sdk-0.1.0/src/barbara/resources/users.py +53 -0
  30. barbara_api_sdk-0.1.0/src/barbara/resources/workloads.py +535 -0
  31. barbara_api_sdk-0.1.0/src/barbara/utils.py +86 -0
  32. barbara_api_sdk-0.1.0/tests/conftest.py +27 -0
  33. barbara_api_sdk-0.1.0/tests/test_alerts.py +41 -0
  34. barbara_api_sdk-0.1.0/tests/test_appconfig.py +42 -0
  35. barbara_api_sdk-0.1.0/tests/test_applications.py +75 -0
  36. barbara_api_sdk-0.1.0/tests/test_client.py +19 -0
  37. barbara_api_sdk-0.1.0/tests/test_clusters.py +125 -0
  38. barbara_api_sdk-0.1.0/tests/test_devices.py +138 -0
  39. barbara_api_sdk-0.1.0/tests/test_groups.py +58 -0
  40. barbara_api_sdk-0.1.0/tests/test_models.py +96 -0
  41. barbara_api_sdk-0.1.0/tests/test_stacks.py +68 -0
  42. barbara_api_sdk-0.1.0/tests/test_users.py +42 -0
  43. barbara_api_sdk-0.1.0/tests/test_workloads.py +101 -0
@@ -0,0 +1,39 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Install package with dev dependencies
20
+ run: pip install -e ".[dev]"
21
+ - name: Lint
22
+ run: ruff check src tests
23
+ - name: Type check
24
+ run: mypy
25
+ - name: Test
26
+ run: pytest -q
27
+
28
+ build:
29
+ runs-on: ubuntu-latest
30
+ needs: test
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+ - uses: actions/setup-python@v5
34
+ with:
35
+ python-version: "3.12"
36
+ - name: Build package
37
+ run: |
38
+ pip install build
39
+ python -m build
@@ -0,0 +1,36 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-python@v5
13
+ with:
14
+ python-version: "3.12"
15
+ - name: Build package
16
+ run: |
17
+ pip install build
18
+ python -m build
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish:
25
+ needs: build
26
+ runs-on: ubuntu-latest
27
+ environment: pypi
28
+ permissions:
29
+ id-token: write # required for PyPI trusted publishing
30
+ steps:
31
+ - uses: actions/download-artifact@v4
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+ - name: Publish to PyPI
36
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ venv/
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .mypy_cache/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .env
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
+
6
+ ## [0.1.0] - 2026-08-06
7
+
8
+ ### Added
9
+
10
+ - `BarbaraClient` and `AsyncBarbaraClient`, with OAuth2 password-grant authentication, automatic token refresh, and 401 retry.
11
+ - `client.devices`: lifecycle (`list`, `get`, `resolve`, `delete`), secrets, app configuration, docker credentials, and actions (`reboot`, `poweroff`, `provision`, `deprovision`, `brick`).
12
+ - `client.devices.workloads`: create, update, start, stop, logs, app configuration, and container info for device workloads.
13
+ - `client.clusters`: lifecycle (`list`, `get`, `update`, `delete`), secrets, app configuration, and docker credentials.
14
+ - `client.clusters.stacks`: create, update, delete, logs, and app configuration for cluster stacks.
15
+ - `client.applications`: application and application version CRUD, with `multipart/form-data` file uploads.
16
+ - `client.models`: model and model version CRUD, with `multipart/form-data` file uploads.
17
+ - `client.appconfig`: reusable application configuration CRUD.
18
+ - `client.groups`: device group CRUD.
19
+ - `client.users`: read-only user listing and pagination.
20
+ - `client.alerts`: alert listing, acknowledgement, and alert events.
21
+ - `client.api_version()`.
22
+ - Typed exceptions: `BarbaraApiError`, `BarbaraAuthError`, `BarbaraNotFoundError`, `BarbaraPermissionError`.
23
+ - Full test suite using `respx` HTTP mocking.
@@ -0,0 +1,37 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ pip install -e ".[dev]"
7
+ pytest
8
+ ruff check src tests
9
+ mypy
10
+ ```
11
+
12
+ ## Adding a resource
13
+
14
+ Follow the pattern in `src/barbara/resources/devices.py`:
15
+
16
+ 1. Add or extend the dataclass in `models.py` (only fields the SDK actually uses; keep `.raw` for the original payload).
17
+ 2. Add a `resources/<name>.py` with a sync `<Name>Resource` and an async `Async<Name>Resource`, both taking the client in `__init__` and calling `client.request(...)`.
18
+ 3. Wire both into `BarbaraClient` and `AsyncBarbaraClient` in `client.py`.
19
+ 4. Add tests under `tests/` mocking HTTP with `respx`. Never call the real API in tests.
20
+ 5. Verify request/response shapes against the [Barbara API documentation](https://prod.bap.barbara.tech/documentation/) before assuming fields or paths.
21
+
22
+ ## Known gaps
23
+
24
+ The following are not yet implemented, either because the API does not document a request body for them, or because their shape does not fit the `list`/`get`/`create`/`update`/`delete` pattern used elsewhere in this SDK:
25
+
26
+ - Device network configuration sub-resources (hostname, network interfaces, iptables, NTP, proxy, VPN).
27
+ - Cluster creation and device cluster-membership management.
28
+ - Model-type workloads and stacks, and their service configuration endpoints.
29
+ - Updating an application version (`PUT` on an app version).
30
+
31
+ ## Checklist before opening a PR
32
+
33
+ - [ ] Sync and async resources expose the same methods.
34
+ - [ ] New or changed public methods are typed and exported from `barbara/__init__.py` if user-facing.
35
+ - [ ] Tests added or updated; `pytest` passes.
36
+ - [ ] `ruff check` and `mypy` pass.
37
+ - [ ] README updated if the change affects usage.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Barbara
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
13
+ all 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,335 @@
1
+ Metadata-Version: 2.4
2
+ Name: barbara-api-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Barbara Edge AI platform API
5
+ Project-URL: Homepage, https://github.com/Barbaraedge/barbara-api-sdk-python
6
+ Project-URL: Documentation, https://github.com/Barbaraedge/barbara-api-sdk-python#readme
7
+ Project-URL: Issues, https://github.com/Barbaraedge/barbara-api-sdk-python/issues
8
+ Project-URL: Changelog, https://github.com/Barbaraedge/barbara-api-sdk-python/blob/main/CHANGELOG.md
9
+ Author-email: Barbara <support@barbara.tech>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,barbara,edge-ai,iot,sdk
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Requires-Dist: httpx>=0.27
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.11; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
30
+ Requires-Dist: pytest>=8; extra == 'dev'
31
+ Requires-Dist: respx>=0.21; extra == 'dev'
32
+ Requires-Dist: ruff>=0.6; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # Barbara API SDK for Python
36
+
37
+ Official Python SDK for the [Barbara](https://barbara.tech) Edge AI platform API. It provides a typed, synchronous and asynchronous client for managing devices, clusters, applications, models, and related resources.
38
+
39
+ ## Requirements
40
+
41
+ - Python 3.9 or later
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install barbara-api-sdk
47
+ ```
48
+
49
+ ## Authentication
50
+
51
+ The SDK authenticates against the Barbara API using OAuth2 password grant. You need four credentials, referred to as **Barbara API Credentials**:
52
+
53
+ | Credential | Description |
54
+ |---|---|
55
+ | `BBR_API_USERNAME` | Your Barbara Panel username |
56
+ | `BBR_API_PASSWORD` | Your Barbara Panel password |
57
+ | `BBR_API_CLIENT_ID` | OAuth2 client ID, provided by Barbara |
58
+ | `BBR_API_CLIENT_SECRET` | OAuth2 client secret, provided by Barbara |
59
+
60
+ Panel credentials can be created at [onboarding.barbara.tech](https://onboarding.barbara.tech). Client credentials are issued by Barbara support (support@barbara.tech).
61
+
62
+ By default, the client reads credentials from environment variables:
63
+
64
+ ```bash
65
+ export BBR_API_USERNAME="..."
66
+ export BBR_API_PASSWORD="..."
67
+ export BBR_API_CLIENT_ID="..."
68
+ export BBR_API_CLIENT_SECRET="..."
69
+ ```
70
+
71
+ ```python
72
+ from barbara import BarbaraClient
73
+
74
+ client = BarbaraClient.from_env()
75
+ ```
76
+
77
+ Additional optional environment variables:
78
+
79
+ | Variable | Description | Default |
80
+ |---|---|---|
81
+ | `BBR_API_URL` | Barbara API base URL | `https://prod.bap.barbara.tech` |
82
+ | `BBR_AUTH_URL` | Barbara auth server base URL | `https://prod.auth.barbara.tech/auth` |
83
+ | `BBR_REALM` | Keycloak realm | `bbr_prod` |
84
+
85
+ Credentials can also be supplied explicitly instead of through environment variables:
86
+
87
+ ```python
88
+ from barbara import BarbaraClient, BarbaraConfig
89
+
90
+ config = BarbaraConfig(
91
+ client_id="...",
92
+ client_secret="...",
93
+ username="...",
94
+ password="...",
95
+ )
96
+ client = BarbaraClient(config)
97
+ ```
98
+
99
+ ## Quick start
100
+
101
+ ```python
102
+ from barbara import BarbaraClient
103
+
104
+ with BarbaraClient.from_env() as client:
105
+ for device in client.devices.list():
106
+ print(device.device_name, device.status)
107
+
108
+ device = client.devices.resolve("my-device-01")
109
+ ```
110
+
111
+ ### Async usage
112
+
113
+ `AsyncBarbaraClient` mirrors `BarbaraClient` method for method; only `await` differs.
114
+
115
+ ```python
116
+ import asyncio
117
+ from barbara import AsyncBarbaraClient
118
+
119
+ async def main():
120
+ async with AsyncBarbaraClient.from_env() as client:
121
+ devices = await client.devices.list()
122
+
123
+ asyncio.run(main())
124
+ ```
125
+
126
+ ## Usage
127
+
128
+ ### Devices
129
+
130
+ ```python
131
+ devices = client.devices.list(search="sensor")
132
+ device = client.devices.get("<device-id>")
133
+ device = client.devices.resolve("my-device-01") # look up by device name
134
+
135
+ client.devices.reboot("<device-id>")
136
+ client.devices.poweroff("<device-id>")
137
+ ```
138
+
139
+ #### Device secrets
140
+
141
+ ```python
142
+ client.devices.create_secrets("<device-id>", {"wifi-psk": "s3cr3t"})
143
+ secrets = client.devices.list_secrets("<device-id>")
144
+ client.devices.delete_secret("<device-id>", "<secret-id>")
145
+ ```
146
+
147
+ #### Device app configuration
148
+
149
+ ```python
150
+ client.devices.set_appconfig("<device-id>", config={"threshold": 5})
151
+ config = client.devices.get_appconfig("<device-id>")
152
+ ```
153
+
154
+ #### Docker credentials
155
+
156
+ ```python
157
+ client.devices.create_docker_credentials(
158
+ "<device-id>", [{"user": "bob", "password": "s3cr3t", "server": "docker.io"}]
159
+ )
160
+ ```
161
+
162
+ ### Device workloads
163
+
164
+ Deploy and manage applications running on a device.
165
+
166
+ ```python
167
+ client.devices.workloads.create_user_workload(
168
+ "<device-id>",
169
+ app_version_id="<app-version-id>",
170
+ application_id="<application-id>",
171
+ )
172
+
173
+ client.devices.workloads.create_market_workload(
174
+ "<device-id>",
175
+ app_version_id="<app-version-id>",
176
+ application_id="<application-id>",
177
+ name="my-workload",
178
+ services=[{"name": "modelservice", "ports": {"PORT_NUMBER": "9083"}}],
179
+ )
180
+
181
+ client.devices.workloads.start("<device-id>", "<workload-id>")
182
+ client.devices.workloads.stop("<device-id>", "<workload-id>")
183
+ logs = client.devices.workloads.get_logs("<device-id>", "<workload-id>")
184
+ ```
185
+
186
+ Creation and update calls do not return the resulting workload state; call `client.devices.workloads.get(...)` afterwards if you need it.
187
+
188
+ ### Clusters
189
+
190
+ ```python
191
+ clusters = client.clusters.list()
192
+ cluster = client.clusters.get("<cluster-id>")
193
+ client.clusters.update("<cluster-id>", "new-name")
194
+
195
+ client.clusters.create_secrets("<cluster-id>", {"db-password": "s3cr3t"})
196
+ client.clusters.set_appconfig("<cluster-id>", config={"threshold": 5})
197
+ ```
198
+
199
+ ### Cluster stacks
200
+
201
+ The cluster-level equivalent of device workloads — deploy an application across every device in a cluster.
202
+
203
+ ```python
204
+ client.clusters.stacks.create_user_stack(
205
+ "<cluster-id>",
206
+ app_version_id="<app-version-id>",
207
+ application_id="<application-id>",
208
+ )
209
+
210
+ client.clusters.stacks.delete("<cluster-id>", "<stack-id>")
211
+ ```
212
+
213
+ ### Applications
214
+
215
+ ```python
216
+ apps = client.applications.list()
217
+
218
+ client.applications.create(
219
+ "edge-app", "Long description", "Barbara", docker=True, icon_path="./icon.png"
220
+ )
221
+
222
+ client.applications.create_version(
223
+ "<application-id>", "./app-v1.tar", "1.0.0", ["amd64"], ["Initial release"]
224
+ )
225
+ ```
226
+
227
+ `create` and `create_version` upload files (icon, installable artifact) as `multipart/form-data`. Pass a local file path; the SDK reads the file and builds the request.
228
+
229
+ ### Models
230
+
231
+ ```python
232
+ models = client.models.list()
233
+
234
+ client.models.create(
235
+ "anomaly-detector", "Long description", "Barbara", model_type=0, engine=0
236
+ )
237
+
238
+ client.models.create_version("<model-id>", "./model.onnx", "1.0.0", ["Initial release"])
239
+ ```
240
+
241
+ `sha256` and `size` for a model version are computed automatically from the artifact.
242
+
243
+ ### App configurations
244
+
245
+ Reusable, named application configurations that can be referenced by ID elsewhere in the API.
246
+
247
+ ```python
248
+ app_config = client.appconfig.create(
249
+ name="sensor-thresholds",
250
+ description="Per-device alert thresholds",
251
+ config={"temperature_max": 80},
252
+ )
253
+ ```
254
+
255
+ ### Groups
256
+
257
+ ```python
258
+ group = client.groups.create(
259
+ name="floor-2-sensors",
260
+ description="All floor 2 devices",
261
+ device_ids=["<device-id-1>", "<device-id-2>"],
262
+ )
263
+ ```
264
+
265
+ ### Users
266
+
267
+ ```python
268
+ users = client.users.list()
269
+ page = client.users.paginate(offset=0, size=50)
270
+ ```
271
+
272
+ ### Alerts
273
+
274
+ ```python
275
+ alerts = client.alerts.list()
276
+ client.alerts.ack("<alert-id>")
277
+ events = client.alerts.list_events(device_id="<device-id>")
278
+ ```
279
+
280
+ ## Error handling
281
+
282
+ All API errors raise a subclass of `BarbaraApiError`:
283
+
284
+ ```python
285
+ from barbara import BarbaraApiError, BarbaraAuthError, BarbaraNotFoundError, BarbaraPermissionError
286
+
287
+ try:
288
+ client.devices.resolve("unknown-device")
289
+ except BarbaraNotFoundError:
290
+ ...
291
+ except BarbaraPermissionError:
292
+ ...
293
+ except BarbaraApiError as e:
294
+ print(e.status, e.body)
295
+ ```
296
+
297
+ ## Design
298
+
299
+ - **One client, one resource tree.** `BarbaraClient` and `AsyncBarbaraClient` expose the same resources (`.devices`, `.clusters`, `.applications`, ...) with identical method signatures.
300
+ - **Automatic token refresh.** A request that receives a 401 is retried once with a freshly fetched token.
301
+ - **Lightweight typed models.** Response entities are plain dataclasses, not a heavyweight validation layer. Every entity keeps the original API payload in `.raw`.
302
+ - **Typed exceptions.** `BarbaraNotFoundError`, `BarbaraAuthError`, and `BarbaraPermissionError` subclass `BarbaraApiError` so callers can handle specific failure modes.
303
+
304
+ ## API reference
305
+
306
+ | Resource | Description |
307
+ |---|---|
308
+ | `client.devices` | Device lifecycle, secrets, app configuration, docker credentials, and actions (reboot, provision, ...) |
309
+ | `client.devices.workloads` | Applications deployed on a device |
310
+ | `client.clusters` | Cluster lifecycle, secrets, app configuration, and docker credentials |
311
+ | `client.clusters.stacks` | Applications deployed across a cluster |
312
+ | `client.applications` | Application catalog and versions |
313
+ | `client.models` | Model catalog and versions |
314
+ | `client.appconfig` | Reusable application configurations |
315
+ | `client.groups` | Device groups |
316
+ | `client.users` | Company users (read-only) |
317
+ | `client.alerts` | Alerts and alert events |
318
+
319
+ See each resource module's docstrings, or the [Barbara API documentation](https://prod.bap.barbara.tech/documentation/), for the full method reference.
320
+
321
+ ## Roadmap
322
+
323
+ The following areas of the Barbara API are not yet covered by this SDK:
324
+
325
+ - Device network configuration (interfaces, NTP, proxy, VPN)
326
+ - Cluster creation and device cluster-membership management
327
+ - Model-type workloads and stacks
328
+
329
+ ## Contributing
330
+
331
+ See [CONTRIBUTING.md](CONTRIBUTING.md). For the release process, see [RELEASING.md](RELEASING.md).
332
+
333
+ ## License
334
+
335
+ MIT — see [LICENSE](LICENSE).