From bddefc4ce1f2d7329730ca4d5ccf53e88b720edd Mon Sep 17 00:00:00 2001 From: Jaiden <38144027+jaidenlab@users.noreply.github.com> Date: Tue, 26 Nov 2024 20:09:15 -0500 Subject: [PATCH 1/3] Revert publish workflow to before adding cibuildwheels --- .github/workflows/publish.yml | 73 ++++++++++++----------------------- 1 file changed, 24 insertions(+), 49 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5e0849a..c11ff7a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,57 +1,37 @@ name: Publish -on: - workflow_dispatch: - pull_request: - push: - branches: - - main - release: - types: - - published +on: push jobs: - build_wheels: - name: Build wheels on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - - steps: - - uses: actions/checkout@v4 - - - name: Build wheels - uses: pypa/cibuildwheel@v2.22.0 - env: - CIBW_BEFORE_ALL: pip install lz4==4.3.3 - - - name: Store the distribution packages - uses: actions/upload-artifact@v4 - with: - name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} - path: ./wheelhouse/*.whl - - build_sdist: - name: Build source distribution + build: + name: Build distribution runs-on: ubuntu-latest + steps: + # Download the repository into the CI runner + # Then, install and activate the newest Python 3 release - uses: actions/checkout@v4 - - - name: Build sdist - run: pipx run build --sdist - + - name: set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Install pypa/build + run: python3 -m pip install build --user + # Build the dists from source and store them + - name: Build a binary wheel and a source tarball + run: python3 -m build - name: Store the distribution packages uses: actions/upload-artifact@v4 with: - name: cibw-sdist - path: dist/*.tar.gz + name: python-package-distributions + path: dist/ publish-to-pypi: name: Publish distribution to PyPI # Only publish to PyPI on tag pushes if: startsWith(github.ref, 'refs/tags/') - needs: [build_wheels, build_sdist] + needs: + - build runs-on: ubuntu-latest environment: name: pypi @@ -62,10 +42,8 @@ jobs: - name: Download the distribution packages uses: actions/download-artifact@v4 with: - pattern: cibw-* + name: python-package-distributions path: dist/ - merge-multiple: true - - name: Publish distribution to PyPI uses: pypa/gh-action-pypi-publish@release/v1 @@ -85,10 +63,8 @@ jobs: - name: Download all the dists uses: actions/download-artifact@v4 with: - pattern: cibw-* + name: python-package-distributions path: dist/ - merge-multiple: true - - name: Sign the dists with Sigstore uses: sigstore/gh-action-sigstore-python@v3.0.0 with: @@ -117,7 +93,8 @@ jobs: publish-to-testpypi: name: Publish distribution to TestPyPI - needs: [build_wheels, build_sdist] + needs: + - build runs-on: ubuntu-latest environment: @@ -131,10 +108,8 @@ jobs: - name: Download the distribution packages uses: actions/download-artifact@v4 with: - pattern: cibw-* + name: python-package-distributions path: dist/ - merge-multiple: true - - name: Publish distribution to TestPyPI uses: pypa/gh-action-pypi-publish@release/v1 with: From 90b654c66ddbaf00f76c67400d07dfd597fe7d11 Mon Sep 17 00:00:00 2001 From: Jaiden <38144027+jaidenlab@users.noreply.github.com> Date: Tue, 26 Nov 2024 20:03:38 -0500 Subject: [PATCH 2/3] Remove python-lz4 entirely --- requirements.txt | Bin 700 -> 702 bytes tuya_vacuum/lz4.py | 105 +++++++++++++++++++++++++++++++ tuya_vacuum/vacuum_map_layout.py | 16 ++--- tuya_vacuum/vacuum_map_path.py | 9 +-- 4 files changed, 112 insertions(+), 18 deletions(-) create mode 100644 tuya_vacuum/lz4.py diff --git a/requirements.txt b/requirements.txt index f395c77c66e85ca6f315eed9056efe61bc98092a..dee6ebb636ead250a6a092f1b0389f33214de8d6 100644 GIT binary patch delta 37 ocmdnPx{r0jgN;9qFiP< +# +# 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: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# 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. +# +# SPDX-License-Identifier: MIT + +from io import BytesIO + +from six import byte2int +from six.moves import xrange # pylint: disable=redefined-builtin + + +class CorruptError(Exception): + pass + + +def uncompress(src): + """uncompress a block of lz4 data. + + :param bytes src: lz4 compressed data (LZ4 Blocks) + :returns: uncompressed data + :rtype: bytearray + + .. seealso:: http://cyan4973.github.io/lz4/lz4_Block_format.html + """ + src = BytesIO(src) + + # if we have the original size, we could pre-allocate the buffer with + # bytearray(original_size), but then we would have to use indexing + # instad of .append() and .extend() + dst = bytearray() + min_match_len = 4 + + def get_length(src, length): + """get the length of a lz4 variable length integer.""" + if length != 0x0F: + return length + + while True: + read_buf = src.read(1) + if len(read_buf) != 1: + raise CorruptError("EOF at length read") + len_part = byte2int(read_buf) + + length += len_part + + if len_part != 0xFF: + break + + return length + + while True: + # decode a block + read_buf = src.read(1) + if len(read_buf) == 0: + raise CorruptError("EOF at reading literal-len") + token = byte2int(read_buf) + + literal_len = get_length(src, (token >> 4) & 0x0F) + + # copy the literal to the output buffer + read_buf = src.read(literal_len) + + if len(read_buf) != literal_len: + raise CorruptError("not literal data") + dst.extend(read_buf) + + read_buf = src.read(2) + if len(read_buf) == 0: + if token & 0x0F != 0: + raise CorruptError("EOF, but match-len > 0: %u" % (token % 0x0F,)) + break + + if len(read_buf) != 2: + raise CorruptError("premature EOF") + + offset = byte2int([read_buf[0]]) | (byte2int([read_buf[1]]) << 8) + + if offset == 0: + raise CorruptError("offset can't be 0") + + match_len = get_length(src, (token >> 0) & 0x0F) + match_len += min_match_len + + # append the sliding window of the previous literals + for _ in xrange(match_len): + dst.append(dst[-offset]) + + return dst diff --git a/tuya_vacuum/vacuum_map_layout.py b/tuya_vacuum/vacuum_map_layout.py index cb07762..3aef56f 100644 --- a/tuya_vacuum/vacuum_map_layout.py +++ b/tuya_vacuum/vacuum_map_layout.py @@ -3,7 +3,6 @@ import logging import re -import lz4.block import numpy as np from PIL import Image, ImageColor @@ -20,6 +19,8 @@ ) from tuya_vacuum.vacuum_map_room import VacuumMapRoom +from .lz4 import uncompress + # Length of map header in bytes MAP_HEADER_LENGTH = 48 @@ -148,11 +149,7 @@ def _parse_map_version_0(self, data: str): if self.length_after_compression: max_buffer_length = self.total_count * 8 encoded_data_array = bytes(hex_to_ints(data[MAP_HEADER_LENGTH:])) - decoded_data_array = lz4.block.decompress( - encoded_data_array, - uncompressed_size=max_buffer_length, - return_bytearray=True, - ) + decoded_data_array = uncompress(encoded_data_array) area = self.width * self.height map_data_str = "".join( @@ -180,12 +177,7 @@ def _parse_map_version_1(self, data: str): info_length = MAP_HEADER_LENGTH + self.total_count * 2 encoded_data_array = bytes(hex_to_ints(data[MAP_HEADER_LENGTH:info_length])) max_buffer_length = self.total_count * 4 - decoded_data_array = lz4.block.decompress( - encoded_data_array, - uncompressed_size=max_buffer_length, - return_bytearray=True, - ) - + decoded_data_array = uncompress(encoded_data_array) self._map_data_array = decoded_data_array[:area] map_room_array = decoded_data_array[area:] diff --git a/tuya_vacuum/vacuum_map_path.py b/tuya_vacuum/vacuum_map_path.py index 30aa5b9..2b40df2 100644 --- a/tuya_vacuum/vacuum_map_path.py +++ b/tuya_vacuum/vacuum_map_path.py @@ -3,7 +3,6 @@ # Large parts of this script are based on the following code: # https://github.com/tuya/tuya-panel-demo/blob/main/examples/laserSweepRobot/src/protocol/path/index.ts -import lz4.block from PIL import Image, ImageDraw from tuya_vacuum.utils import ( @@ -14,6 +13,8 @@ hex_to_ints, ) +from .lz4 import uncompress + # Length of path header in bytes PATH_HEADER_LENGTH = 26 @@ -58,11 +59,7 @@ def __init__(self, data: str) -> None: if self.length_after_compression: max_buffer_length = self.total_count * 4 encoded_data_array = bytes(hex_to_ints(data[PATH_HEADER_LENGTH:])) - decoded_data_array = lz4.block.decompress( - encoded_data_array, - uncompressed_size=max_buffer_length, - return_bytearray=True, - ) + decoded_data_array = uncompress(encoded_data_array) path_data_array = chunks(decoded_data_array, 4) else: # Floor division From 4e81b99b6ada61fa1ea8cc678ff25febe2fc5d59 Mon Sep 17 00:00:00 2001 From: Jaiden <38144027+jaidenlab@users.noreply.github.com> Date: Tue, 26 Nov 2024 20:11:53 -0500 Subject: [PATCH 3/3] v0.1.8 version bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7694e13..84768b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "tuya-vacuum" -version = "0.1.7" +version = "0.1.8" description = "A python library to view maps from Tuya robot vacuums" authors = [ { name = "Jaiden Labelle", email = "jaidenjlabelle@gmail.com" }