busylib 0.0.1__tar.gz → 0.0.2__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.

Potentially problematic release.


This version of busylib might be problematic. Click here for more details.

busylib-0.0.2/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright © 2025 Flipper Devices Inc.
2
+
3
+ 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 permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ 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.
busylib-0.0.2/PKG-INFO ADDED
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: busylib
3
+ Version: 0.0.2
4
+ Summary: Python library for Busy Bar API
5
+ Author-email: Valerii Lisai <v.lisai@flipperdevices.com>
6
+ Project-URL: Homepage, https://github.com/busy-app/busylib
7
+ Project-URL: Repository, https://github.com/busy-app/busylib
8
+ Project-URL: Documentation, https://busylib.readthedocs.io
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: requests==2.32.4
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest==8.4.1; extra == "dev"
23
+ Requires-Dist: requests-mock==1.12.1; extra == "dev"
24
+ Requires-Dist: ruff; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ # busylib
28
+
29
+ A simple and intuitive Python client for interacting with the Busy Bar API. This library allows you to programmatically control the device's display, audio, and assets.
30
+
31
+ ## Features
32
+
33
+ - Easy-to-use API for all major device functions.
34
+ - Upload and manage assets for your applications.
35
+ - Control the display by drawing text and images.
36
+ - Play and stop audio files.
37
+ - Built-in validation for device IP addresses.
38
+
39
+ ## Installation
40
+
41
+ You can install `busylib` directly from PyPI:
42
+
43
+ ```bash
44
+ pip install busylib
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ First, import and initialize the `BusyBar` client with the IP address of your device.
50
+
51
+ ```python
52
+ from busylib import BusyBar
53
+
54
+ try:
55
+ # Default IP is 10.0.4.20, but you can specify your own
56
+ bb = BusyBar("192.168.1.100")
57
+ except ValueError as e:
58
+ print(f"Error: {e}")
59
+
60
+ # Now you can use the bb object to interact with your device.
61
+ ```
62
+
63
+ ## API Examples
64
+
65
+ Here are some examples of how to use the library to control your Busy Bar device.
66
+
67
+ ### Uploading an Asset
68
+
69
+ You can upload files (like images or sounds) to be used by your application on the device.
70
+
71
+ ```python
72
+ # Upload a file from bytes
73
+ with open("path/to/your/image.png", "rb") as f:
74
+ file_bytes = f.read()
75
+ bb.upload_asset(
76
+ app_id="my-app",
77
+ file_name="logo.png",
78
+ file=file_bytes
79
+ )
80
+
81
+ # Or upload directly from a file-like object
82
+ with open("path/to/your/sound.mp3", "rb") as f:
83
+ bb.upload_asset(
84
+ app_id="my-app",
85
+ file_name="notification.mp3",
86
+ file=f
87
+ )
88
+ ```
89
+
90
+ ### Drawing on the Display
91
+
92
+ Draw text or images on the device's screen. The `draw_display` method accepts a list of elements to render.
93
+
94
+ ```python
95
+ elements = [
96
+ {
97
+ "type": "text",
98
+ "value": "Hello, World!",
99
+ "x": 10,
100
+ "y": 20,
101
+ "color": "#FFFFFF" # Optional
102
+ },
103
+ {
104
+ "type": "image",
105
+ "path": "logo.png", # Must be uploaded first
106
+ "x": 50,
107
+ "y": 40
108
+ }
109
+ ]
110
+
111
+ bb.draw_display(app_id="my-app", elements=elements)
112
+ ```
113
+
114
+ ### Clearing the Display
115
+
116
+ To clear everything from the screen:
117
+
118
+ ```python
119
+ bb.clear_display()
120
+ ```
121
+
122
+ ### Playing a Sound
123
+
124
+ Play an audio file that you have already uploaded.
125
+
126
+ ```python
127
+ bb.play_sound(app_id="my-app", path="notification.mp3")
128
+ ```
129
+
130
+ ### Stopping a Sound
131
+
132
+ To stop any audio that is currently playing:
133
+
134
+ ```python
135
+ bb.stop_sound()
136
+ ```
137
+
138
+ ### Deleting All Assets for an App
139
+
140
+ This will remove all files associated with a specific `app_id`.
141
+
142
+ ```python
143
+ bb.delete_assets(app_id="my-app")
144
+ ```
145
+
146
+ ## Development
147
+
148
+ To set up a development environment, clone the repository and install the package in editable mode with test dependencies:
149
+
150
+ ```bash
151
+ git clone https://github.com/busy-app/busylib
152
+ cd busylib
153
+ python3 -m venv .venv
154
+ source .venv/bin/activate
155
+ make install-dev
156
+ ```
157
+
158
+ To run the tests:
159
+
160
+ ```bash
161
+ make test
162
+ ```
@@ -0,0 +1,136 @@
1
+ # busylib
2
+
3
+ A simple and intuitive Python client for interacting with the Busy Bar API. This library allows you to programmatically control the device's display, audio, and assets.
4
+
5
+ ## Features
6
+
7
+ - Easy-to-use API for all major device functions.
8
+ - Upload and manage assets for your applications.
9
+ - Control the display by drawing text and images.
10
+ - Play and stop audio files.
11
+ - Built-in validation for device IP addresses.
12
+
13
+ ## Installation
14
+
15
+ You can install `busylib` directly from PyPI:
16
+
17
+ ```bash
18
+ pip install busylib
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ First, import and initialize the `BusyBar` client with the IP address of your device.
24
+
25
+ ```python
26
+ from busylib import BusyBar
27
+
28
+ try:
29
+ # Default IP is 10.0.4.20, but you can specify your own
30
+ bb = BusyBar("192.168.1.100")
31
+ except ValueError as e:
32
+ print(f"Error: {e}")
33
+
34
+ # Now you can use the bb object to interact with your device.
35
+ ```
36
+
37
+ ## API Examples
38
+
39
+ Here are some examples of how to use the library to control your Busy Bar device.
40
+
41
+ ### Uploading an Asset
42
+
43
+ You can upload files (like images or sounds) to be used by your application on the device.
44
+
45
+ ```python
46
+ # Upload a file from bytes
47
+ with open("path/to/your/image.png", "rb") as f:
48
+ file_bytes = f.read()
49
+ bb.upload_asset(
50
+ app_id="my-app",
51
+ file_name="logo.png",
52
+ file=file_bytes
53
+ )
54
+
55
+ # Or upload directly from a file-like object
56
+ with open("path/to/your/sound.mp3", "rb") as f:
57
+ bb.upload_asset(
58
+ app_id="my-app",
59
+ file_name="notification.mp3",
60
+ file=f
61
+ )
62
+ ```
63
+
64
+ ### Drawing on the Display
65
+
66
+ Draw text or images on the device's screen. The `draw_display` method accepts a list of elements to render.
67
+
68
+ ```python
69
+ elements = [
70
+ {
71
+ "type": "text",
72
+ "value": "Hello, World!",
73
+ "x": 10,
74
+ "y": 20,
75
+ "color": "#FFFFFF" # Optional
76
+ },
77
+ {
78
+ "type": "image",
79
+ "path": "logo.png", # Must be uploaded first
80
+ "x": 50,
81
+ "y": 40
82
+ }
83
+ ]
84
+
85
+ bb.draw_display(app_id="my-app", elements=elements)
86
+ ```
87
+
88
+ ### Clearing the Display
89
+
90
+ To clear everything from the screen:
91
+
92
+ ```python
93
+ bb.clear_display()
94
+ ```
95
+
96
+ ### Playing a Sound
97
+
98
+ Play an audio file that you have already uploaded.
99
+
100
+ ```python
101
+ bb.play_sound(app_id="my-app", path="notification.mp3")
102
+ ```
103
+
104
+ ### Stopping a Sound
105
+
106
+ To stop any audio that is currently playing:
107
+
108
+ ```python
109
+ bb.stop_sound()
110
+ ```
111
+
112
+ ### Deleting All Assets for an App
113
+
114
+ This will remove all files associated with a specific `app_id`.
115
+
116
+ ```python
117
+ bb.delete_assets(app_id="my-app")
118
+ ```
119
+
120
+ ## Development
121
+
122
+ To set up a development environment, clone the repository and install the package in editable mode with test dependencies:
123
+
124
+ ```bash
125
+ git clone https://github.com/busy-app/busylib
126
+ cd busylib
127
+ python3 -m venv .venv
128
+ source .venv/bin/activate
129
+ make install-dev
130
+ ```
131
+
132
+ To run the tests:
133
+
134
+ ```bash
135
+ make test
136
+ ```
@@ -0,0 +1,82 @@
1
+ """
2
+ Main library for interacting with the Busy Bar API.
3
+ """
4
+
5
+ from typing import IO
6
+
7
+ from busylib.client import ApiClient
8
+ from busylib.types import ApiResponse
9
+
10
+
11
+ class BusyBar:
12
+ """
13
+ Main library class for interacting with the Busy Bar API.
14
+ """
15
+
16
+ def __init__(self, addr: str = "10.0.4.20"):
17
+ """
18
+ Creates an instance of BUSY Bar.
19
+ Initializes the API client with the provided address.
20
+
21
+ :param addr: The address of the device.
22
+ """
23
+ self._addr = addr
24
+ self._client = ApiClient(f"http://{self._addr}/api/")
25
+
26
+ def upload_asset(
27
+ self, app_id: str, file_name: str, file: bytes | IO[bytes]
28
+ ) -> ApiResponse | None:
29
+ """
30
+ Uploads an asset to the device.
31
+
32
+ :param app_id: Application ID for organizing assets.
33
+ :param file_name: Filename for the uploaded asset.
34
+ :param file: File data to upload (bytes or file-like object).
35
+ :return: Result of the upload operation.
36
+ """
37
+ return self._client.upload_asset(app_id, file_name, file)
38
+
39
+ def delete_assets(self, app_id: str) -> ApiResponse | None:
40
+ """
41
+ Deletes all assets for a specific application from the device.
42
+
43
+ :param app_id: Application ID whose assets should be deleted.
44
+ :return: Result of the delete operation.
45
+ """
46
+ return self._client.delete_assets(app_id)
47
+
48
+ def draw_display(self, app_id: str, elements: list[dict]) -> ApiResponse | None:
49
+ """
50
+ Draws elements on the device display.
51
+
52
+ :param app_id: Application ID for organizing display elements.
53
+ :param elements: Array of display elements (text or image).
54
+ :return: Result of the draw operation.
55
+ """
56
+ return self._client.draw_display(app_id, elements)
57
+
58
+ def clear_display(self) -> ApiResponse | None:
59
+ """
60
+ Clears the device display.
61
+
62
+ :return: Result of the clear operation.
63
+ """
64
+ return self._client.clear_display()
65
+
66
+ def play_sound(self, app_id: str, path: str) -> ApiResponse | None:
67
+ """
68
+ Plays an audio file from the assets directory.
69
+
70
+ :param app_id: Application ID for organizing assets.
71
+ :param path: Path to the audio file within the app's assets directory.
72
+ :return: Result of the play operation.
73
+ """
74
+ return self._client.play_audio(app_id, path)
75
+
76
+ def stop_sound(self) -> ApiResponse | None:
77
+ """
78
+ Stops any currently playing audio on the device.
79
+
80
+ :return: Result of the stop operation.
81
+ """
82
+ return self._client.stop_audio()
@@ -0,0 +1,108 @@
1
+ import requests
2
+ from typing import IO
3
+ from busylib.types import ApiResponse
4
+
5
+
6
+ class ApiClient:
7
+ def __init__(self, base_url: str):
8
+ if not base_url.endswith("/"):
9
+ base_url += "/"
10
+ self.base_url = base_url
11
+ self.session = requests.Session()
12
+
13
+ def _request(
14
+ self,
15
+ method: str,
16
+ endpoint: str,
17
+ params: dict[str, object] | None = None,
18
+ json: object | None = None,
19
+ data: object | None = None,
20
+ headers: dict[str, str] | None = None,
21
+ ) -> ApiResponse:
22
+ url = f"{self.base_url}{endpoint}"
23
+ try:
24
+ response = self.session.request(
25
+ method, url, params=params, json=json, data=data, headers=headers
26
+ )
27
+ response.raise_for_status()
28
+ if response.status_code == 204 or not response.content:
29
+ return None
30
+ # We expect a JSON response that can be mapped to our dataclass
31
+ data = response.json()
32
+ return ApiResponse(
33
+ success=data.get("success", True), message=data.get("message")
34
+ )
35
+ except requests.exceptions.RequestException as e:
36
+ # Re-raise as a custom exception for better error handling upstream
37
+ raise ConnectionError(f"API request failed: {e}") from e
38
+
39
+ def post(
40
+ self,
41
+ endpoint: str,
42
+ params: dict[str, object] = None,
43
+ json: object | None = None,
44
+ data: object | None = None,
45
+ headers: dict[str, str] | None = None,
46
+ ) -> ApiResponse | None:
47
+ return self._request(
48
+ "POST", endpoint, params=params, json=json, data=data, headers=headers
49
+ )
50
+
51
+ def get(
52
+ self, endpoint: str, params: dict[str, object] | None = None
53
+ ) -> ApiResponse | None:
54
+ return self._request("GET", endpoint, params=params)
55
+
56
+ def delete(
57
+ self, endpoint: str, params: dict[str, object] | None = None
58
+ ) -> ApiResponse | None:
59
+ return self._request("DELETE", endpoint, params=params)
60
+
61
+ def upload_asset(
62
+ self, app_id: str, file_name: str, file: bytes | IO[bytes]
63
+ ) -> ApiResponse | None:
64
+ """
65
+ Uploads an asset to the device.
66
+ """
67
+ payload = {"app_id": app_id, "file": file_name}
68
+ headers = {"Content-Type": "application/octet-stream"}
69
+ return self.post("v0/assets/upload", params=payload, data=file, headers=headers)
70
+
71
+ def delete_assets(self, app_id: str) -> ApiResponse | None:
72
+ """
73
+ Deletes all assets for a specific application from the device.
74
+ """
75
+ params = {"app_id": app_id}
76
+ return self.delete("v0/assets/upload", params=params)
77
+
78
+ def play_audio(self, app_id: str, path: str) -> ApiResponse | None:
79
+ """
80
+ Plays an audio file from the assets directory.
81
+ """
82
+ params = {"app_id": app_id, "path": path}
83
+ return self.post("v0/audio/play", params=params)
84
+
85
+ def stop_audio(self) -> ApiResponse | None:
86
+ """
87
+ Stops any currently playing audio on the device.
88
+ """
89
+ return self.delete("v0/audio/play")
90
+
91
+ def draw_display(
92
+ self, app_id: str, elements: list[dict[str, object]]
93
+ ) -> ApiResponse | None:
94
+ """
95
+ Draws elements on the device display.
96
+ """
97
+ default_values = {"timeout": 5, "x": 0, "y": 0, "display": "front"}
98
+
99
+ normalized_elements = [default_values | e for e in elements]
100
+ return self.post(
101
+ "v0/display/draw", json={"app_id": app_id, "elements": normalized_elements}
102
+ )
103
+
104
+ def clear_display(self) -> ApiResponse | None:
105
+ """
106
+ Clears the device display.
107
+ """
108
+ return self.delete("v0/display/draw")
@@ -0,0 +1,9 @@
1
+ import dataclasses
2
+
3
+
4
+ @dataclasses.dataclass(frozen=True)
5
+ class ApiResponse:
6
+ """A generic response from the BusyBar API"""
7
+
8
+ success: bool
9
+ message: str | None = None
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: busylib
3
+ Version: 0.0.2
4
+ Summary: Python library for Busy Bar API
5
+ Author-email: Valerii Lisai <v.lisai@flipperdevices.com>
6
+ Project-URL: Homepage, https://github.com/busy-app/busylib
7
+ Project-URL: Repository, https://github.com/busy-app/busylib
8
+ Project-URL: Documentation, https://busylib.readthedocs.io
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: requests==2.32.4
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest==8.4.1; extra == "dev"
23
+ Requires-Dist: requests-mock==1.12.1; extra == "dev"
24
+ Requires-Dist: ruff; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ # busylib
28
+
29
+ A simple and intuitive Python client for interacting with the Busy Bar API. This library allows you to programmatically control the device's display, audio, and assets.
30
+
31
+ ## Features
32
+
33
+ - Easy-to-use API for all major device functions.
34
+ - Upload and manage assets for your applications.
35
+ - Control the display by drawing text and images.
36
+ - Play and stop audio files.
37
+ - Built-in validation for device IP addresses.
38
+
39
+ ## Installation
40
+
41
+ You can install `busylib` directly from PyPI:
42
+
43
+ ```bash
44
+ pip install busylib
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ First, import and initialize the `BusyBar` client with the IP address of your device.
50
+
51
+ ```python
52
+ from busylib import BusyBar
53
+
54
+ try:
55
+ # Default IP is 10.0.4.20, but you can specify your own
56
+ bb = BusyBar("192.168.1.100")
57
+ except ValueError as e:
58
+ print(f"Error: {e}")
59
+
60
+ # Now you can use the bb object to interact with your device.
61
+ ```
62
+
63
+ ## API Examples
64
+
65
+ Here are some examples of how to use the library to control your Busy Bar device.
66
+
67
+ ### Uploading an Asset
68
+
69
+ You can upload files (like images or sounds) to be used by your application on the device.
70
+
71
+ ```python
72
+ # Upload a file from bytes
73
+ with open("path/to/your/image.png", "rb") as f:
74
+ file_bytes = f.read()
75
+ bb.upload_asset(
76
+ app_id="my-app",
77
+ file_name="logo.png",
78
+ file=file_bytes
79
+ )
80
+
81
+ # Or upload directly from a file-like object
82
+ with open("path/to/your/sound.mp3", "rb") as f:
83
+ bb.upload_asset(
84
+ app_id="my-app",
85
+ file_name="notification.mp3",
86
+ file=f
87
+ )
88
+ ```
89
+
90
+ ### Drawing on the Display
91
+
92
+ Draw text or images on the device's screen. The `draw_display` method accepts a list of elements to render.
93
+
94
+ ```python
95
+ elements = [
96
+ {
97
+ "type": "text",
98
+ "value": "Hello, World!",
99
+ "x": 10,
100
+ "y": 20,
101
+ "color": "#FFFFFF" # Optional
102
+ },
103
+ {
104
+ "type": "image",
105
+ "path": "logo.png", # Must be uploaded first
106
+ "x": 50,
107
+ "y": 40
108
+ }
109
+ ]
110
+
111
+ bb.draw_display(app_id="my-app", elements=elements)
112
+ ```
113
+
114
+ ### Clearing the Display
115
+
116
+ To clear everything from the screen:
117
+
118
+ ```python
119
+ bb.clear_display()
120
+ ```
121
+
122
+ ### Playing a Sound
123
+
124
+ Play an audio file that you have already uploaded.
125
+
126
+ ```python
127
+ bb.play_sound(app_id="my-app", path="notification.mp3")
128
+ ```
129
+
130
+ ### Stopping a Sound
131
+
132
+ To stop any audio that is currently playing:
133
+
134
+ ```python
135
+ bb.stop_sound()
136
+ ```
137
+
138
+ ### Deleting All Assets for an App
139
+
140
+ This will remove all files associated with a specific `app_id`.
141
+
142
+ ```python
143
+ bb.delete_assets(app_id="my-app")
144
+ ```
145
+
146
+ ## Development
147
+
148
+ To set up a development environment, clone the repository and install the package in editable mode with test dependencies:
149
+
150
+ ```bash
151
+ git clone https://github.com/busy-app/busylib
152
+ cd busylib
153
+ python3 -m venv .venv
154
+ source .venv/bin/activate
155
+ make install-dev
156
+ ```
157
+
158
+ To run the tests:
159
+
160
+ ```bash
161
+ make test
162
+ ```
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ busylib/__init__.py
6
+ busylib/client.py
7
+ busylib/types.py
8
+ busylib.egg-info/PKG-INFO
9
+ busylib.egg-info/SOURCES.txt
10
+ busylib.egg-info/dependency_links.txt
11
+ busylib.egg-info/requires.txt
12
+ busylib.egg-info/top_level.txt
13
+ tests/test_client.py
@@ -0,0 +1,6 @@
1
+ requests==2.32.4
2
+
3
+ [dev]
4
+ pytest==8.4.1
5
+ requests-mock==1.12.1
6
+ ruff
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "busylib"
7
+ version = "0.0.2"
8
+ description = "Python library for Busy Bar API"
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "Valerii Lisai", email = "v.lisai@flipperdevices.com"}
12
+ ]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ ]
23
+ requires-python = ">=3.10"
24
+ dependencies = [
25
+ "requests==2.32.4"
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pytest==8.4.1",
31
+ "requests-mock==1.12.1",
32
+ "ruff"
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/busy-app/busylib"
37
+ Repository = "https://github.com/busy-app/busylib"
38
+ Documentation = "https://busylib.readthedocs.io"
39
+
40
+
41
+ [tool.ruff]
42
+ exclude = [
43
+ ".git",
44
+ ".pytest_cache",
45
+ ".ruff_cache",
46
+ ".venv",
47
+ ".vscode",
48
+ "__pycache__",
49
+ "build",
50
+ "dist",
51
+ "venv"
52
+ ]
53
+
54
+ line-length = 88
55
+ indent-width = 4
56
+ target-version = "py310"
57
+
58
+ [tool.ruff.format]
59
+ quote-style = "double"
60
+ indent-style = "space"
61
+ skip-magic-trailing-comma = false
62
+ line-ending = "auto"
63
+ docstring-code-format = false
64
+ docstring-code-line-length = "dynamic"
busylib-0.0.2/setup.py ADDED
@@ -0,0 +1,4 @@
1
+ from setuptools import setup
2
+
3
+ setup()
4
+
@@ -0,0 +1,103 @@
1
+ import pytest
2
+ import requests
3
+ import requests_mock
4
+ from busylib.client import ApiClient
5
+
6
+ BASE_URL = "http://test.com"
7
+
8
+
9
+ @pytest.fixture
10
+ def api_client():
11
+ return ApiClient(BASE_URL)
12
+
13
+
14
+ @pytest.fixture
15
+ def mocked_requests():
16
+ with requests_mock.Mocker() as m:
17
+ yield m
18
+
19
+
20
+ def test_upload_asset(api_client, mocked_requests):
21
+ app_id = "test_app"
22
+ file_name = "test_file.png"
23
+ file_content = b"test content"
24
+ mocked_requests.post(f"{BASE_URL}/v0/assets/upload", status_code=204)
25
+
26
+ api_client.upload_asset(app_id, file_name, file_content)
27
+
28
+ assert mocked_requests.called
29
+ last_request = mocked_requests.last_request
30
+ assert last_request.method == "POST"
31
+ assert last_request.qs["app_id"] == [app_id]
32
+ assert last_request.qs["file"] == [file_name]
33
+ assert last_request.body == file_content
34
+
35
+
36
+ def test_delete_assets(api_client, mocked_requests):
37
+ app_id = "test_app"
38
+ mocked_requests.delete(f"{BASE_URL}/v0/assets/upload", status_code=204)
39
+
40
+ api_client.delete_assets(app_id)
41
+
42
+ assert mocked_requests.called
43
+ last_request = mocked_requests.last_request
44
+ assert last_request.method == "DELETE"
45
+ assert last_request.qs["app_id"] == [app_id]
46
+
47
+
48
+ def test_play_audio(api_client, mocked_requests):
49
+ app_id = "test_app"
50
+ path = "test.mp3"
51
+ mocked_requests.post(f"{BASE_URL}/v0/audio/play", status_code=204)
52
+
53
+ api_client.play_audio(app_id, path)
54
+
55
+ assert mocked_requests.called
56
+ last_request = mocked_requests.last_request
57
+ assert last_request.method == "POST"
58
+ assert last_request.qs["app_id"] == [app_id]
59
+ assert last_request.qs["path"] == [path]
60
+
61
+
62
+ def test_stop_audio(api_client, mocked_requests):
63
+ mocked_requests.delete(f"{BASE_URL}/v0/audio/play", status_code=204)
64
+
65
+ api_client.stop_audio()
66
+
67
+ assert mocked_requests.called
68
+ last_request = mocked_requests.last_request
69
+ assert last_request.method == "DELETE"
70
+
71
+
72
+ def test_draw_display(api_client, mocked_requests):
73
+ app_id = "test_app"
74
+ elements = [{"type": "text", "value": "Hello"}]
75
+ mocked_requests.post(f"{BASE_URL}/v0/display/draw", status_code=204)
76
+
77
+ api_client.draw_display(app_id, elements)
78
+
79
+ assert mocked_requests.called
80
+ last_request = mocked_requests.last_request
81
+ assert last_request.method == "POST"
82
+ json_body = last_request.json()
83
+ assert json_body["app_id"] == app_id
84
+ assert len(json_body["elements"]) == 1
85
+ assert json_body["elements"][0]["value"] == "Hello"
86
+
87
+
88
+ def test_clear_display(api_client, mocked_requests):
89
+ mocked_requests.delete(f"{BASE_URL}/v0/display/draw", status_code=204)
90
+
91
+ api_client.clear_display()
92
+
93
+ assert mocked_requests.called
94
+ last_request = mocked_requests.last_request
95
+ assert last_request.method == "DELETE"
96
+
97
+
98
+ def test_request_failure(api_client, mocked_requests):
99
+ mocked_requests.get(
100
+ f"{BASE_URL}/v0/some/endpoint", exc=requests.exceptions.ConnectionError
101
+ )
102
+ with pytest.raises(ConnectionError):
103
+ api_client.get("v0/some/endpoint")
busylib-0.0.1/PKG-INFO DELETED
@@ -1,19 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: busylib
3
- Version: 0.0.1
4
- Summary: Package name reserved
5
- Home-page: https://github.com/yourusername/busylib
6
- Author: Your Name
7
- Author-email: your.email@example.com
8
- Classifier: Development Status :: 1 - Planning
9
- Classifier: Programming Language :: Python :: 3
10
- Requires-Python: >=3.6
11
- Dynamic: author
12
- Dynamic: author-email
13
- Dynamic: classifier
14
- Dynamic: description
15
- Dynamic: home-page
16
- Dynamic: requires-python
17
- Dynamic: summary
18
-
19
- This package name is reserved for future use
busylib-0.0.1/README.md DELETED
File without changes
File without changes
@@ -1,19 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: busylib
3
- Version: 0.0.1
4
- Summary: Package name reserved
5
- Home-page: https://github.com/yourusername/busylib
6
- Author: Your Name
7
- Author-email: your.email@example.com
8
- Classifier: Development Status :: 1 - Planning
9
- Classifier: Programming Language :: Python :: 3
10
- Requires-Python: >=3.6
11
- Dynamic: author
12
- Dynamic: author-email
13
- Dynamic: classifier
14
- Dynamic: description
15
- Dynamic: home-page
16
- Dynamic: requires-python
17
- Dynamic: summary
18
-
19
- This package name is reserved for future use
@@ -1,7 +0,0 @@
1
- README.md
2
- setup.py
3
- busylib/__init__.py
4
- busylib.egg-info/PKG-INFO
5
- busylib.egg-info/SOURCES.txt
6
- busylib.egg-info/dependency_links.txt
7
- busylib.egg-info/top_level.txt
busylib-0.0.1/setup.py DELETED
@@ -1,18 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(
4
- name='busylib',
5
- version='0.0.1',
6
- description='Package name reserved',
7
- long_description='This package name is reserved for future use',
8
- url='https://github.com/yourusername/busylib',
9
- author='Your Name',
10
- author_email='your.email@example.com',
11
- packages=find_packages(),
12
- classifiers=[
13
- 'Development Status :: 1 - Planning',
14
- 'Programming Language :: Python :: 3',
15
- ],
16
- python_requires='>=3.6',
17
- )
18
-
File without changes