From 51faad2fd4286f03b502a17c424782f1133af782 Mon Sep 17 00:00:00 2001 From: SageCreations Date: Tue, 18 Feb 2025 17:30:36 -0600 Subject: [PATCH 1/3] added new example showing how to use send_raw, updated send_raw and send_raw_client functions, and updated version text to 2.5.2 --- PyPI/Package/README.md | 2 +- PyPI/Package/pyproject.toml | 2 +- PyPI/Package/src/webui/webui.py | 74 +++++++++++++++++++------- examples/sending-raw/index.html | 10 ++++ examples/sending-raw/main.py | 0 examples/sending-raw/webui_python.png | Bin 0 -> 6723 bytes 6 files changed, 66 insertions(+), 22 deletions(-) create mode 100644 examples/sending-raw/index.html create mode 100644 examples/sending-raw/main.py create mode 100644 examples/sending-raw/webui_python.png diff --git a/PyPI/Package/README.md b/PyPI/Package/README.md index f080236..d4755fe 100644 --- a/PyPI/Package/README.md +++ b/PyPI/Package/README.md @@ -1,4 +1,4 @@ -# Python WebUI v2.5.1 +# Python WebUI v2.5.2 > Use any web browser as GUI, with Python in the backend and HTML5 in the frontend, all in a lightweight Python package. diff --git a/PyPI/Package/pyproject.toml b/PyPI/Package/pyproject.toml index e5476af..314fd93 100644 --- a/PyPI/Package/pyproject.toml +++ b/PyPI/Package/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "webui2" -version = "2.5.1" +version = "2.5.2" authors = [ { name="Hassan Draga" }, ] diff --git a/PyPI/Package/src/webui/webui.py b/PyPI/Package/src/webui/webui.py index 750814c..3bd2a1b 100644 --- a/PyPI/Package/src/webui/webui.py +++ b/PyPI/Package/src/webui/webui.py @@ -1,4 +1,4 @@ -# Python WebUI v2.5.1 +# Python WebUI v2.5.2 # # http://webui.me # https://github.com/webui-dev/python-webui @@ -11,6 +11,7 @@ # webui.py from __future__ import annotations +import array import warnings from typing import Callable, Optional from ctypes import * @@ -210,29 +211,45 @@ def close_client(self) -> None: _raw.webui_close_client(byref(self._c_event())) # -- send_raw_client ---------------------------- - def send_raw_client(self, function: str, raw: Optional[int], size: int) -> None: + def send_raw_client(self, function: str, data: Union[bytes, bytearray, memoryview, array.array]) -> None: """Safely send raw data to the UI for a single client. This function sends raw data to a JavaScript function in the UI. The JavaScript function must be defined to accept the raw data, such as: `function myFunc(myData) {}`. Args: - function (str): The name of the JavaScript function to receive the raw data, encoded in UTF-8. - raw (Optional[int]): The pointer to the raw data buffer. Must not be `None`. - size (int): The size of the raw data buffer in bytes. + function (str): The name of the JavaScript function to receive the raw data. + data (Union[bytes, bytearray, memoryview, array.array]): The raw data buffer. Raises: - ValueError: If `raw` is `None`. + ValueError: If `data` is `None` or empty. Example: - e.send_raw_client("myJavaScriptFunc", my_buffer, 64) + e.send_raw_client("myJavaScriptFunc", bytearray([0x01, 0x0A, 0xFF])) + # Sends 3 bytes of raw data to the JavaScript function `myJavaScriptFunc`. """ - if raw is None: - raise ValueError("Invalid Pointer: Cannot send a null pointer.") + if data is None or len(data) == 0: + raise ValueError("Data must not be None or empty.") + + # Ensure data is a memoryview for uniformity + if not isinstance(data, memoryview): + data = memoryview(data) + + # Ensure that data is a writable copy to obtain void pointer, + # from_buffer will throw error if the buffer passed in is not writable. + if data.readonly: + data = memoryview(bytearray(data)) + + # Obtain a c_void_p pointer to the data buffer + ptr = c_void_p(addressof(c_char.from_buffer(data))) + + # Determine the size of the data + size = len(data) + _raw.webui_send_raw_client( byref(self._c_event()), c_char_p(function.encode("utf-8")), - c_void_p(raw), + ptr, c_size_t(size) ) @@ -1025,33 +1042,50 @@ def set_icon(self, icon: str, icon_type: str) -> None: _raw.webui_set_icon(c_size_t(self._window), icon.encode("utf-8"), icon_type.encode("utf-8")) # -- send_raw ----------------------------------- - def send_raw(self, function: str, raw: Optional[c_void_p], size: int) -> None: - """Safely send raw data to the UI for all clients. + def send_raw(self, function: str, data: Union[bytes, bytearray, memoryview, array.array]) -> None: + """ + Safely send raw data to the UI for all clients. This function sends a raw data buffer to a JavaScript function in the UI. The JavaScript function should be capable of handling raw binary data. Args: function (str): The JavaScript function that will receive the raw data. - raw (Optional[c_void_p]): A pointer to the raw data buffer. Must not be `None`. - size (int): The size of the raw data in bytes. + data (Union[bytes, bytearray, memoryview, array.array]): The raw data buffer. Raises: - ValueError: If `raw` is `None`. + ValueError: If `data` is `None` or empty. Returns: None Example: - my_window.send_raw("myJavaScriptFunc", my_buffer, 64) - # Sends 64 bytes of raw data to the JavaScript function `myJavaScriptFunc`. + my_window.send_raw("myJavaScriptFunc", bytearray([0x01, 0x0A, 0xFF])) + # Sends 3 bytes of raw data to the JavaScript function `myJavaScriptFunc`. """ - if raw is None: - raise ValueError("Invalid pointer: Cannot send a null pointer.") + if data is None or len(data) == 0: + raise ValueError("Data must not be None or empty.") + + # Ensure data is a memoryview for uniformity + if not isinstance(data, memoryview): + data = memoryview(data) + + # Ensure that data is a writable copy to obtain void pointer, + # from_buffer will throw error if the buffer passed in is not writable. + if data.readonly: + data = memoryview(bytearray(data)) + + # Obtain a c_void_p pointer to the data buffer + ptr = c_void_p(addressof(c_char.from_buffer(data))) + + # Determine the size of the data + size = len(data) + + # Call the underlying function to send the data _raw.webui_send_raw( c_size_t(self._window), c_char_p(function.encode("utf-8")), - c_void_p(raw), + ptr, c_size_t(size) ) diff --git a/examples/sending-raw/index.html b/examples/sending-raw/index.html new file mode 100644 index 0000000..566549b --- /dev/null +++ b/examples/sending-raw/index.html @@ -0,0 +1,10 @@ + + + + + Title + + + + + \ No newline at end of file diff --git a/examples/sending-raw/main.py b/examples/sending-raw/main.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/sending-raw/webui_python.png b/examples/sending-raw/webui_python.png new file mode 100644 index 0000000000000000000000000000000000000000..016c4a91000a2493395005c674bda79afbe6d4e9 GIT binary patch literal 6723 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 ws Date: Tue, 18 Feb 2025 21:01:55 -0600 Subject: [PATCH 2/3] Update README.md fixed version number --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63af5ca..006382d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![Logo](https://raw.githubusercontent.com/webui-dev/webui-logo/main/webui_python.png) -# Python-WebUI v2.5.1 +# Python-WebUI v2.5.2 [last-commit]: https://img.shields.io/github/last-commit/webui-dev/webui?style=for-the-badge&logo=github&logoColor=C0CAF5&labelColor=414868 [release-version]: https://img.shields.io/github/v/tag/webui-dev/webui?style=for-the-badge&logo=webtrees&logoColor=C0CAF5&labelColor=414868&color=7664C6 From 952b7e681688cd91dd3a3f3fe8a89a3dcbddc209 Mon Sep 17 00:00:00 2001 From: SageCreations Date: Wed, 19 Feb 2025 13:45:56 -0600 Subject: [PATCH 3/3] forgot to add the example edits --- examples/sending-raw/index.html | 22 ++++++++++++++++++++++ examples/sending-raw/main.py | 24 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/examples/sending-raw/index.html b/examples/sending-raw/index.html index 566549b..73bbdf6 100644 --- a/examples/sending-raw/index.html +++ b/examples/sending-raw/index.html @@ -5,6 +5,28 @@ Title +

Hello there!

+ + \ No newline at end of file diff --git a/examples/sending-raw/main.py b/examples/sending-raw/main.py index e69de29..88392d7 100644 --- a/examples/sending-raw/main.py +++ b/examples/sending-raw/main.py @@ -0,0 +1,24 @@ +from webui import webui + +def main(): + # Create an instance of a Window object + my_window = webui.Window() + + # Open an image file and read it in as byte data. + with open("./webui_python.png", 'rb') as file: + raw_bytes: bytes = file.read() + + # Open the window using the html file in the project while getting the appropriate browser for the user. + my_window.show_browser("index.html", my_window.get_best_browser()) + + #print(raw_bytes) + # Send over the byte data from the picture to the javascript function we have in the html. + my_window.send_raw("myJavaScriptFunc", raw_bytes) + + # waits for all windows to close before terminating the program. + webui.wait() + +if __name__ == "__main__": + main() + +