From 26f25f75064cabde44c6592290abace6aa512962 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 28 Aug 2025 12:16:48 +0100 Subject: [PATCH] chore: remove CLI implementation and update project metadata; add GitHub Actions for CI --- .github/workflows/check.yml | 57 +++ CLAUDE.md | 1 - README.md | 94 +--- poetry.lock | 484 +++++++++++++++++++++ pyproject.toml | 60 ++- setup.py | 48 -- tests/test_vcdiff.py | 6 +- vcdiff/cli.py | 349 --------------- {vcdiff => vcdiff_decoder}/__init__.py | 2 +- {vcdiff => vcdiff_decoder}/addresscache.py | 0 {vcdiff => vcdiff_decoder}/adler32.py | 0 {vcdiff => vcdiff_decoder}/codetable.py | 0 {vcdiff => vcdiff_decoder}/decoder.py | 0 {vcdiff => vcdiff_decoder}/exceptions.py | 0 {vcdiff => vcdiff_decoder}/types.py | 0 {vcdiff => vcdiff_decoder}/varint.py | 1 - 16 files changed, 591 insertions(+), 511 deletions(-) create mode 100644 .github/workflows/check.yml create mode 100644 poetry.lock delete mode 100644 setup.py delete mode 100644 vcdiff/cli.py rename {vcdiff => vcdiff_decoder}/__init__.py (97%) rename {vcdiff => vcdiff_decoder}/addresscache.py (100%) rename {vcdiff => vcdiff_decoder}/adler32.py (100%) rename {vcdiff => vcdiff_decoder}/codetable.py (100%) rename {vcdiff => vcdiff_decoder}/decoder.py (100%) rename {vcdiff => vcdiff_decoder}/exceptions.py (100%) rename {vcdiff => vcdiff_decoder}/types.py (100%) rename {vcdiff => vcdiff_decoder}/varint.py (99%) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..28d5f2f --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,57 @@ +name: Check + +on: + workflow_dispatch: + pull_request: + push: + branches: + - main + +jobs: + check: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ['3.9', '3.10', '3.11', '3.12'] + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + id: setup-python + with: + python-version: ${{ matrix.python-version }} + + - name: Setup poetry + uses: abatilo/actions-poetry@v4 + with: + poetry-version: '2.1.4' + + - name: Setup a local virtual environment + run: | + poetry env use ${{ steps.setup-python.outputs.python-path }} + poetry run python --version + poetry config virtualenvs.create true --local + poetry config virtualenvs.in-project true --local + + - uses: actions/cache@v4 + name: Define a cache for the virtual environment based on the dependencies lock file + id: cache + with: + path: ./.venv + key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }} + + - name: Ensure cache is healthy + if: steps.cache.outputs.cache-hit == 'true' + shell: bash + run: poetry run pip --version >/dev/null 2>&1 || (echo "Cache is broken, skip it" && rm -rf .venv) + + - name: Install dependencies + run: poetry install + + - name: Run tests + run: poetry run pytest --verbose --tb=short diff --git a/CLAUDE.md b/CLAUDE.md index a39dd1c..6137b18 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -159,7 +159,6 @@ Uses the same `vcdiff-tests` submodule as the Go implementation: ### Python Versions - Minimum: Python 3.8 - Tested: Python 3.8, 3.9, 3.10, 3.11, 3.12 -- Dependencies: `click>=8.0.0` (CLI only) ## Limitations (Same as Go Implementation) diff --git a/README.md b/README.md index 15f398f..dce4d8a 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,7 @@ A Python implementation of a VCDIFF (RFC 3284) decoder library and command-line ## Overview -This repository contains both a Python library and a command-line interface (CLI) for working with VCDIFF delta files. The library provides a VCDIFF decoder that can decode delta files created according to RFC 3284 - The VCDIFF Generic Differencing and Compression Data Format. VCDIFF is a format for expressing one data stream as a variant of another data stream, commonly used for binary differencing, compression, and patch applications. - -The CLI tool can be used to apply VCDIFF deltas to reconstruct files, as well as to inspect and analyze the structure of VCDIFF delta files. +The library provides a VCDIFF decoder that can decode delta files created according to RFC 3284 - The VCDIFF Generic Differencing and Compression Data Format. VCDIFF is a format for expressing one data stream as a variant of another data stream, commonly used for binary differencing, compression, and patch applications. ## Features @@ -35,13 +33,13 @@ The CLI tool can be used to apply VCDIFF deltas to reconstruct files, as well as ## Installation ```bash -pip install vcdiff-py +pip install vcdiff ``` ### Development Installation ```bash -pip install -e .[dev] +poetry install ``` ### Cloning with Test Suite @@ -69,7 +67,7 @@ git submodule update --remote ### Library Usage ```python -import vcdiff +import vcdiff_decoder # Read the source file with open("original.txt", "rb") as f: @@ -81,32 +79,12 @@ with open("changes.vcdiff", "rb") as f: # Apply the delta to reconstruct the target try: - result = vcdiff.decode(source, delta_data) + result = vcdiff_decoder.decode(source, delta_data) print(f"Decoded result: {result}") -except vcdiff.VCDIFFError as e: +except vcdiff_decoder.VCDIFFError as e: print(f"Decoding failed: {e}") ``` -### CLI Usage - -Apply a VCDIFF delta: - -```bash -vcdiff apply -b source.txt -d changes.vcdiff -o result.txt -``` - -Inspect a VCDIFF delta file: - -```bash -vcdiff parse -d changes.vcdiff -``` - -Analyze a VCDIFF delta with source context: - -```bash -vcdiff analyze -b source.txt -d changes.vcdiff -``` - ## API Reference ### Core Functions @@ -156,58 +134,6 @@ The decoder provides detailed error messages for various failure conditions: - `CorruptedDataError`: Data corruption detected - `InvalidChecksumError`: Checksum validation failure -## Command-Line Interface - -The CLI provides three main commands: - -### `apply` - Apply VCDIFF Delta - -Applies a VCDIFF delta to a source file to produce the target file. - -```bash -vcdiff apply -b -d -o -``` - -**Options:** -- `-b, --base`: Source/base file path (required) -- `-d, --delta`: VCDIFF delta file path (required) -- `-o, --output`: Output file path (optional, defaults to stdout) - -### `parse` - Inspect VCDIFF Structure - -Parses and displays the internal structure of a VCDIFF delta file. - -```bash -vcdiff parse -d -``` - -**Options:** -- `-d, --delta`: VCDIFF delta file path (required) - -**Output includes:** -- Header information (magic bytes, version, flags) -- Window details (source segments, target length, checksums) -- Instruction breakdown (ADD, COPY, RUN operations) -- Address cache usage -- Data section analysis - -### `analyze` - Analyze with Source Context - -Analyzes a VCDIFF delta file with access to the source data, providing additional insights. - -```bash -vcdiff analyze -b -d -``` - -**Options:** -- `-b, --base`: Source/base file path (required) -- `-d, --delta`: VCDIFF delta file path (required) - -**Additional features:** -- Validates actual address references -- Shows source data context for COPY operations -- Provides hexdump-style output for referenced data - ## Testing ### Prerequisites @@ -231,19 +157,19 @@ sudo apt-get install xdelta3 To run the Python unit tests: ```bash -pytest +poetry run pytest ``` To run tests with coverage: ```bash -pytest --cov=vcdiff tests/ +poetry run pytest --cov=vcdiff tests/ ``` To run the comprehensive test suite against the VCDIFF test cases (requires submodule): ```bash -pytest tests/test_vcdiff.py -v +poetry run pytest tests/test_vcdiff.py -v ``` The test suite includes: @@ -316,8 +242,6 @@ For new features, please: ## Requirements - **Python**: 3.8 or higher -- **Dependencies**: - - `click>=8.0.0` (for CLI functionality) - **Development Dependencies**: - `pytest>=7.0.0` - `pytest-cov>=4.0.0` diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..b350155 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,484 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "black" +version = "22.12.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.7" +files = [ + {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, + {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, + {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, + {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, + {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, + {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, + {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, + {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, + {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, + {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, + {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, + {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.2.7" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "flake8" +version = "5.0.4" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, + {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=1.1.0,<4.3", markers = "python_version < \"3.8\""} +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.9.0,<2.10.0" +pyflakes = ">=2.5.0,<2.6.0" + +[[package]] +name = "importlib-metadata" +version = "4.2.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.6" +files = [ + {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, + {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, +] + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", "pyfakefs", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy" +version = "1.4.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"}, + {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"}, + {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"}, + {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"}, + {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"}, + {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"}, + {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"}, + {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"}, + {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"}, + {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"}, + {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"}, + {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"}, + {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"}, + {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"}, + {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"}, + {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"}, + {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"}, + {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"}, + {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"}, + {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"}, + {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"}, + {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"}, + {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"}, + {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"}, + {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"}, + {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "pathspec" +version = "0.11.2" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, +] + +[[package]] +name = "platformdirs" +version = "4.0.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + +[[package]] +name = "pluggy" +version = "1.2.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pycodestyle" +version = "2.9.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, + {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, +] + +[[package]] +name = "pyflakes" +version = "2.5.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, +] + +[[package]] +name = "pytest" +version = "7.4.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typed-ast" +version = "1.5.5" +description = "a fork of Python 2 and 3 ast modules with type comment support" +optional = false +python-versions = ">=3.6" +files = [ + {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, + {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, + {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, + {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, + {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, + {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, + {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, + {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, + {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, + {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, +] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.7" +content-hash = "9a5ad965c9ac7e0c5e8c2f5d6151643172de7d6ec93faf7ec29fd94d4405a12a" diff --git a/pyproject.toml b/pyproject.toml index 57855ae..6cc2ae8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,39 +1,53 @@ [build-system] -requires = ["setuptools>=64", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" -[project] -name = "vcdiff-py" -version = "1.0.0" +[tool.poetry] +name = "vcdiff-decoder" +version = "0.1.0a1" description = "Python implementation of VCDIFF (RFC 3284) delta compression format" readme = "README.md" -requires-python = ">=3.8" -license = {text = "Apache-2.0"} -authors = [ - {name = "Ably Realtime Limited"} +license = "Apache-2.0" +authors = ["Ably "] +homepage = "https://ably.com" +repository = "https://github.com/ably/vcdiff-python" +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Software Development :: Libraries :: Python Modules", ] -dependencies = [ - "click>=8.0.0", +include = [ + 'vcdiff/**/*.py', + 'README.md', + 'LICENSE' ] -[project.optional-dependencies] -dev = [ - "pytest>=7.0.0", - "pytest-cov>=4.0.0", - "black>=22.0.0", - "flake8>=5.0.0", - "mypy>=1.0.0", -] +[tool.poetry.dependencies] +python = "^3.7" -[project.scripts] -vcdiff = "vcdiff.cli:main" +[tool.poetry.dev-dependencies] +pytest = "^7.0.0" +pytest-cov = "^4.0.0" +black = "^22.0.0" +flake8 = "^5.0.0" +mypy = "^1.0.0" [tool.black] line-length = 100 -target-version = ['py38'] +target-version = ['py37'] [tool.mypy] -python_version = "3.8" +python_version = "3.7" warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index 6df850a..0000000 --- a/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -from setuptools import setup, find_packages - -with open("README.md", "r", encoding="utf-8") as fh: - long_description = fh.read() - -setup( - name="vcdiff-py", - version="1.0.0", - author="Ably Realtime Limited", - description="Python implementation of VCDIFF (RFC 3284) delta compression format", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/ably/vcdiff-py", - packages=find_packages(), - classifiers=[ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: System :: Archiving :: Compression", - "Topic :: Utilities", - ], - python_requires=">=3.8", - install_requires=[ - "click>=8.0.0", - ], - extras_require={ - "dev": [ - "pytest>=7.0.0", - "pytest-cov>=4.0.0", - "black>=22.0.0", - "flake8>=5.0.0", - "mypy>=1.0.0", - ], - }, - entry_points={ - "console_scripts": [ - "vcdiff=vcdiff.cli:main", - ], - }, -) \ No newline at end of file diff --git a/tests/test_vcdiff.py b/tests/test_vcdiff.py index aec0d6d..bf1e606 100644 --- a/tests/test_vcdiff.py +++ b/tests/test_vcdiff.py @@ -11,8 +11,8 @@ # Add the parent directory to the path so we can import vcdiff sys.path.insert(0, str(Path(__file__).parent.parent)) -import vcdiff -from vcdiff.exceptions import VCDIFFError +import vcdiff_decoder as vcdiff +from vcdiff_decoder.exceptions import VCDIFFError class TestVCDIFFSharedTests: @@ -201,7 +201,7 @@ class TestVCDIFFBasic: def test_import(self): """Test that the module can be imported""" - import vcdiff + import vcdiff_decoder as vcdiff assert hasattr(vcdiff, 'decode') assert hasattr(vcdiff, 'Decoder') diff --git a/vcdiff/cli.py b/vcdiff/cli.py deleted file mode 100644 index dd111ac..0000000 --- a/vcdiff/cli.py +++ /dev/null @@ -1,349 +0,0 @@ -"""VCDIFF command-line interface""" - -import io -import sys -from pathlib import Path -from typing import BinaryIO, List, Optional - -import click - -from . import decode, parse_delta -from .types import InstructionType, VCD_DECOMPRESS, VCD_CODETABLE, VCD_APPHEADER, VCD_SOURCE, VCD_TARGET, VCD_ADLER32 - - -@click.group() -@click.version_option(version="1.0.0") -def cli(): - """VCDIFF CLI Tool - - A command-line tool for working with VCDIFF (RFC 3284) delta files. - - VCDIFF is a format for expressing one data stream as a variant of another data stream, - commonly used for binary differencing, compression, and patch applications. - """ - pass - - -@cli.command() -@click.option("-b", "--base", "base_file", required=True, type=click.Path(exists=True, path_type=Path), - help="Path to base document file") -@click.option("-d", "--delta", "delta_file", required=True, type=click.Path(exists=True, path_type=Path), - help="Path to VCDIFF delta file") -@click.option("-o", "--output", "output_file", type=click.Path(path_type=Path), - help="Path to output file (default: stdout)") -def apply(base_file: Path, delta_file: Path, output_file: Optional[Path]): - """Apply a VCDIFF delta to a base document - - Apply a VCDIFF delta to a base document to produce the target document. - - The base document is the original file, and the delta contains the changes - needed to transform it into the target document. - - Examples: - vcdiff apply -base old.txt -delta patch.vcdiff -output new.txt - vcdiff apply -base old.txt -delta patch.vcdiff # Output to stdout - """ - try: - # Read base and delta files - base_data = base_file.read_bytes() - delta_data = delta_file.read_bytes() - - # Apply delta - result = decode(base_data, delta_data) - - # Write output - if output_file: - output_file.write_bytes(result) - else: - sys.stdout.buffer.write(result) - - except Exception as e: - click.echo(f"Error: {e}", err=True) - sys.exit(1) - - -@cli.command() -@click.option("-d", "--delta", "delta_file", required=True, type=click.Path(exists=True, path_type=Path), - help="Path to VCDIFF delta file") -def parse(delta_file: Path): - """Parse a VCDIFF delta and show human-readable representation - - Parse a VCDIFF delta file and display its contents in a human-readable format. - - This command shows the VCDIFF header information, window details, and - instruction sequences contained in the delta file. - - Examples: - vcdiff parse -delta patch.vcdiff - vcdiff parse -d patch.vcdiff # Short form - """ - try: - delta_data = delta_file.read_bytes() - parsed = parse_delta(delta_data) - - _print_delta(parsed) - click.echo() - - _print_instructions(parsed, sys.stdout) - - except Exception as e: - click.echo(f"Error: {e}", err=True) - sys.exit(1) - - -@cli.command() -@click.option("-b", "--base", "base_file", required=True, type=click.Path(exists=True, path_type=Path), - help="Path to base document file") -@click.option("-d", "--delta", "delta_file", required=True, type=click.Path(exists=True, path_type=Path), - help="Path to VCDIFF delta file") -def analyze(base_file: Path, delta_file: Path): - """Analyze a VCDIFF delta with base document context - - Analyze a VCDIFF delta file with access to the base document to provide - detailed information about the instructions and referenced data. - - This command shows the same information as 'parse' but also includes - hexdump-style output of the actual data chunks referenced by COPY instructions. - - Examples: - vcdiff analyze -base old.txt -delta patch.vcdiff - vcdiff analyze -b old.txt -d patch.vcdiff # Short form - """ - try: - base_data = base_file.read_bytes() - delta_data = delta_file.read_bytes() - parsed = parse_delta(delta_data) - - _print_delta(parsed) - click.echo() - - _print_detailed_instructions(parsed, base_data, sys.stdout) - - except Exception as e: - click.echo(f"Error: {e}", err=True) - sys.exit(1) - - -def _print_delta(parsed): - """Print delta structure information""" - _print_header(parsed.header) - click.echo(f" Windows: {len(parsed.windows)}") - - for i, window in enumerate(parsed.windows): - click.echo(f" Window {i}:") - _print_window(window) - - -def _print_header(header): - """Print header information""" - click.echo("VCDIFF Header:") - click.echo(f" Magic: 0x{header.magic[0]:02x} 0x{header.magic[1]:02x} 0x{header.magic[2]:02x}") - click.echo(f" Version: 0x{header.version:02x}") - - click.echo(f" Indicator: 0x{header.indicator:02x}", nl=False) - if header.indicator != 0: - flags = [] - if header.indicator & VCD_DECOMPRESS: - flags.append("VCD_DECOMPRESS") - if header.indicator & VCD_CODETABLE: - flags.append("VCD_CODETABLE") - if header.indicator & VCD_APPHEADER: - flags.append("VCD_APPHEADER") - - if flags: - click.echo(f" ({', '.join(flags)})") - else: - click.echo() - else: - click.echo() - - -def _print_window(window): - """Print window information""" - click.echo(f" WinIndicator: 0x{window.win_indicator:02x}", nl=False) - if window.win_indicator != 0: - flags = [] - if window.win_indicator & VCD_SOURCE: - flags.append("VCD_SOURCE") - if window.win_indicator & VCD_TARGET: - flags.append("VCD_TARGET") - if window.win_indicator & VCD_ADLER32: - flags.append("VCD_ADLER32") - - if flags: - click.echo(f" ({', '.join(flags)})") - else: - click.echo() - else: - click.echo() - - click.echo(f" SourceSegmentSize: 0x{window.source_segment_size:x} ({window.source_segment_size})") - click.echo(f" SourceSegmentPosition: 0x{window.source_segment_position:x} ({window.source_segment_position})") - click.echo(f" TargetWindowLength: 0x{window.target_window_length:x} ({window.target_window_length})") - click.echo(f" DeltaEncodingLength: 0x{window.delta_encoding_length:x} ({window.delta_encoding_length})") - click.echo(f" DeltaIndicator: 0x{window.delta_indicator:02x}") - click.echo(f" DataSectionLength: 0x{window.data_section_length:x} ({window.data_section_length})") - click.echo(f" InstructionSectionLength: 0x{window.instruction_section_length:x} ({window.instruction_section_length})") - click.echo(f" AddressSectionLength: 0x{window.address_section_length:x} ({window.address_section_length})") - if window.has_checksum: - click.echo(f" Adler32: 0x{window.checksum:08x}") - - -def _print_instructions(parsed, output): - """Print instruction summary""" - output.write(" Offset Code Type1 Size1 @Addr1 + Type2 Size2 @Addr2\n") - - for window in parsed.windows: - _print_window_instructions(window, output) - - -def _print_window_instructions(window, output): - """Print instructions for a single window""" - instruction_stream = io.BytesIO(window.instruction_section) - address_stream = io.BytesIO(window.address_section) - - offset = 0 - - while True: - code_data = instruction_stream.read(1) - if not code_data: - break - - code = code_data[0] - - # Look up instructions from code table - from .codetable import DEFAULT_CODE_TABLE - inst1 = DEFAULT_CODE_TABLE.get(code, 0) - inst2 = DEFAULT_CODE_TABLE.get(code, 1) - - output.write(f" {offset:06x} {code:03d} ") - - # Print first instruction - if inst1.type != InstructionType.NO_OP: - _print_single_instruction(inst1, instruction_stream, address_stream, output) - - # Print second instruction if it exists - if inst2.type != InstructionType.NO_OP: - output.write(" + ") - _print_single_instruction(inst2, instruction_stream, address_stream, output) - - output.write("\n") - offset += 1 - - -def _print_single_instruction(inst, instruction_stream, address_stream, output): - """Print a single instruction""" - # Get instruction type string - type_str = { - InstructionType.ADD: "ADD", - InstructionType.COPY: f"CPY_{inst.mode}", - InstructionType.RUN: "RUN", - InstructionType.NO_OP: "NOOP" - }.get(inst.type, f"UNK_{inst.type:02x}") - - # Get size - size = inst.size - if size == 0 and inst.type != InstructionType.NO_OP: - from .varint import read_varint - size = read_varint(instruction_stream) - - # Get address for COPY instructions - addr_str = "" - if inst.type == InstructionType.COPY: - from .varint import read_varint - - if inst.mode == 0: # SELF mode - addr = read_varint(address_stream) - addr_str = f"S@{addr}" - elif inst.mode == 1: # HERE mode - offset = read_varint(address_stream) - addr_str = f"H@{offset}" - else: - # Near/Same cache modes - if inst.mode < 6: - offset = read_varint(address_stream) - addr_str = f"N{inst.mode - 2}@{offset}" - else: - b_data = address_stream.read(1) - if b_data: - b = b_data[0] - addr_str = f"S{inst.mode - 6}@{b}" - - if inst.type == InstructionType.COPY: - output.write(f"{type_str} {size:6d} {addr_str}") - else: - output.write(f"{type_str} {size:6d}") - - -def _print_detailed_instructions(parsed, base_data: bytes, output): - """Print detailed instruction information with data context""" - output.write("Instructions with Data Context:\n") - output.write("===============================\n\n") - - for i, instruction in enumerate(parsed.instructions): - output.write(f"Instruction {i + 1}:\n") - - inst_type = { - InstructionType.ADD: "ADD", - InstructionType.COPY: "COPY", - InstructionType.RUN: "RUN", - InstructionType.NO_OP: "NOOP" - }.get(instruction.type, f"UNK({instruction.type:02x})") - - output.write(f" Type: {inst_type}\n") - output.write(f" Mode: 0x{instruction.mode:02x}\n") - output.write(f" Size: 0x{instruction.size:x} ({instruction.size} bytes)\n") - - if instruction.type == InstructionType.COPY: - output.write(f" Addr: 0x{instruction.addr:x} ({instruction.addr})\n") - - if instruction.addr < len(base_data): - end_addr = min(instruction.addr + instruction.size, len(base_data)) - output.write(f" Data from base [0x{instruction.addr:x}:0x{end_addr:x}]:\n") - _print_hex_dump(base_data[instruction.addr:end_addr], output, instruction.addr) - else: - output.write(" Data:
\n") - elif instruction.data: - output.write(" Data:\n") - _print_hex_dump(instruction.data, output, 0) - - output.write("\n") - - -def _print_hex_dump(data: bytes, output, base_offset: int): - """Print hexdump-style output""" - bytes_per_line = 16 - - for i in range(0, len(data), bytes_per_line): - end = min(i + bytes_per_line, len(data)) - line = data[i:end] - - output.write(f" {base_offset + i:08x} ") - - # Hex bytes - for j in range(bytes_per_line): - if j < len(line): - output.write(f"{line[j]:02x} ") - else: - output.write(" ") - - if j == 7: - output.write(" ") - - # ASCII representation - output.write(" |") - for b in line: - if 32 <= b <= 126: - output.write(chr(b)) - else: - output.write(".") - output.write("|\n") - - -def main(): - """Main entry point""" - cli() - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/vcdiff/__init__.py b/vcdiff_decoder/__init__.py similarity index 97% rename from vcdiff/__init__.py rename to vcdiff_decoder/__init__.py index 961be8c..19b41be 100644 --- a/vcdiff/__init__.py +++ b/vcdiff_decoder/__init__.py @@ -28,7 +28,7 @@ ) from .types import InstructionType -__version__ = "1.0.0" +__version__ = "0.1.0a1" __all__ = [ "Decoder", "decode", diff --git a/vcdiff/addresscache.py b/vcdiff_decoder/addresscache.py similarity index 100% rename from vcdiff/addresscache.py rename to vcdiff_decoder/addresscache.py diff --git a/vcdiff/adler32.py b/vcdiff_decoder/adler32.py similarity index 100% rename from vcdiff/adler32.py rename to vcdiff_decoder/adler32.py diff --git a/vcdiff/codetable.py b/vcdiff_decoder/codetable.py similarity index 100% rename from vcdiff/codetable.py rename to vcdiff_decoder/codetable.py diff --git a/vcdiff/decoder.py b/vcdiff_decoder/decoder.py similarity index 100% rename from vcdiff/decoder.py rename to vcdiff_decoder/decoder.py diff --git a/vcdiff/exceptions.py b/vcdiff_decoder/exceptions.py similarity index 100% rename from vcdiff/exceptions.py rename to vcdiff_decoder/exceptions.py diff --git a/vcdiff/types.py b/vcdiff_decoder/types.py similarity index 100% rename from vcdiff/types.py rename to vcdiff_decoder/types.py diff --git a/vcdiff/varint.py b/vcdiff_decoder/varint.py similarity index 99% rename from vcdiff/varint.py rename to vcdiff_decoder/varint.py index 962d463..efe2fc6 100644 --- a/vcdiff/varint.py +++ b/vcdiff_decoder/varint.py @@ -1,6 +1,5 @@ """Variable-length integer encoding/decoding - RFC 3284 Section 2""" -import io from typing import BinaryIO from .types import VARINT_CONTINUATION_BIT, VARINT_VALUE_MASK