diff --git a/.vscode/settings.json b/.vscode/settings.json index e57e989..94fc0a0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -117,6 +117,7 @@ "cffi", "cfgv", "charliermarsh", + "chunksize", "cimport", "cimports", "clibase", diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb3011..30681e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. - [Changelog](#changelog) - - [2.1.0 - 2026-06-20](#210---2026-06-20) + - [2.1.0 - 2026-06-26](#210---2026-06-26) - [2.0.0 - 2026-06-19](#200---2026-06-19) - [1.9.0 - 2026-06-11](#190---2026-06-11) - [1.8.0 - 2026-06-06](#180---2026-06-06) @@ -30,9 +30,10 @@ This project follows a pragmatic versioning approach: - **Minor**: new features or non-breaking changes. - **Major**: breaking changes (command renames, incompatible output formats). -## 2.1.0 - 2026-06-20 +## 2.1.0 - 2026-06-26 - Added + - **Multi-process frame interpolation rendering** (`core/zoom.py`, `InterpolatedFrameStream()`): frame interpolation (`--i-frames`) now uses Python's `concurrent.futures.ProcessPoolExecutor` to parallelize rendering of interpolated frames across multiple CPU cores; new `InterpolateFrameWorker()` function runs as a separate process to compute individual interpolated frames (linear or quadratic); new `InterpolationJob` and `InterpolationResult` dataclasses encapsulate job distribution and result collection; `InterpolatedFrameStream()` accepts optional `max_threads` parameter (default None = use all available cores) to control parallelism; executor automatically disabled when `i_frames=0` (no interpolation) or single-threaded execution is requested; dramatically speeds up animation generation for high-FPS outputs (e.g., `--fps 10 --i-frames 7` now renders 73 total frames from 10 real frames with ~7× speedup due to parallelism). - **Animation metadata hash injection control** (`--inject/--no-inject` flag, `cli/base.py`, `cli/zoomcommand.py`): new `tranz zoom auto` flag allows users to control whether the final hash is re-injected into animation metadata after rendering; `--inject` (default False) re-saves the animation file to include the final computed hash in metadata, which requires re-processing (lossless for MP4, lossy for GIF); `--no-inject` skips this step for faster completion when the final hash in metadata is not critical; useful for testing or when metadata space is constrained; both GIF and MP4 re-saving is expensive but preserves content fidelity for MP4 via ffmpeg re-mux. - Changed diff --git a/README.md b/README.md index a3ddd70..06954d4 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ Built with: - [Modules / packages](#modules--packages) - [Performance characteristics](#performance-characteristics) - [Three-tier optimization system](#three-tier-optimization-system) + - [Multi-process frame interpolation](#multi-process-frame-interpolation) - [Development Instructions](#development-instructions) - [File structure](#file-structure) - [Development Setup](#development-setup) @@ -1163,6 +1164,16 @@ tranZoom (≥1.7.0) provides three computation modes with progressively better p The default (`--opt` not specified) automatically uses the **best available** optimization. Starting with version 1.8.0, wheels built with `poetry build` include pre-compiled Cython extensions automatically. +#### Multi-process frame interpolation + +Frame interpolation (`--i-frames`) uses **multi-process parallelization** to speed up animation rendering. When frame interpolation is active, interpolated frames are generated in parallel across available CPU cores: + +- **Architecture:** Uses Python's `concurrent.futures.ProcessPoolExecutor` to distribute interpolation jobs across separate OS processes, avoiding Python's Global Interpreter Lock (GIL) +- **Worker function:** `InterpolateFrameWorker()` computes individual interpolated frames (supports both linear and quadratic interpolation modes) in independent processes +- **Speedup:** Renders high-FPS animations much faster; e.g., `--fps 10 --i-frames 7` (producing 73 frames) benefits from ~7–8× speedup with all cores utilized; actual speedup depends on CPU count and per-frame workload +- **Control:** Pass `max_threads` at the command level to cap parallelism; default uses all available cores +- **Automatic fallback:** When `i_frames=0` (no interpolation) or on single-core systems, no process pool is created; overhead is negligible + ## Development Instructions ### File structure diff --git a/poetry.lock b/poetry.lock index 1cb9efa..d7442dd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -26,14 +26,14 @@ files = [ [[package]] name = "anyio" -version = "4.14.0" +version = "4.14.1" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "anyio-4.14.0-py3-none-any.whl", hash = "sha256:dd9b7a2a9799ed6552fde617b2c5df02b7fdd7d88392fc48101e51bae46164d9"}, - {file = "anyio-4.14.0.tar.gz", hash = "sha256:b47c1f9ccf73e67021df785332508f99379c68fa7d0684e8e3492cb1d4b23f89"}, + {file = "anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72"}, + {file = "anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e"}, ] [package.dependencies] @@ -210,14 +210,14 @@ files = [ [[package]] name = "click" -version = "8.4.1" +version = "8.4.2" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2"}, - {file = "click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96"}, + {file = "click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76"}, + {file = "click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6"}, ] [package.dependencies] @@ -238,118 +238,103 @@ markers = {main = "platform_system == \"Windows\"", dev = "sys_platform == \"win [[package]] name = "coverage" -version = "7.14.1" +version = "7.14.3" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "coverage-7.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3e3680291c4a1d0dadfa84a2c459576a4af5133abb617905714339a0c73138cf"}, - {file = "coverage-7.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5274669f37f2343635a347b91a60777621341ab3378e9c6ac9335eee704bddf"}, - {file = "coverage-7.14.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cfe5a5fec635799ef33428f1e5e61bafa45a92a96190ba731561ba558ccc214d"}, - {file = "coverage-7.14.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:62a9f70b52e0b5a95cfef4a5c5641b06983cadc5e538a3feeb5c00211f523ac2"}, - {file = "coverage-7.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c18ebc343e15be53049b3a2dce38fe82d58f37e20ab9094b3a39c0aa4f6bb47"}, - {file = "coverage-7.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b84ffdf877644e7096aa936991efeed873f7f3df57b9cd001312b7668ab08550"}, - {file = "coverage-7.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e854312c4103f2ad4c0dc023b69b77ebfd2c89db5f86c4c94dc2353f9a92167e"}, - {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c643734307300234fafa36bf2a040a7235f8f177ea1fd6ec1423aea6fb7b929f"}, - {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84ac9499e48700399a5dd0ea7085b5091961fec52c68d66b4ec0d3cf7f4441b1"}, - {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7f02d09f70776579b926d889a4c9c235070a1f47c40458aeaca563fae5acfdb5"}, - {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ce66d8e46da2bb5ee313a745cbd2e391d319176c1f7a9451bfcd3a2fb920859b"}, - {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c912c259304cfb5ee584481cfb7ce1ff932b4d61e6c9140b8f19cb7b5ed82332"}, - {file = "coverage-7.14.1-cp310-cp310-win32.whl", hash = "sha256:1238cb94638e610e972c60dac68e813f868dc7d6e982535270558443058d9d59"}, - {file = "coverage-7.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:fc459e5d73be2d6332fcfe8dbf3d8994671fe33c700f4565988ecfa511547253"}, - {file = "coverage-7.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:478b5bcd63c2e1357c5c7e16c070690df7b07f676b1c114d7b93e533c664309f"}, - {file = "coverage-7.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a24a81f9715ee42ef59a316cc11611c98fe23920f7c81861315c9f3ff4a230f4"}, - {file = "coverage-7.14.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:196a13319ad88d6d8ef5ab489ec4f44ddde2143c0c7d5b27786f6c3ffd56a7e1"}, - {file = "coverage-7.14.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d452fd08b5c72c5167c93e6867b5c08500bd40f2a21e1e854a500550b6cc36f"}, - {file = "coverage-7.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23bf7fa51ac02e07fc7c96849b82946da47ae862dc8f86d183b2a4864fc38129"}, - {file = "coverage-7.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcaa50684dcaadfa599ac48f81103c756d791cfd85c97203d2217c593d48b860"}, - {file = "coverage-7.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4ea1c034f95c9b056e856b794630b17f9fa3d57e4800ff1e503d3be0f9c9078c"}, - {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e057326434e441306226fbeb5d1aaf14a2637efe97ba668306635835f32ad7"}, - {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:59baf88468dbc8d63b1887afd92bda52e40bb1561696e5819670601403810cec"}, - {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d75f892b3ab73ba11cab5442cce7b3e168fd64162b16f0e1e0d09c508edef"}, - {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3a56abc20a472baf0304c455721bc601477440d28ecfde8a03dde79ede07e0df"}, - {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6a3cb83d1552c0cd1b4906655b6a33fd4a8473229633a901c6b73bf86914dee9"}, - {file = "coverage-7.14.1-cp311-cp311-win32.whl", hash = "sha256:10274a1fbeb8ec5d72966e17bb198a3104257aca4ac09d98667c5f8aca8c8548"}, - {file = "coverage-7.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:87ebdf787d4888e3f3f2d523eadc6e18c6d18c6d0eb173801a189641627fb37e"}, - {file = "coverage-7.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:dd34767fa19848d35659ffc0a75314f58c7af3f1cd87ec521e8292a1238398a3"}, - {file = "coverage-7.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a06c76364a9360e33d6d23769aefdf7f66f38e2ffb60ceb1baaa4989d83b695c"}, - {file = "coverage-7.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fad54e871165f6ec2f536063ac74c3104508a12963e64072ba44bd822de52b0c"}, - {file = "coverage-7.14.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:84b535f00655ecafe1d929d1fb00ed5d6fa3051ea643ab2c161a3887b86f294b"}, - {file = "coverage-7.14.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6b6b0853b895fe0e98cbfc580d1ec3393d9302b4b1e96a77b3f5c91fdab899e6"}, - {file = "coverage-7.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:442cc9c952b2df400cda54bb04ab87330cf2cd08a8692cbbea36773531eb6f37"}, - {file = "coverage-7.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8270544c361ed405a27a060dbc9ed2c124b084d96dfdc2d9a2510482aef981ad"}, - {file = "coverage-7.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:48b283b1dd6372e8de2a7a9a4c4d5dc06f4d4fd209b876f3c88a7a205a0c8f84"}, - {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5b0c99ba93a07d56f6df340bb79be53202a082b2fdb81bfe6190b741a3470d54"}, - {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e471bc5769ff073b058cfadb0d736b56ce067c8560eabeb0da88462df98c23e7"}, - {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f497a1ea81d4cd7c10ddcaa685135b9aabd291af3d55775a9ddf3cb7a364cdd9"}, - {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2222be86d0b54f5dd5a38f45f17f315f737245e857bf0bdedc70734f84a13c02"}, - {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85e85586565842f6932abebd4c18bcb1074223dc0b3576e7d173ca710622813a"}, - {file = "coverage-7.14.1-cp312-cp312-win32.whl", hash = "sha256:4a28fd227808366b196a75476dced2eb35b351d6766ba9c858dc93319e87f4f1"}, - {file = "coverage-7.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:54acdb6674a4661768d7bf7db32dfb9f46ab1d764f8aba6df75ce1a6a088724e"}, - {file = "coverage-7.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:99cd41ff91afd94896fea3bc002706b6ae4ce95727d06e4a0f39c0a8d8bd8b1a"}, - {file = "coverage-7.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:be9f2c802dcfce3f71298303aa5dad0dce440a76c52f2f60dacd8656dab78793"}, - {file = "coverage-7.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6223a72fd0e4c7156353ec0f08a5f93623e1d3034d0e2683b9bb8ea674131b1d"}, - {file = "coverage-7.14.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7279d2110a28cebc738b6459ecda2771735a4c18465fbbd36b3288fe5ed92247"}, - {file = "coverage-7.14.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9eeb3fcbc13ba40dfbdb22d01d196a28e9cef9ed4c29b60061a1e0e823a9929d"}, - {file = "coverage-7.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f0cfc27c539f07cf5c0a4cfe211d0b6cae039f8f40526dbaa71944e64b50a7b"}, - {file = "coverage-7.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:221c70f316241a78e77e607c227cefc8808d4e08f28d99c04f35694690e940be"}, - {file = "coverage-7.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:da028256b04ec30e5e0114b6f76172938c313991f0a2d3d894271315cf5d5e43"}, - {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76a085d7005236a767e3426148b2c407e53ad61695c562f8a81da2d373324901"}, - {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b553d04b5e778a8e56d57eb134aff42a92718ecba45e79c4764ecfa40efd92ff"}, - {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:46f714d2fb8ae2f4f29f23ada7f1e79b759fff5a70f94a1dac23af204c3ec9e4"}, - {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1896f5e19ff3f0431c7ce2172adc54890fd97f86b59ced8ca1649145d9ffe35d"}, - {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:62fd185ef9df3c33d1c8178c5af105f762afbad96038de9a4ae100aa6297ca33"}, - {file = "coverage-7.14.1-cp313-cp313-win32.whl", hash = "sha256:ab4af6352741a604c431c6072fce5bee33bf0f20dc7a56618d6bf6bb89e9810c"}, - {file = "coverage-7.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:7af486dabe8954d03b087f0021540897afe084f04e16ff5579e08cc46f871416"}, - {file = "coverage-7.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:2224f89ffd0c5605ccce1ed7a584da162bc7c55f601ab1c946bc9de31a486b42"}, - {file = "coverage-7.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de286598cc65d2b489411174b1faec2f5a7775fb3201fd925db2a76b4030f37d"}, - {file = "coverage-7.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:042c46ded7c288aeb07cf14a28b6c1e10b78fcba40171c3fa1e939377eeef0b5"}, - {file = "coverage-7.14.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f4ddbe407477f04c45115d1a4e5bc480f753553b534d338d4c3358b1cdd0ea52"}, - {file = "coverage-7.14.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d13e6725992e2d2fd7d81d4f5241952d13740121dfd501da09201be39b2c003a"}, - {file = "coverage-7.14.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f747dc8edcfe740130f28f32f3995e955494285717e86ee25af51db2219df08a"}, - {file = "coverage-7.14.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ced2f09ef276fd58611a1ef502164ad266d2b75174e5a40cabbdb4033f9f6cf2"}, - {file = "coverage-7.14.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b84800013769a78ccb9ef4659402e26d06867e337b61ec365f77ad008adea80e"}, - {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ea8cd6ca0ee9f616aaef3afc6882e32c2cbf18b00d96313ffd76af650574034d"}, - {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:aa5e304a873fabddc11e484e9b6b738bd38bd7bed17b09aa84eecf5332e8b8bb"}, - {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5a1c5215be81035e629d5bc756650634d0bf31991038db7a0eccb90f025ce16d"}, - {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:79058c47dae6788504b5effb319961bcd72d7240551464b91d474bc0ed186d69"}, - {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:370c5afae3fa0658e11694a32b24c2778f6bc2d17718121f94ee185e69f26b54"}, - {file = "coverage-7.14.1-cp313-cp313t-win32.whl", hash = "sha256:3758dd0a7f1fa57365ef2e781df0f0731d38b6e3772259d13dae4bd8a958d4b1"}, - {file = "coverage-7.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:6ff665fb023a77386fe11685190cee1f60a7d635994a30d9b0a061533d470fce"}, - {file = "coverage-7.14.1-cp313-cp313t-win_arm64.whl", hash = "sha256:17a5a241e5997621a956a7f402a7433ef4221e5152809b785bec79e2323799f1"}, - {file = "coverage-7.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d5ed429d0b8edaac649e889b4ffcedb6c80b06629a3f93050e3dddfb99235bee"}, - {file = "coverage-7.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8011224a62280e50dab346960c03cf47aca1a1e09e608c0fb33fd6e0cc8e9500"}, - {file = "coverage-7.14.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:12c42ec1e14f553c4f817e989365982e646e27211f10a0f717855b94a79c8906"}, - {file = "coverage-7.14.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06144cd511cf2624873a035c5069cf297144f6e77a73ee3d7a55b605ec5efb42"}, - {file = "coverage-7.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a311d8e1da24be5c1ccf85cbfb06315dbaa1703d5a1eab3f6432c72b837917c8"}, - {file = "coverage-7.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c79cead5b5bc584d9c71451cb984d0e3a84e0c0937379c8efcbf27c8d661b851"}, - {file = "coverage-7.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dcbf65f1f66a26cdd88c35cf68fb4729c5d1cd2e88added72420541dfb212034"}, - {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fd86572566fb40189a8260446158235159bc7a82dfbc87a3b39cf4fb57fcec1c"}, - {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7771b601718fdde84832c3a434ca9bbf4ae9adbc49d84198b4110700c3c77c36"}, - {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:39b21e212c55af06fa375e3dbf90a8a8e38792f3a910c580066d23563830ddd5"}, - {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f2302660e32562a532b442480121aef8aa61a5bdb20b30bf0adab29f10a5a4b4"}, - {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:03a6f93c1ec3b7f2e77b5dbcc5573a2c21f12529a5c6bbe0f16f72303cc2fa4d"}, - {file = "coverage-7.14.1-cp314-cp314-win32.whl", hash = "sha256:8a3ce026d73290f42f08dafecbd82c193a74df280461fbf97300fec51fd133ee"}, - {file = "coverage-7.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:114c95ef29302423b87d159075805f4ab973254a2638a5d7d046c94887cc87d7"}, - {file = "coverage-7.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:a07891c3f4805442b31b71e84ba3cf29ed1aa9a428284e06deeb4b23e5b46343"}, - {file = "coverage-7.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1101a5ebb083aecb625ebb6209d4105b58f647b093cb2dc8122d7b33f743cfe1"}, - {file = "coverage-7.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:851b9e1e4e8a4608e77c79714b2e77c0970d2ed7202a05e92ae407817481887b"}, - {file = "coverage-7.14.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d5b89cdfb2ee051b71e8c3c70bd81a9eff81100f736a269136fe1a68efe00474"}, - {file = "coverage-7.14.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0177614a0370f227888b4e436a7c55686d6a9f90eb1ade2b624ba685a1686e86"}, - {file = "coverage-7.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d69af5dea2de76fc485a83032a630523f985198b7e25be901ec60181587b01e"}, - {file = "coverage-7.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:35ab22d91de736e8966b980dc355cbcdd2c6dbbcfe275f9a2991bc8a91b3df65"}, - {file = "coverage-7.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:357d4e32935c36588aaba057d734fa32428c360c9fc2e4442afbf1b646beee6e"}, - {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:51bd64741cc6fa065abd300ede1afe5a5291ece9c31da8b24884deda48bcc3f8"}, - {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:9132cd363a68a4c3daa7c8704a654b1e39d3360f6f5b8ddd470608a945236c07"}, - {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:07c6290b1697b862c0478eab545eec949a0d0e4d6d03497f446d706da3b4f2de"}, - {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5ea0c297e27133853b4d8a3eb799bff5a2dbd9f2f41537a240d337ac9b4df890"}, - {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:01b7733daad0237daa01ef80fe2dfceffc911e6a17fa7b55d14aa8214eaaaecd"}, - {file = "coverage-7.14.1-cp314-cp314t-win32.whl", hash = "sha256:6adc5a36984624a70bf11d7184e20fa0a49aa7c47ffab43804106a1a695ea22e"}, - {file = "coverage-7.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:ddf799247318f34dbcd2efa8c95a8d0642674e926bb1774cf9b63dfd2a389d1c"}, - {file = "coverage-7.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:145986fe66647eb489f18d9a997567a3fd358584c4b5a808769113abc07466af"}, - {file = "coverage-7.14.1-py3-none-any.whl", hash = "sha256:a252f21c27e38347e60111a3266b03827422a7d5525951aceee313aa68bab1d2"}, - {file = "coverage-7.14.1.tar.gz", hash = "sha256:30c08f7d90415aa98b3c990385dea2939b0da55f38515e5b369b83655f8523be"}, + {file = "coverage-7.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:360bec1f58e7243e3405d3bdf7a1a8115aa9b448d54dc7cd6f7b7e0e9406b62e"}, + {file = "coverage-7.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed68faa5e85de2f3e400bc3f122e5c82735a58c8bb24b9f63a2215954ba17b2d"}, + {file = "coverage-7.14.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:830c1fca669c572dec37ce9c838224ee45aac5be0f6961edf871e82e49d6537c"}, + {file = "coverage-7.14.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a64caee2193563601dbaaa55fe2dcf597debef04a2f8f1fa8a07aa4bb7ac7a1e"}, + {file = "coverage-7.14.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0096fd7559178f0cc9cf088f2dbd2a02ef85bacaa69732c633517286b4494610"}, + {file = "coverage-7.14.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6197e5a00183c11a8ce7c6abd18be1a9189fd8399084ffc95196f4f0db4f2137"}, + {file = "coverage-7.14.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7dfe427045520d6abca33687dfef767b4f635015893a1816c5decb12eb72ce18"}, + {file = "coverage-7.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9a3f142070eb7b82fc4085a55d887396f9c4e21250bccebe2ba22502c45b9647"}, + {file = "coverage-7.14.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64b2055bb6e0dc945af35cdeceb3633e6ed9273475ef3af85592410fd6803803"}, + {file = "coverage-7.14.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1551b4caac3e3ec9f2bfcec6bf3776e01c0edbdd2e240431a50ca1a1aac72c27"}, + {file = "coverage-7.14.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:583d50d59142f8549470bd6390471d0fe8b8c8d69d6a0f28ac71e05380cef640"}, + {file = "coverage-7.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0bb8a6bc7015efdf8a928753b25da1b9ca2d6f24ef04d2ee0688e486f32aae7"}, + {file = "coverage-7.14.3-cp310-cp310-win32.whl", hash = "sha256:d48400185564042287dc487c1f016a3397f18ab4f4c5d5ec36edc218f7ffa35b"}, + {file = "coverage-7.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:eadea7aba74e40adee867a8c0eec17b820b061d308a4b014f7a0e118c2b0aa61"}, + {file = "coverage-7.14.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e574801e1d643561594aa021206c46d80b257e9853087090ba97bed8b0a509d3"}, + {file = "coverage-7.14.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f82b6bb7d75a2613e85d07cefa3a8c973d0544a8993337f6e2728e4a1e94c305"}, + {file = "coverage-7.14.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a2335ea5fed26af2e831094964fa3f8fae60b45f7e37fcc2d3b615b2add3ad87"}, + {file = "coverage-7.14.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fbb8c3a98e779013786ae01d229662aeacbc77100efbd3f2f245219ace5af700"}, + {file = "coverage-7.14.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac082660de8f429ba0ea363595abb838998570b9a7546777c60f413ab902bbde"}, + {file = "coverage-7.14.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ac012839ff7e396030f1e94e10553a431d14e4de2ab65cb3acb72bbd5628ca2"}, + {file = "coverage-7.14.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5952f8c1bda2a5347154450379316e6dfa4d934d62ca35f6784451e6f55074fb"}, + {file = "coverage-7.14.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8cf0f2509acb4619e2471a1951089054dd58ebea7a912066d2ea56dd4c24ca4a"}, + {file = "coverage-7.14.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2e41fd3aab806770008279a93879b0924b16247e09ab537c043d08bbca53b4ab"}, + {file = "coverage-7.14.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f0a47095963cfe054e0df178daca95aec21e680d6076da807c3add28dfe920f7"}, + {file = "coverage-7.14.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a090cbf9521e78ffdb2fcf448b72902afe9f5923ff6a12d5c0d0120200348af9"}, + {file = "coverage-7.14.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4d310baf69a4fbe8a098ce727e4808a34866ac718a6f759ae659cbd3221358bc"}, + {file = "coverage-7.14.3-cp311-cp311-win32.whl", hash = "sha256:74fdd718d88fe144f4579b8747873a07ec3f04cb837d5faec5a25d9e22fa31a8"}, + {file = "coverage-7.14.3-cp311-cp311-win_amd64.whl", hash = "sha256:cc96aa922e21d4bc5d5ed3c915cef27dfcbc13686f47d5e378d647fbfba655a2"}, + {file = "coverage-7.14.3-cp311-cp311-win_arm64.whl", hash = "sha256:c66f9f9d4f1e9712eb9b1de5310f881d4e2188cfcba5065e1a8490f38687f2c4"}, + {file = "coverage-7.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3d74ff26299c4879ce3a4d826f9d3d4d556fd285fde7bbce3c0ef5a8ab1cec24"}, + {file = "coverage-7.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:96150a9cf3468ea20f0bc5d0e21b3df8972c31480ef90fa7614b773cc6429665"}, + {file = "coverage-7.14.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:27d07a46500ba23515b838dbcf52512026af04090755cf6cc64166d88c9b9a1a"}, + {file = "coverage-7.14.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:621e13c6108234d7960aaf5762ab5c3c00f33c30c15af06dcbff0c73bf112727"}, + {file = "coverage-7.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4b60ca6d8af70473491a15a343cbabab2e8f9ea66a4376e81c7aa24876a6f977"}, + {file = "coverage-7.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c90a7cdd5e380e1ce02f19792e2ac2fbfbf177e35a27e69fd3e873b30d895c0c"}, + {file = "coverage-7.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5d788e5fd55347eef06ca0732c77d04a264de67e8ff24631270cdff3767a60cf"}, + {file = "coverage-7.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:62c7f79db2851c95ef020e5d28b97afde3daf9f7febcd35b53e05638f729063f"}, + {file = "coverage-7.14.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:90f7608aeb5d9b60b523b9fb2a4ee1973867cc4865a3f26fe6c7577073b70205"}, + {file = "coverage-7.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1e3b91f9c4740aeb571ecf82e5e8d8e4ab62d34fcb5a5d4e5baa38c6f7d2857c"}, + {file = "coverage-7.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c946099774a7699de03cbd0ff0a64e21aed4525eed9d959adde4afe6d15758ef"}, + {file = "coverage-7.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16b206e521feb8b7133a45754643dead0538489cf8b783b90cf5f4e3299625fd"}, + {file = "coverage-7.14.3-cp312-cp312-win32.whl", hash = "sha256:ea3169c7116eb6cdf7608c6c7da9ecfcb3da40688e3a510fac2d1d2bafd6dc35"}, + {file = "coverage-7.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:7ea52fc08f007bcc494d4bb3df3851e95843d881860ba38fe2c64dc100db5e7d"}, + {file = "coverage-7.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:8cec0ad652ec57790970d817490105bd917d783c2f7b38d6b58a0ca312e1a336"}, + {file = "coverage-7.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47968988b367990ae4ab17523790c38cd125e02c6bfd379b6022be2d40bdc38c"}, + {file = "coverage-7.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0ee68f5c34812780f3a7063382c0a9fcbb99985b7ddcdcaa626e4f3fb2e0783a"}, + {file = "coverage-7.14.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fa9e5c6857a7e80fa22ace5cf3550ae392bbfc322f1d8dd2d2d5a8be38cec027"}, + {file = "coverage-7.14.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:98a0859b0e98e43e1178a9402e19c8127766b14f7109a374d976e5a62c0e5c73"}, + {file = "coverage-7.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69918344541ed9c8368566c2adc03c0e33d4550d7faa87d1b35e49b6a3286ea9"}, + {file = "coverage-7.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b7f300ac92cd4b570724c8ffbbd0c130fee298d2447f41d5a3abf58976fae1de"}, + {file = "coverage-7.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:11a7ec9f97ab950f4c5af62229befc7faf208fdbc0116d3902d7e306cf2c5abd"}, + {file = "coverage-7.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a571bd889cd36c5922ce8e42e059f9d37d02301531d11374afa4c87a578625d5"}, + {file = "coverage-7.14.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de76caefc8deabb0dd1678b6a980be97d14c8d87e213ac194dbf8b09e96d63fb"}, + {file = "coverage-7.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d20a15c622194234161535459affa8f7905830391c9ccfa060d495dbfe3a1c7f"}, + {file = "coverage-7.14.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b488bd4b23397db62e7a9459129d01ff06a846582a732efd24834b24a6ada498"}, + {file = "coverage-7.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a3693b4153394d265f44fb855fdc80e72403024d4d6f91c4871b334d028e4e0"}, + {file = "coverage-7.14.3-cp313-cp313-win32.whl", hash = "sha256:338b19131ab1a6b767b462bfcbaa692e7ae22f24463e39d49b02a83410ff6b37"}, + {file = "coverage-7.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:b3d77f7f196abdef7e01415de1bce09f216189e83e58159cfeef2b92d0464994"}, + {file = "coverage-7.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:e6230e688c7c3e65cedd41a774eb4ec221adc6bfee13768231015b702d5e4150"}, + {file = "coverage-7.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:605ab2b566a22bd94834529d66d295c364aba84afd3e5498285c7a524017b1fc"}, + {file = "coverage-7.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a3c2134809e80fac091bfed18a6991b5a5eb5df5ae32b17ac4f4f99864b73dd7"}, + {file = "coverage-7.14.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c02efd507227bde9969cab0db8f48890eb3b5dcad6afac57a4792df4133543ce"}, + {file = "coverage-7.14.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1bb93c2aa61d2a5b38f1526546d95cf4132cb681e541a337bf8dfd092be816e5"}, + {file = "coverage-7.14.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f502e948e03e866538048bba081c075caaa62e5bda6ea5b7432e45f587eb462a"}, + {file = "coverage-7.14.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9973ef2463f8e6cfb61a6324126bb3e17d67a85f22f58d856e583ea2e3ca6501"}, + {file = "coverage-7.14.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9be4e7d4c5ca0427889f8f9d614bd630c2be741b1de7699bca3b2b6c0e41003e"}, + {file = "coverage-7.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a574912f3bde4b0619f6e97d01aa590b70998859244793769eb3a6df78ee56d3"}, + {file = "coverage-7.14.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:e343fb086c9cd780b38622fea7c369acd64c1a0724312149b5d769c387a2b1f5"}, + {file = "coverage-7.14.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:3c68df8e61f1e09633fefc7538297145623957a048534368c9d212782aa5e845"}, + {file = "coverage-7.14.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3e5b550a128419373c2f6cec28a244207013ef15f5cbcff6a5ca09d1dfaaf027"}, + {file = "coverage-7.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2bfc4dd0a912329eccc7484a7d0b2a38032b38c40663b1e1ac595f10c457954b"}, + {file = "coverage-7.14.3-cp314-cp314-win32.whl", hash = "sha256:0423d64c013057a06e70f070f073cec4b0cbc7d2b27f3c7007292f2ff1d52965"}, + {file = "coverage-7.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:92c22e19ce64ca3f2ad751f16f14df1468b4c231bd6af97185063a9c292a0cb3"}, + {file = "coverage-7.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:41de778bd41780586e2b04912079c73089ab5d839624e28db3bdb26de638da92"}, + {file = "coverage-7.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8427f370ca67db4c975d2a26acfc0e5783ca0b52444dbc50278ace0f35445949"}, + {file = "coverage-7.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d8e88f335544a47e22ae2e45b344772925ec65166555c958720d5ed971880891"}, + {file = "coverage-7.14.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:beaab199b9e5ceaf5a225e16a9d4df136f2a1eae0a5c20de1e277c8a5225f388"}, + {file = "coverage-7.14.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3ff255799f5a1676c71c1c32ec01fd043aa09d57b3d95764b24992757184784"}, + {file = "coverage-7.14.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:878832eaac515b62decfa76965aed558775f86bf1fc8cca76993c0c84ae31aed"}, + {file = "coverage-7.14.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:611e62cb9386096d81b63e0a05330750268617231e7bd598e1fe77482a2c58a5"}, + {file = "coverage-7.14.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:02c41de2a88011b893050fc9830267d927a50a215f7ad5ec17349db7090ccf26"}, + {file = "coverage-7.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:526ce9721116af23b1065089f0b75046fe521e7772ab94b641cd66b7a0421889"}, + {file = "coverage-7.14.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e4ed44705ca4bead6fc977a8b741f2145608289b33c8a9b42a95d0f15aedbf4d"}, + {file = "coverage-7.14.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2415902f385a23dcc4ccd26e0ba803249a169af6a930c003a4c715eeb9a5444e"}, + {file = "coverage-7.14.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b75ee850fc2d7c831e883220c445b035f2224de2ba6103f1e56dbd237ab913f7"}, + {file = "coverage-7.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dc9b4e35e7c3920e925ba7f14886fd5fbe481232754624e832ddba66c7535635"}, + {file = "coverage-7.14.3-cp314-cp314t-win32.whl", hash = "sha256:7b27c822a8161afbe48e99f1adfb098d270ae7e0f7d7b0555ce110529bdb69cc"}, + {file = "coverage-7.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:39e1dbbb6ff2c338e0196a482558a792a1de3aa64261196f5cdb3da016ad9cda"}, + {file = "coverage-7.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:68520c90babfa2d560eca6d497921ed3a4f469623bd709733124491b2aa8ef3f"}, + {file = "coverage-7.14.3-py3-none-any.whl", hash = "sha256:fb7e18afb6e903c1a92401a2f0501ac277dca527bb9ca6fe1f691a8a0026a0e8"}, + {file = "coverage-7.14.3.tar.gz", hash = "sha256:1a7563a443f3d53fdeb040ec8c9f7466aed7ca3dc5891aa09d3ca3625fa4387f"}, ] [package.extras] @@ -419,51 +404,51 @@ ssh = ["bcrypt (>=3.1.5)"] [[package]] name = "cython" -version = "3.2.5" +version = "3.2.6" description = "The Cython compiler for writing C extensions in the Python language." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "cython-3.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:220e8b160b2a4ddc362ad8a8c2ab885aa7156099702cdc48f6518a5de921b553"}, - {file = "cython-3.2.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4e722ceab6d795b4682d693656218671c873d4aa74119c54a2b62de0e7c48ce"}, - {file = "cython-3.2.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4bfb00baef07106a1e5e7252ace18de91225322f7fa29970995aea7c380fa21"}, - {file = "cython-3.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:45baf00cb8b222a2ca7e9c48add5dac3ceb6e65be4f591150a6b6767ce1f86b0"}, - {file = "cython-3.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5887c24ebd19604b7a76d8ea57446cb562a590f7f2557e5954a69aae38b3195e"}, - {file = "cython-3.2.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56c97c5e43782ec9d9e66c465e253d2ccde0c578c364c46445efe484965524f0"}, - {file = "cython-3.2.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:75f5295dc1b32d084fec598f9507e6f264311d78c07da640bc9a05dc47f7ac2c"}, - {file = "cython-3.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:b8bc1325cf3e4394cc08a3c1ea7fa24f02f405eef0e8c156d5055f6f9a7a1565"}, - {file = "cython-3.2.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:eb38b89e5a8eb2508a1a0832063826b0703dfb02be84e4aa34b8818ce0ca50fe"}, - {file = "cython-3.2.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80e1e5cba5b4b9890364e9360939fc298c474f25754bb4bb861270d24bda6d6"}, - {file = "cython-3.2.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e2c976ee96da4deff50506c7882ccebb4a932fc178ef27eb42bfde959839"}, - {file = "cython-3.2.5-cp312-cp312-win_amd64.whl", hash = "sha256:29243859d6824e2d33bae92fc83d591c3671b6d9ac1b757fa264b894ae906c2b"}, - {file = "cython-3.2.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5d7a60835345a8bd29d3aa57070880cc3ce017ea0ade7b9f771ce4bf539b1f"}, - {file = "cython-3.2.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b564f67b01bffa2521f475794b49f2787709cec1f91d5935a38eba37f2b359"}, - {file = "cython-3.2.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0a81220817ff954eddf4512a5b82089094a2f523eb1dc4ad555efd6f07b009b4"}, - {file = "cython-3.2.5-cp313-cp313-win_amd64.whl", hash = "sha256:3795237ab49753647e329181b140c424e8aa97543074f171f8d2c45e5014a06e"}, - {file = "cython-3.2.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a636c8b7824f3cb587eb2fdde59d8f4a14d433565508081cc290198e37567910"}, - {file = "cython-3.2.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69cd71b90d4e0f142fd15b2353982c3f9171fc5e613001f16bcb366ffb29004b"}, - {file = "cython-3.2.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3864da4ca2ebe4660d8f672f2143b02840bf3045655222f6090486171c84298f"}, - {file = "cython-3.2.5-cp314-cp314-win_amd64.whl", hash = "sha256:605c447188aecf2941709f53a2ce44862be256e54601c01b38ab710d83db8047"}, - {file = "cython-3.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3a423468ee77c3c5b26494f57d9c52e9318991fb7142f4c49fb01b99373e8d6"}, - {file = "cython-3.2.5-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cce98a9011ac6a2560b3587db22912bd0138267669ec567b0d57eddd2d741b8b"}, - {file = "cython-3.2.5-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:561613ddd1ee83088eb126e80a5a7d73ee6eb82e0b1aea09afbe170287e5e27f"}, - {file = "cython-3.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:677bb60fd8f5949e26c0a7898983967dbbb65f7628481d8480956b85ca766554"}, - {file = "cython-3.2.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:224149d18d980e6ea5001b70fc7ce096c1891d59035dfa9cc5ede50f55804913"}, - {file = "cython-3.2.5-cp39-abi3-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:992a50e90d01813333752f374a4405863113059ec67102ab8d6a431a171ee328"}, - {file = "cython-3.2.5-cp39-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8d7b81e6a52a84a02993f01aa5873786ba1dd593c892d93d5fe9866da0bad297"}, - {file = "cython-3.2.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:34d21aeb08477c9173e8be7a566b19e880a7c8109ec6bb47a4b20cb680141114"}, - {file = "cython-3.2.5-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:c4c79e697db55f082a2d3ba97702e71881d5bb1f56f0a80fa338e69101e4c59b"}, - {file = "cython-3.2.5-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:39acb30eba78ba6d995d5cf3d97d57d450663d93aac6f8b93753d2b89d768c60"}, - {file = "cython-3.2.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:382122de8d6b6024fc374fabc3a2b14ba5860ed981c25055ed14fe44278b9dc7"}, - {file = "cython-3.2.5-cp39-abi3-win32.whl", hash = "sha256:0bc29c7f870b09efdb1f583fbec9592b33af81a7ce273b89c8f5163d7572d5c1"}, - {file = "cython-3.2.5-cp39-abi3-win_arm64.whl", hash = "sha256:85b2944c3eddfc230f9082720195a2e9f869908e5a8b3185be1be832755ee7fc"}, - {file = "cython-3.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91cb5b9ff599612737b3fd0dddcd401acdf904b78c2caf8cd1049501d0a53f2d"}, - {file = "cython-3.2.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:268aecadcabcdad9f773b8a5694746e0b9ee7894b56b84e2e3a2ccb6c929ea79"}, - {file = "cython-3.2.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05c22cd606ac8d14a9cf17e48668bb37734c803978bf4d793c7f11ef54c4451f"}, - {file = "cython-3.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:3e5e519bad217a0b96fc281666720ed7d339da618acaa012bea712980b8fe6c9"}, - {file = "cython-3.2.5-py3-none-any.whl", hash = "sha256:dc1c8cebb7df5bce37f5f8dc1e5bf04313272a5973d50a55c0ec76c83812911b"}, - {file = "cython-3.2.5.tar.gz", hash = "sha256:3dd42e4cf36ad15f265bdfec2337cc00c688c8eb6d374ffd13bb19437c27bba1"}, + {file = "cython-3.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2256911b04b61cd1868fd3c8fa48a0a4df1b6fe0cc95df39ae31a05e313b1df"}, + {file = "cython-3.2.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fed593ff9beeda252acce9f8b475f5107a3a04f99183950b8a4ba45c5b5bb959"}, + {file = "cython-3.2.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de9067c5e5d16f964487b3e8a6084709484372a9b786ae6e6f5be61a7d5d3540"}, + {file = "cython-3.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:7bad96281c0e0be103d082eedf7f5357058f675a69fc2bc55eb678c7eebd22e7"}, + {file = "cython-3.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6d9c43ff8b31a49b2f2f8e4d7b2ed4120890a1654ce9725fcad483561f114cb2"}, + {file = "cython-3.2.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e97789425a0638dd9078cd4a28c90bf53b0679ec73706fcaa4f88c39572350d5"}, + {file = "cython-3.2.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0acf7093a7b672152b2a3f062f1c3f520c0598332e050b1d01fecd41a96df780"}, + {file = "cython-3.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:24bd2a82a07269a1e6e6595bb466e2392b0da1dfc1975ae7029a1c8a25177f0a"}, + {file = "cython-3.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18e6867912d30ed72193d13ddfa1ee2dee993ebe5cf7ec68d67df72999621ae2"}, + {file = "cython-3.2.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4898f8c192881c887cb6ddec76019aed76fca1bb5503d9ac4ca1b71e5888c025"}, + {file = "cython-3.2.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b24a7acb0579705a0469f0e8f46992afb21446f0fa378071e04b761cc307efcb"}, + {file = "cython-3.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:52642711db295185ec1393a21017c1b4e77c7b9fbdc5610b9a4830ac67ce0e8a"}, + {file = "cython-3.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1620fa6bc06e08abaf186ca48b537866fec8e36d063bda40baa97b4c69464e30"}, + {file = "cython-3.2.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11801c84778e57d47d5b5a986c89a8b56ea5931ee6a2847ff467b39743809366"}, + {file = "cython-3.2.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:334590964868d3687be573906e8e68e7215a05728dc85ba28ca8e866c1ec670a"}, + {file = "cython-3.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:ada44272f4627c8fe0cab7ab8f1643f12717b79ad6db6c8b08b570045a557aaf"}, + {file = "cython-3.2.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7a06b86bc7f319f73586d59b9fc7e03b737f4e64340520acb1aa72bacd2ddb4b"}, + {file = "cython-3.2.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eedaac613e339871dbb7b63cad9128a1223cb732b7c3b33d56f5c2773ab4270b"}, + {file = "cython-3.2.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b74d3cc341112274fd9ac45e48218b88a45ae9549f1a78f7b6321f5862f0f993"}, + {file = "cython-3.2.6-cp314-cp314-win_amd64.whl", hash = "sha256:038969d1c1a9c7982ad86e45c1fb555d90230d8fab106af5e30b629d1c0d5570"}, + {file = "cython-3.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:575ae7a4abbac34abe83f9428c748850639ca5b7457096769a81cdbcc904f687"}, + {file = "cython-3.2.6-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ddf484a71f0815ec5a106bc90912f832efd4edc96f41619ac318b6fb67c8325"}, + {file = "cython-3.2.6-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6251eb9d1995d898ab86e3bc458398a32df804bf4e704e76f703face663be45"}, + {file = "cython-3.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:a69300a63b93c44863eae70307cd6de1833532dcbed566b597cc79528716ed51"}, + {file = "cython-3.2.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9a5e31253e54a93b05aaab46f5b3ee0002112cf040b09476921e75115fd40321"}, + {file = "cython-3.2.6-cp39-abi3-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c8abcf755dd6e0a9b37993a285998a5fc08cbbca5669ce4832d996ba304182fc"}, + {file = "cython-3.2.6-cp39-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:08fce6c6450a5bc92bb7fe1d936cf9d5429d8124e9459622316f00859406aa56"}, + {file = "cython-3.2.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b4fa2401cfd8632294dcf87469c6a235bbdf822b49c0f5d79077f4d63e4c4d58"}, + {file = "cython-3.2.6-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:df431a50c13b46f3785b3b2c6a10d83ec493974b5a25a3e07342aa5e36afe976"}, + {file = "cython-3.2.6-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:0a4e3a352e56e4f11ccf5b883c01c2daf005d5c74f472cf7fcc15a04498b49fd"}, + {file = "cython-3.2.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b54ad419c478164a101b374f4fd1a9211de4dd696a1ba572b283f5622901ed72"}, + {file = "cython-3.2.6-cp39-abi3-win32.whl", hash = "sha256:b20c4f946b6dda39f2e4b1c643e333c560d6ab9eea8befb3fe9007f40e40bd9c"}, + {file = "cython-3.2.6-cp39-abi3-win_arm64.whl", hash = "sha256:3a49d32bd54d7ac9b6ddadc7a890dc667ccb2308bd71621d402d9087aae3a291"}, + {file = "cython-3.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b64353e1faf9b0ffe770e2a1dae3bb77b663d738c52e8064d618987b8349903"}, + {file = "cython-3.2.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a27b599bfcc062d9bfa2c715fd25404f5ba89a7cb4e8d375f0b6cabda4a93fa3"}, + {file = "cython-3.2.6-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d438d76a6e6977cab3eff39de825e9798a9956a4be627faf23e1ca296dcfbe69"}, + {file = "cython-3.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:f9506c30bf137bf9255fe98e46e4696ef008e99ba01698b8dc2024da060ef379"}, + {file = "cython-3.2.6-py3-none-any.whl", hash = "sha256:6b1e044b465b66eb242d5a415072a54c4b0325557e5e91fc134f003fdcc20150"}, + {file = "cython-3.2.6.tar.gz", hash = "sha256:6509472a245ccdf5fd11637a4744a1edfd38debb1a48332a8f3fe4b07db725bd"}, ] [[package]] @@ -555,87 +540,95 @@ files = [ [[package]] name = "gmpy2" -version = "2.3.0" +version = "2.3.1" description = "gmpy2 interface to GMP, MPFR, and MPC for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "gmpy2-2.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e993f860fdd8d7c7d817ad55abfbd7002e2416da32990f7f24f3e1fc09151f00"}, - {file = "gmpy2-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c00b8f5c4e0e75a37a881b56bf34da1cab9f2e2f705bc2c556a077994586e471"}, - {file = "gmpy2-2.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fcee5a11f66c7e0c55b73868e016a2e30e60adad52eadf8cc4edb1f01c81af3"}, - {file = "gmpy2-2.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:950e261e5a32e2e2dadf0a120cb5bcbf09ce5d3f449b1949d4f98805991af73a"}, - {file = "gmpy2-2.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd298f0a6c49e4293c5f87b47871f6c6d3376a532647d5f82e55f2eab79e033e"}, - {file = "gmpy2-2.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8667105be66a733a2398e613a489c5684ee2c7d835406266759f7c04e2a75e05"}, - {file = "gmpy2-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:ca24dfc437e1c387454b83e837ab1d43b356aa350aecd723d5828a34ed60718a"}, - {file = "gmpy2-2.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:72d4430faf34065e12b3296de7dd8f0f1bf07c34c2d9208fba6a550db6fd44c7"}, - {file = "gmpy2-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2792ec96b2c4ee5af9f72409cd5b786edaf8277321f7022ce80ddff265815b01"}, - {file = "gmpy2-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3770aa5e44c5650d18232a0b8b8ed3d12db530d8278d4c800e4de5eef24cac5"}, - {file = "gmpy2-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b4cee1fa3647505f53b81dc3b60ac49034768117f6295a04aaf4d3f216b821"}, - {file = "gmpy2-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd9f4124d7dc39d50896ba08820049a95f9f3952dcd6e072cc3a9d07361b7f1f"}, - {file = "gmpy2-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2f6b38e1b6d2aeb553c936c136c3a12cf983c9f9ce3e211b8632744a15f2bce7"}, - {file = "gmpy2-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:089229ef18b8d804a76fec9bd7e7d653f598a977e8354f7de8850731a48adb37"}, - {file = "gmpy2-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:f1843f2ca5a1643fac7563a12a6a7d68e539d93de4afe5812355d32fb1613891"}, - {file = "gmpy2-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:cd5b92fa675dde5151ebe8d89814c78d573e5210cdc162016080782778f15654"}, - {file = "gmpy2-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f35d6b1a8f067323a0a0d7034699284baebef498b030bbb29ab31d2ec13d1068"}, - {file = "gmpy2-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:392d0560526dfa377c54c5c001d507fbbdea6cf54574895b90a97fc3587fa51e"}, - {file = "gmpy2-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e900f41cc46700a5f49a4fbdcd5cd895e00bd0c2b9889fb2504ac1d594c21ac2"}, - {file = "gmpy2-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:713ba9b7a0a9098591f202e8f24f27ac5dd5001baf088ece1762852608a04b95"}, - {file = "gmpy2-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d2ed7b6d557b5d47068e889e2db204321ac855e001316a12928e4e7435f98637"}, - {file = "gmpy2-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d135dcef824e26e1b3af544004d8f98564d090e7cf1001c50cc93d9dc1dc047"}, - {file = "gmpy2-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:9dcbb628f9c806f0e6789f2c5e056e67e949b317af0e9ea0c3f0e0488c56e2a8"}, - {file = "gmpy2-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:19022e0103aa76803b666720f107d8ab1941c597fd3fe70fadf7c49bac82a097"}, - {file = "gmpy2-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2f045c824c7ac28bb026e55b8a8c97a41ebbcdfbe1f065e47debb5d842baf667"}, - {file = "gmpy2-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bc09a8fddecf2eed7b6da1b877d96ec9582285f0bbc3bdf57f3dedfcfbef01f7"}, - {file = "gmpy2-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a12f5b508b940000b54dec3a2fdd3523e09f20b87093a190a55d9a139bb5eece"}, - {file = "gmpy2-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:488a370c232b314c353982920fded3c275e44a4f55d48d690462ad31cbf971ae"}, - {file = "gmpy2-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:67606f3da678b3c2379dc606186867cde5061e44f96bf5a114cc6a08ea0d2fc7"}, - {file = "gmpy2-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77d4d5b580339f31f89db3640453472d3c8c9308233db35bdccd2e8a93ae61fd"}, - {file = "gmpy2-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:b308af421eadb1736befdde0f9ab9927d4a674596eef88a99faa98d75bba8f16"}, - {file = "gmpy2-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:65d8bf129b50b42644602e241e04ba3a27dafef0b07904964d8b4689704d97d7"}, - {file = "gmpy2-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:800d6bbb5ad1dac5ab13000c4a693332c8e27f169723e4b43f98ec8e15d41277"}, - {file = "gmpy2-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:51dd9999a2cbfc4cd1d6166478c2e5749aa9cf5cf384349d2d8f9169463190f1"}, - {file = "gmpy2-2.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab62738afef1d65e96d170efdd8e982caa9338591e8faa0ac6999bf574b5f441"}, - {file = "gmpy2-2.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:122e37c3f2ced5ae30a904d3ba5cc9c9e65e752560911eac44c6e9f3a8a240a1"}, - {file = "gmpy2-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:28422e9a137ac1ae60f906b7c1a9b99fc7191e6a8ced3c4222dd514b33d5556f"}, - {file = "gmpy2-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fc6329b18bdbac682452ae403edf373be52794400643578863b5a751cc606e4f"}, - {file = "gmpy2-2.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5779f6cf498dfea2dd486c6acff0b61b834d3c3a18724d09f297a495a2ba4794"}, - {file = "gmpy2-2.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:63203c8a31f2afb282e0535e517e8f53a7f63c490b51bb3e1e3dbad67533ca63"}, - {file = "gmpy2-2.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf9ac69c1346a6dc21e62261d916325be74d1aee97e87e14c90eedbb0171feba"}, - {file = "gmpy2-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0a42ced3bc8a679daa46fba0d7b46f5549c5c1400adc005da76a9420821ad959"}, - {file = "gmpy2-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17770d7a8fb06159563d63a69b95e9c935f94d078ec5b1876e64ae2f233cc97b"}, - {file = "gmpy2-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:566861a586dabffc4913b3a99f611240c966e9d5fab71cdb3147e759a035ebd2"}, - {file = "gmpy2-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04112c8c572499877aa785e91a1b06a90ac65138638d8d331b78032b2fe76dd9"}, - {file = "gmpy2-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:404f1c46e9e3871c482d485f661b8b94e7b8bb7837e582d2dad961a3c8a9aa81"}, - {file = "gmpy2-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:9cedc4e27c543fa811175a00765bd284114fc6f813fcca2dbb24b383173115e2"}, - {file = "gmpy2-2.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:51051b7327f384cbd6e3fecdb31280c3aab5648cc5f49a79d447b9851840eb65"}, - {file = "gmpy2-2.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:23235c78f75f5d5349c5a28ba747abdabf8e43cb6c3e2d7296d9be07d5ee150c"}, - {file = "gmpy2-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:884b200343db4eca4a918cff602ecd1686a8dfc44f4b0b7e7df21747edf4e168"}, - {file = "gmpy2-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d7cae51c2613884192901b3b7cf6546e4c70548589b58ef9eec7d3aaea88783"}, - {file = "gmpy2-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:399d8ed2168075837c9b8817808532d5d3fc197cd7b121822e97e8add3e60f7f"}, - {file = "gmpy2-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a5713e51e244470e986051ac2be4aa4d0594067216f07d76cd07234f8c25a2c6"}, - {file = "gmpy2-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:baf62ccecb76a0c922af2f01c7fbb0b0f7606ed41fd7d59458656898a0dad5c9"}, - {file = "gmpy2-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8b6399d2dd1229242b0e24ebf525f70fee0efa98f366990c7efafd32ce90855c"}, - {file = "gmpy2-2.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:3c13f1078b30bbb95472f38e6213fb269be55ef37ede94fb9695fb1173e568a4"}, - {file = "gmpy2-2.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6666ca96e5620c335a2cee76d4edef17f9f6e56fd72c2b27e2ad8515ab89109d"}, - {file = "gmpy2-2.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6e6ee096cbedf55d15ae43501e602dbadacbe30aa5c87eb615bcddbe1510323e"}, - {file = "gmpy2-2.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0a94d44419cdb1672352b1011185f341093b52dbdaf43c298785cd75c42956e"}, - {file = "gmpy2-2.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e70067a7bc0a126d6616d23f63554c91d92778ed6a5cfd36bf687169cbcd8f19"}, - {file = "gmpy2-2.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6e53f925093655940443be93198a7571e159670262a651838ea48e992816547d"}, - {file = "gmpy2-2.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e4a17cf8c3db708fb850e876d485f0e82ab34beffe3d0b2cd53e5389612843d"}, - {file = "gmpy2-2.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:8dbe94d515d5af85bd1206f52844464b53d73e8f016240ee03d91f309d435d59"}, - {file = "gmpy2-2.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:85392b2ac5e6c6769be70d0f86e937617f9fc9770fc61b7bf4d101f1910527fa"}, - {file = "gmpy2-2.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71dc3734104fa1f300d35ac6f55c7e98f7b0e1c7fd96f27b409110ed1c0c47d2"}, - {file = "gmpy2-2.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4623e700423396ef3d1658efa83b6feb0615fb68cb0b850e9ac0cba966db34c8"}, - {file = "gmpy2-2.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:692289a37442468856328986e0fab7e7e71c514bc470e1abae82d3bc54ca4cd2"}, - {file = "gmpy2-2.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bb379412033b52c3ec6bc44c6eaa134c88a068b6f1f360e6c13ca962082478ee"}, - {file = "gmpy2-2.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8d087b262a0356c318a56fbb5c718e4e56762d861b2f9d581adc90a180264db9"}, - {file = "gmpy2-2.3.0.tar.gz", hash = "sha256:2d943cc9051fcd6b15b2a09369e2f7e18c526bc04c210782e4da61b62495eb4a"}, + {file = "gmpy2-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7591d074879588430a774bdcb7eff1ef834d433a993c182a9c195b96d4a7eee"}, + {file = "gmpy2-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7cd0431d0a56e7dedad6bc2521913aa401bab7ebde4cc4e079243d2414f2be35"}, + {file = "gmpy2-2.3.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13f8d4fa3c678f60ab001514bf9a9a207487e1e62228d1985c58d26e5e0c1973"}, + {file = "gmpy2-2.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44315a9f64f77fe097619e73440e631ac79fe464211684b4473edc8cb573997e"}, + {file = "gmpy2-2.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0e8f48ab7407ef635ee81176f5807b60eb39c0c2bab589893f34883aede0c1c3"}, + {file = "gmpy2-2.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c81692a0c36527a4bf379cc6d8c4d2cdf71a8d6305734c06c891b7d7ac15b133"}, + {file = "gmpy2-2.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:7ba83f1fecee41630d10b276f7213261dcb6dcc2f123ce83aaca16bfc760e84f"}, + {file = "gmpy2-2.3.1-cp310-cp310-win_arm64.whl", hash = "sha256:9ef8e7fd3d4ba06a83c22f03cf430182adb4f1467af3e370706c97358263eebe"}, + {file = "gmpy2-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:48ead9abf937929eeeab5562c98e2feaba23fe6fe342346feb19938a83b14985"}, + {file = "gmpy2-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:63c867ad5bf43486dc4d7e4b6bafb04bd2b50bce400130f4c49fa4bf4325076e"}, + {file = "gmpy2-2.3.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3dadd6567b4873bfc55368cc0ad4ff205595cf78af762ba843febf62cb999da3"}, + {file = "gmpy2-2.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:beb43dfb4b28e541343400115f009b57d44b29fdf4c0b0435d6d3674ae52c098"}, + {file = "gmpy2-2.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b541a39999dc59ca654edb072ede3fd9be7decd3cbba24d5b0250a01fc59371"}, + {file = "gmpy2-2.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23eacccb2442dbadb6b5564dc0e6cf6b4f86c156fb1ea1fcba4da6a0169d03dc"}, + {file = "gmpy2-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:495f684d1ccb671f014a352f28b3ba77b9dbddf5ede5828a8f4508f32b35f2bc"}, + {file = "gmpy2-2.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:f6a9779510a4571f852e90c1141145afcf4c9ffb1a25cb487710c14050b434c7"}, + {file = "gmpy2-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0808da8c24271b554e27ca1c4ca73ee33fbca367a9dba455630fdead70eb96dc"}, + {file = "gmpy2-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:04048f0ac0bf529f15980d17d566495536a0a1adfc31f4dc622973c58009dac3"}, + {file = "gmpy2-2.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32dbf42716d1773c9a7d760957f6dfe6ea13646119fba6bc5cb7445d86de9974"}, + {file = "gmpy2-2.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e9cc3703df3bf740f87744cd9816c3bb65da68a605d31d38173c38414dfb516"}, + {file = "gmpy2-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5fd224e299e3cbc83712b96546893ef5a6d8df3c5f2dcdd9086b0b63048edfc5"}, + {file = "gmpy2-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6eb0859c9202c97c50883997974edd4fa67860d11796a1774187e29c64c2965a"}, + {file = "gmpy2-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:4aaeecabcc01aaa5a6ccc96971b967d5e2f9872021e6c4965d068909c620c830"}, + {file = "gmpy2-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:381c053f30a6a755832a5a016a4536bc96a075870d6af4980b0328f9b9d62aeb"}, + {file = "gmpy2-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:376595b3ba348d2b0ca0fbd21e9d13b2fd4534200f8c46e351bafa3398485a79"}, + {file = "gmpy2-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5a3e9ff8f6465cab78f275117c45fef2fc50fbba5ab228dcfd6676907fe200cb"}, + {file = "gmpy2-2.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4e14b32adf4a69e7755833ac795ae70b5932a50d75d2106f1cbaadf80fb642c"}, + {file = "gmpy2-2.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:32e599e078234fd6d0e59c3ae7e6f78fe033394b69018a1b80c5c7d57a3c057e"}, + {file = "gmpy2-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a12d33c133efc7157a9afd3f357ddfd33077062c91c7bf186bf2d6de0d8562b"}, + {file = "gmpy2-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8577b05584bb1653fac44b1f07f958089bcaab2e54a8c3cc2979c066042f6fc8"}, + {file = "gmpy2-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:4e1496e1a40c87dccb13163bebb265fdb7d0579726f197d59a93b94441e4e509"}, + {file = "gmpy2-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:9caae7f55b34bfefe88d5d0f287fb95eb72ec78172bcbeee9e194e327885cd5b"}, + {file = "gmpy2-2.3.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:93fabff8f2aeea38555fe298cdeab6dde87082d2a189dc919117cbaa99d67a13"}, + {file = "gmpy2-2.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f4b7d3f828567b3a42b518f0a1694d8acf947996660c48428e97b0d7b11db709"}, + {file = "gmpy2-2.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:29e3ca03037a7674007eda851b87564c7de0fef07402513e99f6919fbd200a6e"}, + {file = "gmpy2-2.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8749196c8bcd51612d989f5e509ea77d5c97c40b57eda9a863938facbe2b9eab"}, + {file = "gmpy2-2.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9d76d62233e09ccfe2c492df3368ef19e7b7a62d3172a8f78c96d37f8f646b91"}, + {file = "gmpy2-2.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2f986ef8612ef47f3f8dc308d957d49082400bc986e40e288a00556ef9f0c06c"}, + {file = "gmpy2-2.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:dcf0c32b50f859736ef4c4ba0b36132899e175cce666958e96b93cb43cd241df"}, + {file = "gmpy2-2.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:ed0c6ca01e879451df5120b15e24f0d4430652d1e8b867b86b62f8ee7b4e3ebd"}, + {file = "gmpy2-2.3.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:23a702ef9b84a4c072ae8fea9a713779efd3562cc7c62f7ef2a4e4f7f5648d24"}, + {file = "gmpy2-2.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4199127acf096281bac79f78c492211a71b1290a7b32d2e0de271b1c98bb3dea"}, + {file = "gmpy2-2.3.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c843c21ef78e96f3519fcd925bd3ff444c4cd3d3911b4282c53870298afb8c2"}, + {file = "gmpy2-2.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5f8c80813d370584ba00dbeb917262d4ec2192dcacb2c0774cf3f33a94c5565"}, + {file = "gmpy2-2.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2627879f06b156f3421a5775bfc8ea9323388181ab6b8f2447f8dbcc151f5c33"}, + {file = "gmpy2-2.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6935a76caed64ab4f55c4177d4a20b559fe5fcae08db5313f7cd7ee62e0ab2be"}, + {file = "gmpy2-2.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:db6a7f0951f6024764f493192cb53410890412d8d47fa7028983f2cbec1eb4dc"}, + {file = "gmpy2-2.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:b3859613f34e608eab7108665552c8b1b4aa88fbfd4bc0b8c98e79fa8d83e561"}, + {file = "gmpy2-2.3.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:40a7db7529d382a98fbbb43477029157c03b51e182a5f823be4a0f8b173ac438"}, + {file = "gmpy2-2.3.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:0464c1ef5e39f457bc959819f4e178d5a38ca3ec7eb00a81d536ac5463038b0f"}, + {file = "gmpy2-2.3.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a80f81db02764f698bdea1477a023ad95f57fc9b8694a02afad44cafca1917"}, + {file = "gmpy2-2.3.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c480a0ab05cf6f02ac7a49470a2310b8b6923c714a64dce2c611a056e66d5e47"}, + {file = "gmpy2-2.3.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:41676a965b47323a5c69d390a6c3c8744029b7ef03f05a76c49bf607a612bb5a"}, + {file = "gmpy2-2.3.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:5a9b05327d25a2f4d61f702477f0d47fa936ad82ae29a6a8737be8313c4fb21a"}, + {file = "gmpy2-2.3.1-cp315-cp315-win_amd64.whl", hash = "sha256:573d9742b30a1f45bd50bd52b25dede7b0bc9122b97efe84a13f09e51f689dd9"}, + {file = "gmpy2-2.3.1-cp315-cp315-win_arm64.whl", hash = "sha256:83fe9da759375daa3c97a6d2458a2d84f4dc3a3d39bb15e49fb3785c54d9062a"}, + {file = "gmpy2-2.3.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e6976cf921c7a6fc49e32303bbe37a377827742e2c7c9b7fbda42692381f58ef"}, + {file = "gmpy2-2.3.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:50541a8369ec1639dd9a91db8df212b60e3749b6822848349aec031aeaad71d3"}, + {file = "gmpy2-2.3.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46dfe8fe9c570796631dda28afcbf1982fb974cfd9b03e344cb0692bcea746b3"}, + {file = "gmpy2-2.3.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e853640df4e745cefe4cac18335fb315633d3372daca353ee4ddfdff5f0517e9"}, + {file = "gmpy2-2.3.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:f6eeb5576094bac64fadb3dd8d07f8f69cf339830eafdb26d2dfa6b90edb2432"}, + {file = "gmpy2-2.3.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:03e3ad5578f34107d4d5b6c2bb44922a046e7ac552cc9f26430d07a04ef031f8"}, + {file = "gmpy2-2.3.1-cp315-cp315t-win_amd64.whl", hash = "sha256:1f62ab7409086899852463dce6dfc131ca67830fac2f4e0d6b4cc9b3ff597fa6"}, + {file = "gmpy2-2.3.1-cp315-cp315t-win_arm64.whl", hash = "sha256:e78a0e2dd489da512cdabcd518b0b7b3075c29efde6ae33375c2ee65362d5363"}, + {file = "gmpy2-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a3a2bf973af4f28ea9a033d2c7ad21e3b982e94a7c2c35d4795775f638c7b87"}, + {file = "gmpy2-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d3af971453bd74794a15fc845045ac9d684e9442f7a6ef22d942b98d356050b"}, + {file = "gmpy2-2.3.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5259e9548056bad5acd0e0519c86e895eda77080dd42760060fca3df25b6fc01"}, + {file = "gmpy2-2.3.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ffa6710dc785223045ae25a3c71ac6cc6c5ac116a13fce86097943bdf35ccef"}, + {file = "gmpy2-2.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bee2840cd554d3bf790038eb6c2c35c3e9533ba0f7769adb040fe2cee3553d2f"}, + {file = "gmpy2-2.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4edb11d3691fddd456bbbf8c5ca0c3a0093c0e907b8df70a72bbe4eec31c46a6"}, + {file = "gmpy2-2.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:78e129107fcbeed59b9fcdf297f427505b749a84dfb2f48500f5dfdb22c79d89"}, + {file = "gmpy2-2.3.1-cp39-cp39-win_arm64.whl", hash = "sha256:e4c8b8d2acd466bba6a5992c0e65c3f645df9507542de6b61bdeabbd216e4f9b"}, + {file = "gmpy2-2.3.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bf92c2e3d3407b1cd860ac5771f4de0971d9f4fb71bddb16af92af4d74e96543"}, + {file = "gmpy2-2.3.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:c65f6b335bae8b0307deae478dbffd20281908d9b3f4e1dfbfe35e583bd57b0f"}, + {file = "gmpy2-2.3.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c6bafc81bd518a5ddbab253fbfa95db4980baf24b5b96c8b0f81a130e8fe6327"}, + {file = "gmpy2-2.3.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00de568482f4876e815ec871e1fa2bc10b6b7fd162e82908282f830bebeb1329"}, + {file = "gmpy2-2.3.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:9bd518d118dbf7221eff8c108c3fe9870f940485ad6769b08e980f74247e9e14"}, + {file = "gmpy2-2.3.1.tar.gz", hash = "sha256:313f35e9fe6b9ddf72759b14dac25166fe5757c970403e4bbf87a70ab2be07df"}, ] [package.extras] docs = ["sphinx (>=4)", "sphinx-rtd-theme (>=1)"] -tests = ["cython", "hypothesis", "mpmath", "numpy ; python_version >= \"3.11\"", "pytest", "setuptools"] +tests = ["cython", "hypothesis", "mpmath", "numpy ; python_version >= \"3.11\" and python_version < \"3.15\"", "pytest", "setuptools"] [[package]] name = "gmpy2-stubs" @@ -1353,84 +1346,56 @@ files = [ [[package]] name = "numpy" -version = "2.4.6" +version = "2.5.0" description = "Fundamental package for array computing in Python" optional = false -python-versions = ">=3.11" +python-versions = ">=3.12" groups = ["main"] files = [ - {file = "numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4"}, - {file = "numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d"}, - {file = "numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8"}, - {file = "numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538"}, - {file = "numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47"}, - {file = "numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93"}, - {file = "numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8"}, - {file = "numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6"}, - {file = "numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8"}, - {file = "numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147"}, - {file = "numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577"}, - {file = "numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1"}, - {file = "numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb"}, - {file = "numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41"}, - {file = "numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698"}, - {file = "numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f"}, - {file = "numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853"}, - {file = "numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a"}, - {file = "numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2"}, - {file = "numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45"}, - {file = "numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751"}, - {file = "numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8"}, - {file = "numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0"}, - {file = "numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb"}, - {file = "numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f"}, - {file = "numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3"}, - {file = "numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b"}, - {file = "numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089"}, - {file = "numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a"}, - {file = "numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605"}, - {file = "numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91"}, - {file = "numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359"}, - {file = "numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778"}, - {file = "numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1"}, - {file = "numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe"}, - {file = "numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997"}, - {file = "numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20"}, - {file = "numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d"}, - {file = "numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67"}, - {file = "numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd"}, - {file = "numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab"}, - {file = "numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75"}, - {file = "numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd"}, - {file = "numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079"}, - {file = "numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7"}, - {file = "numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5"}, - {file = "numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096"}, - {file = "numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b"}, - {file = "numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8"}, - {file = "numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402"}, - {file = "numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb"}, - {file = "numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1"}, - {file = "numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261"}, - {file = "numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6"}, - {file = "numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a"}, - {file = "numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e"}, - {file = "numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e"}, - {file = "numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43"}, - {file = "numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e"}, - {file = "numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895"}, - {file = "numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4"}, - {file = "numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063"}, - {file = "numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627"}, - {file = "numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66"}, - {file = "numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662"}, - {file = "numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7"}, - {file = "numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f"}, - {file = "numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c"}, - {file = "numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0"}, - {file = "numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02"}, - {file = "numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73"}, - {file = "numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda"}, + {file = "numpy-2.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:489780423903667933b4ed6197b6ec3b75ea5dd17d1d8f0f38d798feb6921561"}, + {file = "numpy-2.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ece55976ced6bca95a03ae2839e2e5ccffe8eb6a3e7022415645eb154a81e4e6"}, + {file = "numpy-2.5.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:c83b664b0e6eee9594fa920cf0639d8af796606d3fad6cc70180c87e4b97c7be"}, + {file = "numpy-2.5.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:bf80333980bf37f523341ddd72c783f39d6829ec7736b9eb99086388a2d52cc2"}, + {file = "numpy-2.5.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1a4874217b36d5ac8fc876f52e39df56f8182c88463e9e2dceabf7ca8b7efb8"}, + {file = "numpy-2.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aaa760137137e8d3c920d27927748215b56014f92667dc9b6c27dfc61249255a"}, + {file = "numpy-2.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7174ce8265fc7f7417d171c9ea8fe905220748893ea67a2a7abe726ec331c4b0"}, + {file = "numpy-2.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b8c3daaf99de52415d20b42f8e8155c78642cb04207d02f9d317a0dcf1b3fb54"}, + {file = "numpy-2.5.0-cp312-cp312-win32.whl", hash = "sha256:6206db0af545d73d068add6d992279145f158428d1da6cc49adc4b630c5d6ee5"}, + {file = "numpy-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:6f2d6873e2940c860a309d21e25b1e69af6aaffdd80aa056b04c16380db1c4f2"}, + {file = "numpy-2.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:a55e1eb2bca2cfd17a16b213c99dfc8502d47b0d494224d2122277d0400935ca"}, + {file = "numpy-2.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:520e6b8be0a4b65840ac8090d4f51cef4bed66e2b0894d5a520f099adc24a9b2"}, + {file = "numpy-2.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:146b81cdd3967fdb6beca8ba25f00c58741d8f3cbd797f55af0fbe0bfec3469c"}, + {file = "numpy-2.5.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:126b88d95e8ff9b00c9e717aa540469f21d6180162f84c0caec51b16215d49cd"}, + {file = "numpy-2.5.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d4313cef1594c5ce46c31b6e54e918338f63f16ee9322304e8c9114d6d81c8bd"}, + {file = "numpy-2.5.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:750fb097caf26fa878746d9d119f6f9da12dedcbff1eea966c3e3447647c4a9e"}, + {file = "numpy-2.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3893adc2dc7c0412ba76777db55a049215d99c9aa3113003be8f49f4f1290ab9"}, + {file = "numpy-2.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:835e454dd99b238cdc5a3f63bce2371296f5ebc53ca1e0f8e6ddbb6d92a29aab"}, + {file = "numpy-2.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f9836778081a0a3c02a6a21493f3e9f5b311f8d2541934f31f05583dc999ea4"}, + {file = "numpy-2.5.0-cp313-cp313-win32.whl", hash = "sha256:0b525be4744b60bb0557ac872d53ef07d085b5f39622bc579c98d3809d05b988"}, + {file = "numpy-2.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:44353e2878930039db472b99dc353d749826e4010bd4d2a7f835e94a97a5c748"}, + {file = "numpy-2.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:48f54b00711f83a5f796b70c518e8c2b3c5848dda03a54911f23eb68519b9b60"}, + {file = "numpy-2.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f27582c55ba4c750b7c58c8faf021d2cd9324a662b466229db8a417b41368af9"}, + {file = "numpy-2.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:28e7137057d551e4a83c4ae414e3451f50568409db7569aacc7f9811ee06a446"}, + {file = "numpy-2.5.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e1da54b53e75cd9fcfc23efcc7edab2c6aecf97b6037566d8a0fe804af8ec57c"}, + {file = "numpy-2.5.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:694d8f74e156f7fd01179f1aa8faa2f648ab6ae0f70b6c3fe57a03249aea2303"}, + {file = "numpy-2.5.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a7569a7b53c77716f036bb28cb1c91f166a26ec7d9502cd1e4bdfe502fdec22"}, + {file = "numpy-2.5.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:39a0433bd4086ebd462960cf375e19195bb07b53dc1d87dd5fcf47ad78576f03"}, + {file = "numpy-2.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:929f0c79ac38bcbd7154fe631dc907abfeddbcc5027a896bd1f7767323271e7a"}, + {file = "numpy-2.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cc4f247a47bbf070bfd70be53ccdcf47b800af563535e7bbe172322197c30e21"}, + {file = "numpy-2.5.0-cp314-cp314-win32.whl", hash = "sha256:5dc71423499fab3f46f7a7201155ade1669ea101f2f429d332df9e72f8161731"}, + {file = "numpy-2.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:ebb81d9d5443e0309d6c54894c3fbed74ad7da0714352a67b6d773cd189eae73"}, + {file = "numpy-2.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:3b94d0d0deceebfad3e67ae5c0e5eb87371e8f7a0581cd04a779928c2450cf1e"}, + {file = "numpy-2.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:22f3d43e362d650bc39db1f17851302874a148ca95ba6981c1dfb5fa6862f35b"}, + {file = "numpy-2.5.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:243563efb4cd7528a264567e9fd206c87826457322521d06206a00bfa316c927"}, + {file = "numpy-2.5.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:84881d825ca75249b189bbee875fcfe3238aa5c479e6100893cda566e8e86826"}, + {file = "numpy-2.5.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cda12aa4779d42b8771180aba759c96f527d43446d8f380ab59e2b35e8489efd"}, + {file = "numpy-2.5.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c0121101093d2bd74981b10f8837d78e794a8ff57834eb27179f49e1ba11ac6"}, + {file = "numpy-2.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d371c92cfa09da00022f501ab67fafaea813d752eb30ac44336d45b1e5b0268a"}, + {file = "numpy-2.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9990713e9c38154c6861e7547f1e3fc7a87e75ff09bab24ef1cc81d81c2835e9"}, + {file = "numpy-2.5.0-cp314-cp314t-win32.whl", hash = "sha256:edadfbd4794b1086c0d822f81863e8a68fc129d132fd0bb9e31e955d7fbbbdb7"}, + {file = "numpy-2.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f7e5fa4382967ae6548bd2f174219afb908e294b0d5f625af01166edd5f7d9aa"}, + {file = "numpy-2.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:016623417bb330d719d579daf2d6b9a01ddc52e41a9ed61a47f39fde46dcd865"}, + {file = "numpy-2.5.0.tar.gz", hash = "sha256:5a129578019311b6e56bdd714250f19b518f7dceeeb8d1af5490f4942d3f891c"}, ] [[package]] @@ -1885,14 +1850,14 @@ types = ["typing_extensions"] [[package]] name = "pyright" -version = "1.1.410" +version = "1.1.411" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "pyright-1.1.410-py3-none-any.whl", hash = "sha256:5e961bed37cacf96b3f7cd7b1da39b350a9239aa2e69138d0e88f728cfaf296c"}, - {file = "pyright-1.1.410.tar.gz", hash = "sha256:07a073b8ba6749826773c1269773efa11b93440d9a6aa60419d9a3172d6dc488"}, + {file = "pyright-1.1.411-py3-none-any.whl", hash = "sha256:dc7c72a8e2700c55baa127554040e067041ea53ccfd50bf96308cc4291c7d5d9"}, + {file = "pyright-1.1.411.tar.gz", hash = "sha256:d885a0551f2e763b089a02702174e7f4ba77548cddabc972ab86d1f7f1b0f998"}, ] [package.dependencies] @@ -2085,30 +2050,30 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.15.18" +version = "0.15.20" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.15.18-py3-none-linux_armv6l.whl", hash = "sha256:8b6850172348c8381b8b3084c5915a4393c2373b9b54cd5b5e1ea15812bc10df"}, - {file = "ruff-0.15.18-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3fccc153a85417dcd976883160cacce486997b0a0058dd18f54b8aaaac7d1ce2"}, - {file = "ruff-0.15.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:08d4c86a68f2c3ec2c9d56380a71fb4a4f65373055cbb8caabd645e9102f38d4"}, - {file = "ruff-0.15.18-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37e5108745c2c0705da916d7d4de533ddf547051ef45f62888c31bae73f66318"}, - {file = "ruff-0.15.18-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56949a6ce8b3abde54c0bcb22cebfe57e8771cadc84b407ae8b8eaf67ebdcd43"}, - {file = "ruff-0.15.18-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a754cd6a1b630d3f97e33eb452cf7a98040482318e870f8bc52a5a30e62657"}, - {file = "ruff-0.15.18-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ba7a07e03a44dbf10bb086ee06705b173625014ec99f73a7e6836a5e5590a0c"}, - {file = "ruff-0.15.18-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a2c40a41a4cadbcf5897b548ab29dfe248b20c540961c0247d98a3973c70403"}, - {file = "ruff-0.15.18-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f0480ce690cbb6c4db6e5d08f19fce98e10ba131a8b60c1bcdac42771e3ae2d"}, - {file = "ruff-0.15.18-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2330215f1f393fa8733f55edce04fcf94c36a2c460fcde31f78cc84e4951e9b1"}, - {file = "ruff-0.15.18-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6aa6a3d979e48ae617578183674bf264fbe7d0114a796a26bd678d67963c7ff"}, - {file = "ruff-0.15.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a81beadbbff2c9c245561ae3f77b16709d87f35eec650d0501679239d3449b22"}, - {file = "ruff-0.15.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2186d9e940ae332ab293623a75b5f4fe49565f449954d50a72a046683aa6b809"}, - {file = "ruff-0.15.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c2abf140438032bc77b2284a6c9944ecd8a19e5f1c7b52b1b8e4a0a80d19a7a"}, - {file = "ruff-0.15.18-py3-none-win32.whl", hash = "sha256:02299e6e9fa5b297a3f6d5d10d7bcd655c925b028bb8b9d4588214549c6b9ec4"}, - {file = "ruff-0.15.18-py3-none-win_amd64.whl", hash = "sha256:dac80dc8d26b2257dbefabed62f5d255c3937b4ccb122da1fc634794fa3578b3"}, - {file = "ruff-0.15.18-py3-none-win_arm64.whl", hash = "sha256:b2c9257fcbd4a3e5b977a1904e6facca016bafe2edc17df24db67cfaee03b4e4"}, - {file = "ruff-0.15.18.tar.gz", hash = "sha256:2698a964c70e8bf402dcb99c8810472d270d141e7aa8c4e13599fd52033a2f33"}, + {file = "ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078"}, + {file = "ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b"}, + {file = "ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460"}, + {file = "ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21"}, + {file = "ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415"}, + {file = "ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca"}, + {file = "ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566"}, ] [[package]] @@ -2226,14 +2191,14 @@ typing_extensions = ">=4.14.0" [[package]] name = "typer" -version = "0.26.7" +version = "0.26.8" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "typer-0.26.7-py3-none-any.whl", hash = "sha256:5c87cfbc5d34491c5346ebf49c23e18d56ccb863268d3a8d592b26087c2f5e58"}, - {file = "typer-0.26.7.tar.gz", hash = "sha256:e314a34c617e419c091b2830dda3ea1f257134ff593061a8f5b9717ab8dddb3a"}, + {file = "typer-0.26.8-py3-none-any.whl", hash = "sha256:3512ca79ac5c11113414b36e80281b872884477722440691c89d1112e321a49c"}, + {file = "typer-0.26.8.tar.gz", hash = "sha256:c244a6bd558886fe3f8780efb6bdd28bb9aff005a94eedebaa5cb32926fe2f7e"}, ] [package.dependencies] @@ -2477,4 +2442,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "07c05e549897aa70786a11bc3fccc2f2b95848798293660c30f9f7c0d7c66be3" +content-hash = "bf1c224e390426edd4a7cf8de180b4c7c83293aceec0302c4b0089c882e3eb0a" diff --git a/pyproject.toml b/pyproject.toml index 33feabb..8544754 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,14 +60,14 @@ dependencies = [ "gmpy2>=2.3", # if you change here, also change "requires" above "ImageIO>=2.37", "imageio-ffmpeg>=0.6", - "numpy>=2.4", + "numpy>=2.5", "Pillow>=12.2", "rich>=15.0", "setuptools>=82.0", # if you change here, also change "requires" above "tqdm>=4.68", "transai>=1.3.3", "transcrypto>=2.7", - "typer>=0.26.7", # if this changes, also change: [tool.poetry.dependencies] + "typer>=0.26.8", # if this changes, also change: [tool.poetry.dependencies] ] @@ -125,7 +125,7 @@ script = "scripts/build_extensions.py" # prefer to add dependencies inside the [project.dependencies] section python = "^3.12" # if version changes, remember to change README.md -typer = { version = "^0.26.7", extras = ["all"] } # if this changes, also change: dependencies +typer = { version = "^0.26.8", extras = ["all"] } # if this changes, also change: dependencies [tool.poetry.group.dev.dependencies] @@ -138,7 +138,7 @@ pytest = "^9.1" pytest-cov = "^7.1" pytest-flakefinder = "^1.1" pre-commit = "^4.6" -ruff = "^0.15.18" +ruff = "^0.15.20" typeguard = "^4.5" # project-specific dev-only diff --git a/requirements.txt b/requirements.txt index ea07948..161768c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,17 @@ annotated-doc==0.0.4 ; python_version >= "3.12" and python_version < "4.0" annotated-types==0.7.0 ; python_version >= "3.12" and python_version < "4.0" -anyio==4.14.0 ; python_version >= "3.12" and python_version < "4.0" +anyio==4.14.1 ; python_version >= "3.12" and python_version < "4.0" certifi==2026.6.17 ; python_version >= "3.12" and python_version < "4.0" cffi==2.0.0 ; python_version >= "3.12" and python_version < "4.0" and platform_python_implementation != "PyPy" -click==8.4.1 ; python_version >= "3.12" and python_version < "4.0" +click==8.4.2 ; python_version >= "3.12" and python_version < "4.0" colorama==0.4.6 ; python_version >= "3.12" and python_version < "4.0" and platform_system == "Windows" cryptography==49.0.0 ; python_version >= "3.12" and python_version < "4.0" -cython==3.2.5 ; python_version >= "3.12" and python_version < "4.0" +cython==3.2.6 ; python_version >= "3.12" and python_version < "4.0" diskcache==5.6.3 ; python_version >= "3.12" and python_version < "4.0" filelock==3.29.4 ; python_version >= "3.12" and python_version < "4.0" fsspec==2026.6.0 ; python_version >= "3.12" and python_version < "4.0" func-timeout==4.3.5 ; python_version >= "3.12" and python_version < "4.0" -gmpy2==2.3.0 ; python_version >= "3.12" and python_version < "4.0" +gmpy2==2.3.1 ; python_version >= "3.12" and python_version < "4.0" h11==0.16.0 ; python_version >= "3.12" and python_version < "4.0" hf-xet==1.5.1 ; python_version >= "3.12" and python_version < "4.0" and (platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "arm64" or platform_machine == "aarch64") httpcore==1.0.9 ; python_version >= "3.12" and python_version < "4.0" @@ -28,7 +28,7 @@ markdown-it-py==4.2.0 ; python_version >= "3.12" and python_version < "4.0" markupsafe==3.0.3 ; python_version >= "3.12" and python_version < "4.0" mdurl==0.1.2 ; python_version >= "3.12" and python_version < "4.0" msgspec==0.21.1 ; python_version >= "3.12" and python_version < "4.0" -numpy==2.4.6 ; python_version >= "3.12" and python_version < "4.0" +numpy==2.5.0 ; python_version >= "3.12" and python_version < "4.0" packaging==26.2 ; python_version >= "3.12" and python_version < "4.0" pillow==12.2.0 ; python_version >= "3.12" and python_version < "4.0" platformdirs==4.10.0 ; python_version >= "3.12" and python_version < "4.0" @@ -43,7 +43,7 @@ shellingham==1.5.4 ; python_version >= "3.12" and python_version < "4.0" tqdm==4.68.3 ; python_version >= "3.12" and python_version < "4.0" transai==1.3.3 ; python_version >= "3.12" and python_version < "4.0" transcrypto==2.7.0 ; python_version >= "3.12" and python_version < "4.0" -typer==0.26.7 ; python_version >= "3.12" and python_version < "4.0" +typer==0.26.8 ; python_version >= "3.12" and python_version < "4.0" typing-extensions==4.15.0 ; python_version >= "3.12" and python_version < "4.0" typing-inspection==0.4.2 ; python_version >= "3.12" and python_version < "4.0" wsproto==1.3.2 ; python_version >= "3.12" and python_version < "4.0" diff --git a/src/tranzoom/cli/base.py b/src/tranzoom/cli/base.py index 70b6561..f9f20c9 100644 --- a/src/tranzoom/cli/base.py +++ b/src/tranzoom/cli/base.py @@ -1575,7 +1575,7 @@ def _SmartImage(i: int) -> image.Image: try: def _TwoFrameRenderStream() -> abc.Iterator[ - tuple[zoom.RenderedZoomFrame, zoom.RenderedZoomFrame | None] + tuple[pixels.RenderedZoomFrame, pixels.RenderedZoomFrame | None] ]: """Render base frames with a rolling [curr, next] window. @@ -1589,12 +1589,12 @@ def _TwoFrameRenderStream() -> abc.Iterator[ (frameN-1, None) Yields: - tuple[zoom.RenderedZoomFrame, zoom.RenderedZoomFrame | None]: A tuple of + tuple[pixels.RenderedZoomFrame, pixels.RenderedZoomFrame | None]: A tuple of the current frame and the next frame (or None if at the end) """ - curr_frame: zoom.RenderedZoomFrame = _StreamingRenderFrame(0) - next_frame: zoom.RenderedZoomFrame | None = _StreamingRenderFrame(1) # (MIN_FRAMES is 3) + curr_frame: pixels.RenderedZoomFrame = _StreamingRenderFrame(0) + next_frame: pixels.RenderedZoomFrame | None = _StreamingRenderFrame(1) # (MIN_FRAMES=3) for i in range(zoom_params.n_frames): yield (curr_frame, next_frame) if next_frame is None: @@ -1602,14 +1602,14 @@ def _TwoFrameRenderStream() -> abc.Iterator[ curr_frame = next_frame next_frame = _StreamingRenderFrame(i + 2) if i + 2 < zoom_params.n_frames else None - def _StreamingRenderFrame(i: int) -> zoom.RenderedZoomFrame: + def _StreamingRenderFrame(i: int) -> pixels.RenderedZoomFrame: """Render a single frame, returning the image data. Only one in memory at a time. Args: i (int): The index of the frame in the zoom sequence. Returns: - zoom.RenderedZoomFrame: The rendered image data for the frame at index i. + pixels.RenderedZoomFrame: The rendered image data for the frame at index i. """ # render the frame, get the image data and hash @@ -1642,7 +1642,7 @@ def _StreamingRenderFrame(i: int) -> zoom.RenderedZoomFrame: # update progress bar, return data if p_bar: p_bar.update(1) - return zoom.RenderedZoomFrame( + return pixels.RenderedZoomFrame( idx=i, data=img_data, data_hash=data_hash, img_path=img_path ) @@ -1701,6 +1701,7 @@ def _StreamingRenderFrame(i: int) -> zoom.RenderedZoomFrame: i_frames=zoom_params.render.i_frames, zoom_per_step=float(zoom_params.scalar_magnification_per_step), use_quadratic=zoom.DEFAULT_USE_QUADRATIC, + max_threads=config.max_threads, ) if zoom_params.render.anim == pixels.AnimationEncoding.GIF: zoom.WriteAnimatedGIF( diff --git a/src/tranzoom/core/fractal.py b/src/tranzoom/core/fractal.py index 268b69e..949c8b0 100644 --- a/src/tranzoom/core/fractal.py +++ b/src/tranzoom/core/fractal.py @@ -195,10 +195,10 @@ def ComputeFractal( if params.frm.fractal == frame.Fractal.MANDELBROT else PY_JULIA_COMPUTATION ) - # log the start of the render (not pre-computation anymore here) + # log the start of the actual computation (not pre-computation anymore here) logging.info( f'{params.frm.fractal.value.upper()} using {n_processes} process(es) ' - f'for {"PRE " if is_preprocess else ""}rendering - {actual_opt_msg}' + f'for {"PRE " if is_preprocess else ""}computation - {actual_opt_msg}' ) # create inputs inp: list[image.FractalTaskInput] = [ diff --git a/src/tranzoom/core/pixels.py b/src/tranzoom/core/pixels.py index 8c90eae..701ecb6 100644 --- a/src/tranzoom/core/pixels.py +++ b/src/tranzoom/core/pixels.py @@ -28,7 +28,7 @@ import imageio_ffmpeg # type: ignore import numpy as np from numpy.typing import NDArray -from PIL import ExifTags, ImageDraw, ImageFont, PngImagePlugin +from PIL import ExifTags, ImageDraw, ImageFilter, ImageFont, PngImagePlugin from PIL import Image as PILImage from transcrypto.core import hashes from transcrypto.utils import base as tbase @@ -47,6 +47,15 @@ # interior points are stored as -(int(floor(scale * |z|)) + 1), with scale = RES / MAX_Z = RES / 2 +# interpolation constants; these could conceivably be made user-configurable, but for that they +# would need to be added to the ZoomParameters dataclass and serialized in the JSON, which is +# a bit overkill for now +ERODE_LINEAR: int = 5 +BLUR_LINEAR: float = 16.0 +ERODE_QUADRATIC: int = 8 +BLUR_QUADRATIC: float = 32.0 + + class Error(frame.Error): """Base image exception.""" @@ -1388,6 +1397,223 @@ def ValidateIFrames(i_frames: int) -> None: raise Error(f'Interpolation must be between 0 and {MAX_INTERPOLATION_FRAMES}, got {i_frames=}') +#################################################################################################### +# +# Rendering Interpolation Code +# +# The way the code is organized makes it easy to add a Cython InterpolateFrameWorker() +# implementation for speed, if needed. BUT BEWARE: +# +# (1) if they are moved to core/fractalfast.py the compiled Hybrid code will have differences to +# the pure Python code, and the results will NOT be bit-for-bit identical (we tested); +# +# (2) there are 2 ways of making a pure Cython implementation: +# (a) Cython off only the numpy math, but keep PIL operations in PIL: this has meager speedup, +# tests we did show that even that will have results that are NOT bit-for-bit identical; +# (b) Cython off the entire function, including PIL operations: this reasonable, but it is +# a huge risk and has ZERO chance of being bit-for-bit identical to the pure Python code. +# +# So we gave up of this optimization path for now. +# +# TODO: revisit this if we need to speed up interpolation. +# +#################################################################################################### + + +@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) +class RenderedZoomFrame: + """One fully-rendered base animation frame.""" + + idx: int + data: Pixels + data_hash: str + img_path: pathlib.Path + + +@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) +class InterpolationJob: + """A job for interpolating a frame between two rendered zoom frames.""" + + job_index: int + curr_frame: RenderedZoomFrame + next_frame: RenderedZoomFrame + next2_frame: RenderedZoomFrame | None + i_frames: int + zoom_per_step: float + use_quadratic: bool + + +@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) +class InterpolationResult: + """The result of interpolating a frame between two rendered zoom frames.""" + + data_hash: str + png: bytes + + +def InterpolateFrameWorker(job: InterpolationJob) -> InterpolationResult: + """Worker function to interpolate a frame between two rendered zoom frames. + + Args: + job (InterpolationJob): The job containing the current and next frames + parameters. + + Returns: + InterpolationResult: The result containing the interpolated frame's hash and PNG bytes. + + """ + # frac is the fraction of the way between curr_frame and next_frame for this interpolated frame + frac: float = float(job.job_index + 1) / float(job.i_frames + 1) + # make the Pixels based on the interpolation method (linear or quadratic) + pix: Pixels = ( + _LinearInterpolatedFrame( + job.curr_frame, job.next_frame, zoom_per_step=job.zoom_per_step, frac=frac + ) + if job.next2_frame is None or not job.use_quadratic + else _QuadraticInterpolatedFrame( + job.curr_frame, job.next_frame, job.next2_frame, zoom_per_step=job.zoom_per_step, frac=frac + ) + ) + # return the interpolation result + return InterpolationResult(data_hash=pix.data_hash, png=pix.PNG(copy_previous=False)[0]) + + +def _LinearInterpolatedFrame( + curr_img: RenderedZoomFrame, + next_img: RenderedZoomFrame, + *, + zoom_per_step: float, + frac: float, +) -> Pixels: + """Interpolate between curr_img and next_img at fraction frac. + + Args: + curr_img (RenderedZoomFrame): The current rendered zoom frame. + next_img (RenderedZoomFrame): The next rendered zoom frame. + zoom_per_step (float): The zoom factor per step between frames. + frac (float): The interpolation fraction between 0.0 and 1.0. + + Returns: + Pixels: Data object representing the interpolated image; NO META is included + + Raises: + Error: on error + + """ + # check params and convert images + if not math.isfinite(zoom_per_step) or zoom_per_step <= 0.0: + raise Error(f'Invalid zoom_per_step: {zoom_per_step}') + if not (0.0 <= frac <= 1.0): + raise Error(f'Invalid interpolation fraction: {frac}') + # get border from "current" + curr_border: tuple[int, int, int] = _BorderFillColor(curr_img.data) + # align both images to the virtual zoom depth between the two real frames + curr_aligned: Pixels = _CenterZoomRGB(curr_img.data, zoom_per_step**frac, fill_color=curr_border)[ + 0 + ] + next_aligned_raw: Pixels + next_valid_mask: NDArray[np.uint8] | None + next_aligned_raw, next_valid_mask = _CenterZoomRGB( + next_img.data, zoom_per_step ** (frac - 1.0), return_mask=True, fill_color=curr_border + ) + if next_valid_mask is None: + raise Error('next_valid_mask is None, but it should not be; bug! report') + # the future frames will have a black border where the zoomed-out image is outside the + # original image; we create a soft alpha mask to blend the current frame into the next frame + # to avoid harsh transitions + next_alpha_mask: NDArray[np.uint8] = _FeatherValidMask( + next_valid_mask, erode_pixels=ERODE_LINEAR, blur_pixels=BLUR_LINEAR + ) + alpha1: NDArray[np.float32] = frac * _MaskArray(next_alpha_mask) + return Pixels( + data=(curr_aligned.data * (1.0 - alpha1)) + (next_aligned_raw.data * alpha1), # pyright: ignore[reportArgumentType] + meta={}, + ) + + +def _QuadraticInterpolatedFrame( # noqa: PLR0914 + curr_img: RenderedZoomFrame, + next_img_1: RenderedZoomFrame, + next_img_2: RenderedZoomFrame, + *, + zoom_per_step: float, + frac: float, +) -> Pixels: + """Quadratic interpolation using curr_img, next_img_1, next_img_2. + + Points are interpreted as: + curr_img at x = 0 + next_img_1 at x = 1 + next_img_2 at x = 2 + + We evaluate the quadratic at x = t, where 0 < t < 1. + + Args: + curr_img (RenderedZoomFrame): The current rendered zoom frame. + next_img_1 (RenderedZoomFrame): The next rendered zoom frame. + next_img_2 (RenderedZoomFrame): The next rendered zoom frame after next_img_1. + zoom_per_step (float): The zoom factor per step between frames. + frac (float): The interpolation fraction between 0.0 and 1.0. + + Returns: + Pixels: Data object representing the interpolated image; NO META is included + + Raises: + Error: on error + + """ + # check params and convert images + if not math.isfinite(zoom_per_step) or zoom_per_step <= 0.0: + raise Error(f'Invalid zoom_per_step: {zoom_per_step}') + if not (0.0 <= frac <= 1.0): + raise Error(f'Invalid interpolation fraction: {frac}') + # align all three samples to the same virtual zoom depth + curr_border: tuple[int, int, int] = _BorderFillColor(curr_img.data) + curr_aligned: Pixels = _CenterZoomRGB(curr_img.data, zoom_per_step**frac, fill_color=curr_border)[ + 0 + ] + next_aligned_1_raw: Pixels + next_valid_mask_1: NDArray[np.uint8] | None + next_aligned_1_raw, next_valid_mask_1 = _CenterZoomRGB( + next_img_1.data, zoom_per_step ** (frac - 1.0), return_mask=True, fill_color=curr_border + ) + next_aligned_2_raw: Pixels + next_valid_mask_2: NDArray[np.uint8] | None + next_aligned_2_raw, next_valid_mask_2 = _CenterZoomRGB( + next_img_2.data, zoom_per_step ** (frac - 2.0), return_mask=True, fill_color=curr_border + ) + if next_valid_mask_1 is None or next_valid_mask_2 is None: + raise Error('next_valid_mask_1|2 is None, but it should not be; bug! report') + # the future frames will have a black border where the zoomed-out image is outside the + # original image; we create a soft alpha mask to blend the current frame into the next frame + # to avoid harsh transitions + soft_mask_1: NDArray[np.uint8] = _FeatherValidMask( + next_valid_mask_1, erode_pixels=ERODE_LINEAR, blur_pixels=BLUR_LINEAR + ) + soft_mask_2: NDArray[np.uint8] = _FeatherValidMask( + next_valid_mask_2, erode_pixels=ERODE_QUADRATIC, blur_pixels=BLUR_QUADRATIC + ) + # blend using Lagrange interpolation + w0: float = ((frac - 1.0) * (frac - 2.0)) / 2.0 + w1: float = -frac * (frac - 2.0) + w2: float = (frac * (frac - 1.0)) / 2.0 + alpha1: NDArray[np.float32] = _MaskArray(soft_mask_1) + alpha2: NDArray[np.float32] = _MaskArray(soft_mask_2) + # fade future-frame contributions out near their invalid borders; + # important: when future weights are masked away, give the missing weight + # back to curr_aligned: this keeps brightness stable and avoids dark seams + effective_w0: NDArray[np.float32] = w0 + (w1 * (1.0 - alpha1)) + (w2 * (1.0 - alpha2)) # pyright: ignore[reportAssignmentType] + effective_w1: NDArray[np.float32] = w1 * alpha1 + effective_w2: NDArray[np.float32] = w2 * alpha2 + return Pixels( + data=( + (effective_w0 * curr_aligned.data) + + (effective_w1 * next_aligned_1_raw.data) + + (effective_w2 * next_aligned_2_raw.data) + ), # pyright: ignore[reportArgumentType] + meta={}, + ) + + def _BilinearInterpolate( data: NDArray[np.float32], src_x: float, @@ -1446,3 +1672,190 @@ def _LoadAndCheckMetadataKeys(img_m: abc.Iterable[tuple[Any, Any]]) -> dict[str, raise Error(f'Invalid metadata key type {type(k)} for key {k!r}') m[k] = str(v) return m + + +def _CenterZoomRGB( + img: Pixels, + scale: float, + *, + return_mask: bool = False, + fill_color: tuple[int, int, int] | None = None, +) -> tuple[Pixels, NDArray[np.uint8] | None]: + """Return img zoomed around its center. + + scale > 1 zooms in. + scale < 1 zooms out. + scale == 1 returns a copy. + + If return_mask is True, also return an L-mode validity mask: + MAX_COLOR where the transformed output samples from inside the source image. + 0 where the transformed output is outside the source image. + + Args: + img (Pixels): The input RGB image to be zoomed. + scale (float): The zoom scale factor. Must be a finite positive number. + return_mask (bool): Whether to return the transform validity mask; default False. + fill_color (tuple[int, int, int] | None): Optional RGB fill color for areas outside the + source image. If None, the fill color is estimated from the median of the border pixels. + + Returns: + tuple[Pixels, NDArray[np.uint8] | None]: The zoomed image (NO META is included), + optionally with its validity mask. + + Raises: + Error: on error + + """ + # check image and scale are valid + if not math.isfinite(scale) or scale <= 0.0: + raise Error(f'invalid interpolation zoom scale: {scale}') + if fill_color and (max(fill_color) > MAX_COLOR or min(fill_color) < 0): + raise Error(f'invalid fill_color: {fill_color}') + # if scale is effectively 1, return a copy + height: int + width: int + height, width, _ = img.data.shape + if abs(scale - 1.0) < 1e-12: # noqa: PLR2004 + return ( + dataclasses.replace(img, meta={}), + np.full((height, width), MAX_COLOR, dtype=np.uint8) if return_mask else None, + ) + # get center + cx: float = (width - 1) / 2.0 + cy: float = (height - 1) / 2.0 + # compute inverse scale for Pillow affine transform + inv: float = 1.0 / scale + affine: tuple[float, float, float, float, float, float] = ( + inv, + 0.0, + cx - cx * inv, + 0.0, + inv, + cy - cy * inv, + ) + with img.obj as pil_img: + out_pil: PILImage.Image = pil_img.transform( + pil_img.size, + PILImage.Transform.AFFINE, + affine, + resample=PILImage.Resampling.BICUBIC, + fillcolor=fill_color or _BorderFillColor(img), + ) + out: Pixels = Pixels(data=np.asarray(out_pil, dtype=np.float32), meta={}) + # if the caller does not want a mask, return just the zoomed image + if not return_mask: + return (out, None) + # create a mask of the same size as the input image, filled with MAX_COLOR (valid) + mask_src: PILImage.Image = PILImage.new('L', (width, height), MAX_COLOR) + mask_pil: PILImage.Image = mask_src.transform( + (width, height), + PILImage.Transform.AFFINE, + affine, + resample=PILImage.Resampling.NEAREST, + fillcolor=0, + ) + return (out, np.asarray(mask_pil, dtype=np.uint8)) + + +def _BorderFillColor(img: Pixels) -> tuple[int, int, int]: + """Estimate a safer affine fill color from the median of the image border pixels. + + Args: + img (Pixels): The input image. + + Returns: + tuple[int, int, int]: The estimated fill color as an RGB tuple. + + Raises: + Error: on error + + """ + # pick up only border pixels (top, bottom, left, right) + arr: NDArray[np.uint8] = img.clip + border: NDArray[np.uint8] = np.concatenate( + ( + arr[0, :, :], + arr[-1, :, :], + arr[:, 0, :], + arr[:, -1, :], + ), + axis=0, + ) + # compute the median color of the border pixels + color: NDArray[np.float64] = np.median(border, axis=0) + if color.shape != (3,): + raise Error(f'Unexpected border color shape: {color.shape}') + return tuple(int(x) for x in color) # type: ignore[return-value] + + +def _FeatherValidMask( + mask: NDArray[np.uint8], + *, + erode_pixels: int, + blur_pixels: float, +) -> NDArray[np.uint8]: + """Return a soft validity mask. + + The valid region is first eroded, then blurred. This creates a smooth + alpha ramp from valid transformed pixels to invalid/out-of-bounds pixels. + + Args: + mask (NDArray[np.uint8]): validity mask, MAX_COLOR valid and 0 invalid. + erode_pixels (int): Pixels to shrink the hard valid region before blur. + blur_pixels (float): Gaussian blur radius for the alpha ramp. + + Returns: + NDArray[np.uint8]: validity soft mask. + + Raises: + Error: on error + + """ + # sanity check + if mask.ndim != 2: # noqa: PLR2004 + raise Error(f'expected 2-D mask, got shape {mask.shape}') + if mask.dtype != np.uint8: + raise Error(f'expected uint8 mask, got {mask.dtype}') + if erode_pixels < 0: + raise Error(f'pixels must be >= 0, got {erode_pixels}') + if blur_pixels < 0.0: + raise Error(f'blur_pixels must be >= 0, got {blur_pixels}') + # erode & blur + with PILImage.fromarray(mask, mode='L') as mask_img: + soft_mask: PILImage.Image = mask_img + if erode_pixels: + soft_mask = soft_mask.filter(ImageFilter.MinFilter(erode_pixels * 2 + 1)) + if blur_pixels: + soft_mask = soft_mask.filter(ImageFilter.GaussianBlur(blur_pixels)) + soft: NDArray[np.float32] = np.asarray(soft_mask, dtype=np.float32) + # critical: GaussianBlur leaks white alpha into the invalid region: + # clamp it so invalid transformed pixels remain fully transparent + hard_alpha: NDArray[np.float32] = mask.astype(np.float32) / float(MAX_COLOR) + return cast('NDArray[np.uint8]', np.clip(soft * hard_alpha, 0, MAX_COLOR).astype(np.uint8)) # pyright: ignore[reportUnnecessaryCast] + + +def _MaskArray(mask: NDArray[np.uint8]) -> NDArray[np.float32]: + """Convert a uint8 validity mask to a float32 alpha array in [0, 1]. + + Args: + mask (NDArray[np.uint8]): validity mask, MAX_COLOR valid and 0 invalid + + Returns: + NDArray[np.float32]: A float32 array of shape (height, width, 1) with values in [0, 1]. + + Raises: + Error: on error + + """ + # sanity check + if mask.ndim != 2: # noqa: PLR2004 + raise Error(f'expected 2-D mask, got shape {mask.shape}') + if mask.dtype != np.uint8: + raise Error(f'expected uint8 mask, got {mask.dtype}') + # convert to float32 array in [0, 1] + return mask.astype(np.float32)[:, :, None] / float(MAX_COLOR) + + +#################################################################################################### +# end of Rendering Interpolation Code +#################################################################################################### diff --git a/src/tranzoom/core/zoom.py b/src/tranzoom/core/zoom.py index 4d791d0..bd8406b 100644 --- a/src/tranzoom/core/zoom.py +++ b/src/tranzoom/core/zoom.py @@ -13,15 +13,13 @@ import pathlib import subprocess # noqa: S404 from collections import abc +from concurrent import futures from typing import cast import gmpy2 import imageio import imageio_ffmpeg # type: ignore -import numpy as np -from numpy.typing import NDArray from PIL import Image as PILImage -from PIL import ImageFilter from transcrypto.utils import base as tbase from transcrypto.utils import timer @@ -31,10 +29,6 @@ # would need to be added to the ZoomParameters dataclass and serialized in the JSON, which is # a bit overkill for now DEFAULT_USE_QUADRATIC: bool = True # use quadratic interpolation for smoother transitions -_ERODE_LINEAR: int = 5 -_BLUR_LINEAR: float = 16.0 -_ERODE_QUADRATIC: int = 8 -_BLUR_QUADRATIC: float = 32.0 # animation constants @@ -624,16 +618,6 @@ def _FramesSubset( return marker_frames -@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) -class RenderedZoomFrame: - """One fully-rendered base animation frame.""" - - idx: int - data: pixels.Pixels - data_hash: str - img_path: pathlib.Path - - def FrameEstimatedIters(d: int, s: image.FractalStats) -> int: """Estimate a measure for how hard the iterations will be for this frame. @@ -653,332 +637,14 @@ def FrameEstimatedIters(d: int, s: image.FractalStats) -> int: return d // 5 + math.floor((4.0 * d * s.n_interior) / (5.0 * s.n_px)) -def CenterZoomRGB( - img: pixels.Pixels, - scale: float, - *, - return_mask: bool = False, - fill_color: tuple[int, int, int] | None = None, -) -> tuple[pixels.Pixels, NDArray[np.uint8] | None]: - """Return img zoomed around its center. - - scale > 1 zooms in. - scale < 1 zooms out. - scale == 1 returns a copy. - - If return_mask is True, also return an L-mode validity mask: - MAX_COLOR where the transformed output samples from inside the source image. - 0 where the transformed output is outside the source image. - - Args: - img (pixels.Pixels): The input RGB image to be zoomed. - scale (float): The zoom scale factor. Must be a finite positive number. - return_mask (bool): Whether to return the transform validity mask; default False. - fill_color (tuple[int, int, int] | None): Optional RGB fill color for areas outside the - source image. If None, the fill color is estimated from the median of the border pixels. - - Returns: - tuple[pixels.Pixels, NDArray[np.uint8] | None]: The zoomed image (NO META is included), - optionally with its validity mask. - - Raises: - Error: on error - - """ - # check image and scale are valid - if not math.isfinite(scale) or scale <= 0.0: - raise Error(f'invalid interpolation zoom scale: {scale}') - if fill_color and (max(fill_color) > pixels.MAX_COLOR or min(fill_color) < 0): - raise Error(f'invalid fill_color: {fill_color}') - # if scale is effectively 1, return a copy - height: int - width: int - height, width, _ = img.data.shape - if abs(scale - 1.0) < 1e-12: # noqa: PLR2004 - return ( - dataclasses.replace(img, meta={}), - np.full((height, width), pixels.MAX_COLOR, dtype=np.uint8) if return_mask else None, - ) - # get center - cx: float = (width - 1) / 2.0 - cy: float = (height - 1) / 2.0 - # compute inverse scale for Pillow affine transform - inv: float = 1.0 / scale - affine: tuple[float, float, float, float, float, float] = ( - inv, - 0.0, - cx - cx * inv, - 0.0, - inv, - cy - cy * inv, - ) - with img.obj as pil_img: - out_pil: PILImage.Image = pil_img.transform( - pil_img.size, - PILImage.Transform.AFFINE, - affine, - resample=PILImage.Resampling.BICUBIC, - fillcolor=fill_color or BorderFillColor(img), - ) - out: pixels.Pixels = pixels.Pixels(data=np.asarray(out_pil, dtype=np.float32), meta={}) - # if the caller does not want a mask, return just the zoomed image - if not return_mask: - return (out, None) - # create a mask of the same size as the input image, filled with MAX_COLOR (valid) - mask_src: PILImage.Image = PILImage.new('L', (width, height), pixels.MAX_COLOR) - mask_pil: PILImage.Image = mask_src.transform( - (width, height), - PILImage.Transform.AFFINE, - affine, - resample=PILImage.Resampling.NEAREST, - fillcolor=0, - ) - return (out, np.asarray(mask_pil, dtype=np.uint8)) - - -def BorderFillColor(img: pixels.Pixels) -> tuple[int, int, int]: - """Estimate a safer affine fill color from the median of the image border pixels. - - Args: - img (pixels.Pixels): The input image. - - Returns: - tuple[int, int, int]: The estimated fill color as an RGB tuple. - - Raises: - Error: on error - - """ - # pick up only border pixels (top, bottom, left, right) - arr: NDArray[np.uint8] = img.clip - border: NDArray[np.uint8] = np.concatenate( - ( - arr[0, :, :], - arr[-1, :, :], - arr[:, 0, :], - arr[:, -1, :], - ), - axis=0, - ) - # compute the median color of the border pixels - color: NDArray[np.float64] = np.median(border, axis=0) - if color.shape != (3,): - raise Error(f'Unexpected border color shape: {color.shape}') - return tuple(int(x) for x in color) # type: ignore[return-value] - - -def FeatherValidMask( - mask: NDArray[np.uint8], - *, - erode_pixels: int, - blur_pixels: float, -) -> NDArray[np.uint8]: - """Return a soft validity mask. - - The valid region is first eroded, then blurred. This creates a smooth - alpha ramp from valid transformed pixels to invalid/out-of-bounds pixels. - - Args: - mask (NDArray[np.uint8]): validity mask, MAX_COLOR valid and 0 invalid. - erode_pixels (int): Pixels to shrink the hard valid region before blur. - blur_pixels (float): Gaussian blur radius for the alpha ramp. - - Returns: - NDArray[np.uint8]: validity soft mask. - - Raises: - Error: on error - - """ - # sanity check - if mask.ndim != 2: # noqa: PLR2004 - raise Error(f'expected 2-D mask, got shape {mask.shape}') - if mask.dtype != np.uint8: - raise Error(f'expected uint8 mask, got {mask.dtype}') - if erode_pixels < 0: - raise Error(f'pixels must be >= 0, got {erode_pixels}') - if blur_pixels < 0.0: - raise Error(f'blur_pixels must be >= 0, got {blur_pixels}') - # erode & blur - with PILImage.fromarray(mask, mode='L') as mask_img: - soft_mask: PILImage.Image = mask_img - if erode_pixels: - soft_mask = soft_mask.filter(ImageFilter.MinFilter(erode_pixels * 2 + 1)) - if blur_pixels: - soft_mask = soft_mask.filter(ImageFilter.GaussianBlur(blur_pixels)) - soft: NDArray[np.float32] = np.asarray(soft_mask, dtype=np.float32) - # critical: GaussianBlur leaks white alpha into the invalid region: - # clamp it so invalid transformed pixels remain fully transparent - hard_alpha: NDArray[np.float32] = mask.astype(np.float32) / float(pixels.MAX_COLOR) - return cast('NDArray[np.uint8]', np.clip(soft * hard_alpha, 0, pixels.MAX_COLOR).astype(np.uint8)) # pyright: ignore[reportUnnecessaryCast] - - -def MaskArray(mask: NDArray[np.uint8]) -> NDArray[np.float32]: - """Convert a uint8 validity mask to a float32 alpha array in [0, 1]. - - Args: - mask (NDArray[np.uint8]): validity mask, MAX_COLOR valid and 0 invalid - - Returns: - NDArray[np.float32]: A float32 array of shape (height, width, 1) with values in [0, 1]. - - Raises: - Error: on error - - """ - # sanity check - if mask.ndim != 2: # noqa: PLR2004 - raise Error(f'expected 2-D mask, got shape {mask.shape}') - if mask.dtype != np.uint8: - raise Error(f'expected uint8 mask, got {mask.dtype}') - # convert to float32 array in [0, 1] - return mask.astype(np.float32)[:, :, None] / float(pixels.MAX_COLOR) - - -def LinearInterpolatedFrame( - curr_img: RenderedZoomFrame, - next_img: RenderedZoomFrame, - *, - zoom_per_step: float, - frac: float, -) -> pixels.Pixels: - """Interpolate between curr_img and next_img at fraction frac. - - Args: - curr_img (_RenderedZoomFrame): The current rendered zoom frame. - next_img (_RenderedZoomFrame): The next rendered zoom frame. - zoom_per_step (float): The zoom factor per step between frames. - frac (float): The interpolation fraction between 0.0 and 1.0. - - Returns: - pixels.Pixels: Data object representing the interpolated image; NO META is included - - Raises: - Error: on error - - """ - # check params and convert images - if not math.isfinite(zoom_per_step) or zoom_per_step <= 0.0: - raise Error(f'Invalid zoom_per_step: {zoom_per_step}') - if not (0.0 <= frac <= 1.0): - raise Error(f'Invalid interpolation fraction: {frac}') - # get border from "current" - curr_border: tuple[int, int, int] = BorderFillColor(curr_img.data) - # align both images to the virtual zoom depth between the two real frames - curr_aligned: pixels.Pixels = CenterZoomRGB( - curr_img.data, zoom_per_step**frac, fill_color=curr_border - )[0] - next_aligned_raw: pixels.Pixels - next_valid_mask: NDArray[np.uint8] | None - next_aligned_raw, next_valid_mask = CenterZoomRGB( - next_img.data, zoom_per_step ** (frac - 1.0), return_mask=True, fill_color=curr_border - ) - if next_valid_mask is None: - raise Error('next_valid_mask is None, but it should not be; bug! report') - # the future frames will have a black border where the zoomed-out image is outside the - # original image; we create a soft alpha mask to blend the current frame into the next frame - # to avoid harsh transitions - next_alpha_mask: NDArray[np.uint8] = FeatherValidMask( - next_valid_mask, erode_pixels=_ERODE_LINEAR, blur_pixels=_BLUR_LINEAR - ) - alpha1: NDArray[np.float32] = frac * MaskArray(next_alpha_mask) - return pixels.Pixels( - data=(curr_aligned.data * (1.0 - alpha1)) + (next_aligned_raw.data * alpha1), # pyright: ignore[reportArgumentType] - meta={}, - ) - - -def QuadraticInterpolatedFrame( # noqa: PLR0914 - curr_img: RenderedZoomFrame, - next_img_1: RenderedZoomFrame, - next_img_2: RenderedZoomFrame, - *, - zoom_per_step: float, - frac: float, -) -> pixels.Pixels: - """Quadratic interpolation using curr_img, next_img_1, next_img_2. - - Points are interpreted as: - curr_img at x = 0 - next_img_1 at x = 1 - next_img_2 at x = 2 - - We evaluate the quadratic at x = t, where 0 < t < 1. - - Args: - curr_img (_RenderedZoomFrame): The current rendered zoom frame. - next_img_1 (_RenderedZoomFrame): The next rendered zoom frame. - next_img_2 (_RenderedZoomFrame): The next rendered zoom frame after next_img_1. - zoom_per_step (float): The zoom factor per step between frames. - frac (float): The interpolation fraction between 0.0 and 1.0. - - Returns: - pixels.Pixels: Data object representing the interpolated image; NO META is included - - Raises: - Error: on error - - """ - # check params and convert images - if not math.isfinite(zoom_per_step) or zoom_per_step <= 0.0: - raise Error(f'Invalid zoom_per_step: {zoom_per_step}') - if not (0.0 <= frac <= 1.0): - raise Error(f'Invalid interpolation fraction: {frac}') - # align all three samples to the same virtual zoom depth - curr_border: tuple[int, int, int] = BorderFillColor(curr_img.data) - curr_aligned: pixels.Pixels = CenterZoomRGB( - curr_img.data, zoom_per_step**frac, fill_color=curr_border - )[0] - next_aligned_1_raw: pixels.Pixels - next_valid_mask_1: NDArray[np.uint8] | None - next_aligned_1_raw, next_valid_mask_1 = CenterZoomRGB( - next_img_1.data, zoom_per_step ** (frac - 1.0), return_mask=True, fill_color=curr_border - ) - next_aligned_2_raw: pixels.Pixels - next_valid_mask_2: NDArray[np.uint8] | None - next_aligned_2_raw, next_valid_mask_2 = CenterZoomRGB( - next_img_2.data, zoom_per_step ** (frac - 2.0), return_mask=True, fill_color=curr_border - ) - if next_valid_mask_1 is None or next_valid_mask_2 is None: - raise Error('next_valid_mask_1|2 is None, but it should not be; bug! report') - # the future frames will have a black border where the zoomed-out image is outside the - # original image; we create a soft alpha mask to blend the current frame into the next frame - # to avoid harsh transitions - soft_mask_1: NDArray[np.uint8] = FeatherValidMask( - next_valid_mask_1, erode_pixels=_ERODE_LINEAR, blur_pixels=_BLUR_LINEAR - ) - soft_mask_2: NDArray[np.uint8] = FeatherValidMask( - next_valid_mask_2, erode_pixels=_ERODE_QUADRATIC, blur_pixels=_BLUR_QUADRATIC - ) - # blend using Lagrange interpolation - w0: float = ((frac - 1.0) * (frac - 2.0)) / 2.0 - w1: float = -frac * (frac - 2.0) - w2: float = (frac * (frac - 1.0)) / 2.0 - alpha1: NDArray[np.float32] = MaskArray(soft_mask_1) - alpha2: NDArray[np.float32] = MaskArray(soft_mask_2) - # fade future-frame contributions out near their invalid borders; - # important: when future weights are masked away, give the missing weight - # back to curr_aligned: this keeps brightness stable and avoids dark seams - effective_w0: NDArray[np.float32] = w0 + (w1 * (1.0 - alpha1)) + (w2 * (1.0 - alpha2)) # pyright: ignore[reportAssignmentType] - effective_w1: NDArray[np.float32] = w1 * alpha1 - effective_w2: NDArray[np.float32] = w2 * alpha2 - return pixels.Pixels( - data=( - (effective_w0 * curr_aligned.data) - + (effective_w1 * next_aligned_1_raw.data) - + (effective_w2 * next_aligned_2_raw.data) - ), # pyright: ignore[reportArgumentType] - meta={}, - ) - - def InterpolatedFrameStream( - pairs: abc.Iterable[tuple[RenderedZoomFrame, RenderedZoomFrame | None]], + pairs: abc.Iterable[tuple[pixels.RenderedZoomFrame, pixels.RenderedZoomFrame | None]], mutable_hashes: list[str], *, i_frames: int, zoom_per_step: float, use_quadratic: bool = DEFAULT_USE_QUADRATIC, + max_threads: int | None = None, ) -> abc.Iterator[bytes]: """Yield real + interpolated animation frames. @@ -991,13 +657,15 @@ def InterpolatedFrameStream( lookahead in this function. Args: - pairs (RenderedZoomFrame, RenderedZoomFrame | None]]): An iterable of pairs of frames - (curr, next). + pairs (abc.Iterable[tuple[pixels.RenderedZoomFrame, pixels.RenderedZoomFrame | None]]): + An iterable of pairs of frames (curr, next). mutable_hashes (list[str]): A mutable empty list to store mutable hashes for each frame. i_frames (int): The number of interpolated frames to generate between each pair of real frames. zoom_per_step (float): The zoom factor per step between frames. use_quadratic (bool): Whether to use quadratic interpolation (True) or linear interpolation only (False); default is DEFAULT_USE_QUADRATIC + max_threads (int | None): The maximum number of threads to use for parallel interpolation; + if None, the default is to use all available CPU cores that can be used Yields: bytes: The PNG-encoded bytes of each frame (real and interpolated). @@ -1012,55 +680,74 @@ def InterpolatedFrameStream( raise Error(f'Invalid zoom_per_step: {zoom_per_step}') if mutable_hashes: raise Error('mutable_hashes must be an empty list') - # create an iterator over the pairs, get the first one - it: abc.Iterator[tuple[RenderedZoomFrame, RenderedZoomFrame | None]] = iter(pairs) - curr_frame: RenderedZoomFrame - next_frame: RenderedZoomFrame | None + # determine how many workers to use for parallel interpolation + interpolation_workers: int = frame.ConcurrenceToUse( + max(1, i_frames if max_threads is None else min(max_threads, i_frames)) + ) + use_parallelism: bool = i_frames > 0 and interpolation_workers > 1 + # log the start of the render + logging.info(f'Frame interpolation using {interpolation_workers} process(es) for rendering') + # get the first pair from the iterator + curr_frame: pixels.RenderedZoomFrame + next_frame: pixels.RenderedZoomFrame | None + it: abc.Iterator[tuple[pixels.RenderedZoomFrame, pixels.RenderedZoomFrame | None]] = iter(pairs) try: curr_frame, next_frame = next(it) except StopIteration: - # no frames to yield + # no frames to process, just return an empty iterator return - # loop over the pairs, yielding the current frame and interpolated frames until we get the last - next_pending: tuple[RenderedZoomFrame, RenderedZoomFrame | None] | None - while True: - # get the next triple for lookahead - try: - next_pending = next(it) - except StopIteration: - next_pending = None - # always yield the real current frame - mutable_hashes.append(curr_frame.data_hash) - yield curr_frame.data.PNG(copy_previous=False)[0] - # no next real frame means curr is the final real frame - if next_frame is None: - return # done - # for quadratic interpolation of curr_frame -> next_frame, use next2 when available. - next2: RenderedZoomFrame | None = None if next_pending is None else next_pending[1] - for jj in range(i_frames): - frac: float = float(jj + 1) / float(i_frames + 1) - pix: pixels.Pixels = ( - LinearInterpolatedFrame( - curr_frame, - next_frame, - zoom_per_step=zoom_per_step, - frac=frac, + # create (only once) a process pool executor to parallelize the interpolation jobs + pool: futures.ProcessPoolExecutor | None = ( + futures.ProcessPoolExecutor(max_workers=interpolation_workers) if use_parallelism else None + ) + try: + # loop over the pairs, yielding the current frame and interpolated frames until we get the last + while True: + # get the next pair from the iterator, if any + try: + next_pending: tuple[pixels.RenderedZoomFrame, pixels.RenderedZoomFrame | None] | None = ( + next(it) ) - if next2 is None or not use_quadratic - else QuadraticInterpolatedFrame( - curr_frame, - next_frame, - next2, + except StopIteration: + # no more pairs, set next_pending to None + next_pending = None + # yield the current frame and its hash + mutable_hashes.append(curr_frame.data_hash) + yield curr_frame.data.PNG(copy_previous=False)[0] + # if there is no next frame, we are done + if next_frame is None: + return + next2: pixels.RenderedZoomFrame | None = None if next_pending is None else next_pending[1] + # create a list of interpolation jobs for the current segment + jobs: list[pixels.InterpolationJob] = [ + pixels.InterpolationJob( + job_index=jj, + curr_frame=curr_frame, + next_frame=next_frame, + next2_frame=next2, + i_frames=i_frames, zoom_per_step=zoom_per_step, - frac=frac, + use_quadratic=use_quadratic, ) - ) - mutable_hashes.append(pix.data_hash) - yield pix.PNG(copy_previous=False)[0] - # if we have a next triple, advance the frames; otherwise, we are done - if next_pending is None: - return # done - curr_frame, next_frame = next_pending + for jj in range(i_frames) + ] + # PARALLEL or SEQUENTIAL interpolation: for sequential, we just feed the jobs directly to + # the generator expression, and for parallel, we use pool.map to distribute the jobs across + # the worker processes (pool.map preserves input order, which the encoder needs) + for result in ( + pool.map(pixels.InterpolateFrameWorker, jobs, chunksize=1) + if pool + else (pixels.InterpolateFrameWorker(job) for job in jobs) + ): + mutable_hashes.append(result.data_hash) # remember the hash for this interpolated frame + yield result.png + # if there is no next pair, we are done + if next_pending is None: + return + curr_frame, next_frame = next_pending + finally: + if pool: + pool.shutdown() def WriteAnimatedGIF( # noqa: C901 diff --git a/tranz.md b/tranz.md index 47a0e66..c73f5f3 100644 --- a/tranz.md +++ b/tranz.md @@ -643,42 +643,40 @@ Usage: tranz image julia [OPTIONS] [POINT_RE] [POINT_IM] [CENTER_RE] [CENTER_IM] Generate a Julia image. ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────╮ -│ point_re [POINT_RE] Real part of the Julia Set constant; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; ALTERNATIVELY: you can use this to input an │ -│ existing PNG image path, and it will read the Julia Set constant │ -│ from the given image's metadata frame *CENTER* │ -│ (overriding/ignoring the imaginary parameter part!); default is │ -│ '0.27334' │ +│ TEXT Real part of the Julia Set constant; this can be a float (ex: "0.34") │ +│ or a fraction of ints (rational number, ex: "123/451") and the number │ +│ will be fed directly to multi-precision arithmetic so no precision is │ +│ lost; ALTERNATIVELY: you can use this to input an existing PNG image │ +│ path, and it will read the Julia Set constant from the given image's │ +│ metadata frame *CENTER* (overriding/ignoring the imaginary parameter │ +│ part!); default is '0.27334' │ │ │ -│ point_im [POINT_IM] Imaginary part of the Julia Set constant; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '0.00742' │ +│ TEXT Imaginary part of the Julia Set constant; this can be a float (ex: │ +│ "0.34") or a fraction of ints (rational number, ex: "123/451") and the │ +│ number will be fed directly to multi-precision arithmetic so no │ +│ precision is lost; default is '0.00742' │ │ │ -│ center_re [CENTER_RE] Real part of the center point; this can be a float (ex: "0.34") or │ -│ a fraction of ints (rational number, ex: "123/451") and the number │ -│ will be fed directly to multi-precision arithmetic so no precision │ -│ is lost; ALTERNATIVELY: you can use this to input an existing PNG │ -│ image path, and it will read the frame from the given image's │ -│ metadata (overriding/ignoring the other CLI frame parameters!); │ -│ default is '0' │ +│ TEXT Real part of the center point; this can be a float (ex: "0.34") or a │ +│ fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ ALTERNATIVELY: you can use this to input an existing PNG image path, │ +│ and it will read the frame from the given image's metadata │ +│ (overriding/ignoring the other CLI frame parameters!); default is '0' │ │ │ -│ center_im [CENTER_IM] Imaginary part of the center point; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '0' │ +│ TEXT Imaginary part of the center point; this can be a float (ex: "0.34") or │ +│ a fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ default is '0' │ │ │ -│ f_width [F_WIDTH] Width of the frame in the real plane; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '1.8' │ +│ TEXT Width of the frame in the real plane; this can be a float (ex: "0.34") │ +│ or a fraction of ints (rational number, ex: "123/451") and the number │ +│ will be fed directly to multi-precision arithmetic so no precision is │ +│ lost; default is '1.8' │ │ │ -│ f_height [F_HEIGHT] Height of the frame in the imaginary plane; this can be a float │ -│ (ex: "0.34") or a fraction of ints (rational number, ex: │ -│ "123/451") and the number will be fed directly to multi-precision │ -│ arithmetic so no precision is lost; default is '2.2' │ +│ TEXT Height of the frame in the imaginary plane; this can be a float (ex: │ +│ "0.34") or a fraction of ints (rational number, ex: "123/451") and the │ +│ number will be fed directly to multi-precision arithmetic so no │ +│ precision is lost; default is '2.2' │ │ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮ @@ -709,29 +707,28 @@ Usage: tranz image mandel [OPTIONS] [CENTER_RE] [CENTER_IM] [F_WIDTH] [F_HEIGHT] Generate a Mandelbrot image. ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────╮ -│ center_re [CENTER_RE] Real part of the center point; this can be a float (ex: "0.34") or │ -│ a fraction of ints (rational number, ex: "123/451") and the number │ -│ will be fed directly to multi-precision arithmetic so no precision │ -│ is lost; ALTERNATIVELY: you can use this to input an existing PNG │ -│ image path, and it will read the frame from the given image's │ -│ metadata (overriding/ignoring the other CLI frame parameters!); │ -│ default is '-0.75' │ +│ TEXT Real part of the center point; this can be a float (ex: "0.34") or a │ +│ fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ ALTERNATIVELY: you can use this to input an existing PNG image path, │ +│ and it will read the frame from the given image's metadata │ +│ (overriding/ignoring the other CLI frame parameters!); default is │ +│ '-0.75' │ │ │ -│ center_im [CENTER_IM] Imaginary part of the center point; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '0' │ +│ TEXT Imaginary part of the center point; this can be a float (ex: "0.34") or │ +│ a fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ default is '0' │ │ │ -│ f_width [F_WIDTH] Width of the frame in the real plane; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '2.5' │ +│ TEXT Width of the frame in the real plane; this can be a float (ex: "0.34") │ +│ or a fraction of ints (rational number, ex: "123/451") and the number │ +│ will be fed directly to multi-precision arithmetic so no precision is │ +│ lost; default is '2.5' │ │ │ -│ f_height [F_HEIGHT] Height of the frame in the imaginary plane; this can be a float │ -│ (ex: "0.34") or a fraction of ints (rational number, ex: │ -│ "123/451") and the number will be fed directly to multi-precision │ -│ arithmetic so no precision is lost; default is None, i.e, the same │ -│ as width │ +│ TEXT Height of the frame in the imaginary plane; this can be a float (ex: │ +│ "0.34") or a fraction of ints (rational number, ex: "123/451") and the │ +│ number will be fed directly to multi-precision arithmetic so no │ +│ precision is lost; default is None, i.e, the same as width │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮ │ --help Show this message and exit. │ @@ -909,29 +906,28 @@ Usage: tranz zoom ai [OPTIONS] [CENTER_RE] [CENTER_IM] [F_WIDTH] [F_HEIGHT] Use AI to search for an interest point. ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────╮ -│ center_re [CENTER_RE] Real part of the center point; this can be a float (ex: "0.34") or │ -│ a fraction of ints (rational number, ex: "123/451") and the number │ -│ will be fed directly to multi-precision arithmetic so no precision │ -│ is lost; ALTERNATIVELY: you can use this to input an existing PNG │ -│ image path, and it will read the frame from the given image's │ -│ metadata (overriding/ignoring the other CLI frame parameters!); │ -│ default is '-0.75' │ +│ TEXT Real part of the center point; this can be a float (ex: "0.34") or a │ +│ fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ ALTERNATIVELY: you can use this to input an existing PNG image path, │ +│ and it will read the frame from the given image's metadata │ +│ (overriding/ignoring the other CLI frame parameters!); default is │ +│ '-0.75' │ │ │ -│ center_im [CENTER_IM] Imaginary part of the center point; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '0' │ +│ TEXT Imaginary part of the center point; this can be a float (ex: "0.34") or │ +│ a fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ default is '0' │ │ │ -│ f_width [F_WIDTH] Width of the frame in the real plane; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '2.5' │ +│ TEXT Width of the frame in the real plane; this can be a float (ex: "0.34") │ +│ or a fraction of ints (rational number, ex: "123/451") and the number │ +│ will be fed directly to multi-precision arithmetic so no precision is │ +│ lost; default is '2.5' │ │ │ -│ f_height [F_HEIGHT] Height of the frame in the imaginary plane; this can be a float │ -│ (ex: "0.34") or a fraction of ints (rational number, ex: │ -│ "123/451") and the number will be fed directly to multi-precision │ -│ arithmetic so no precision is lost; default is None, i.e, the same │ -│ as width │ +│ TEXT Height of the frame in the imaginary plane; this can be a float (ex: │ +│ "0.34") or a fraction of ints (rational number, ex: "123/451") and the │ +│ number will be fed directly to multi-precision arithmetic so no │ +│ precision is lost; default is None, i.e, the same as width │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮ │ --query -q TEXT Query to be added to the default prompt; │ @@ -978,49 +974,39 @@ Usage: tranz zoom auto [OPTIONS] [CENTER_RE] [CENTER_IM] [F_WIDTH] [F_HEIGHT] Create a GIF/MP4 zoom fractal animation. ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────╮ -│ center_re [CENTER_RE] Real part of the center point; this can be │ -│ a float (ex: "0.34") or a fraction of ints │ -│ (rational number, ex: "123/451") and the │ -│ number will be fed directly to │ -│ multi-precision arithmetic so no precision │ -│ is lost; ALTERNATIVELY: you can use this │ -│ to input an existing PNG image path, and │ -│ it will read the frame from the given │ -│ image's metadata (overriding/ignoring the │ -│ other CLI frame parameters!); default is │ -│ '-0.75' │ +│ TEXT Real part of the center point; this can be a float (ex: │ +│ "0.34") or a fraction of ints (rational number, ex: │ +│ "123/451") and the number will be fed directly to │ +│ multi-precision arithmetic so no precision is lost; │ +│ ALTERNATIVELY: you can use this to input an existing PNG │ +│ image path, and it will read the frame from the given │ +│ image's metadata (overriding/ignoring the other CLI frame │ +│ parameters!); default is '-0.75' │ │ │ -│ center_im [CENTER_IM] Imaginary part of the center point; this │ -│ can be a float (ex: "0.34") or a fraction │ -│ of ints (rational number, ex: "123/451") │ -│ and the number will be fed directly to │ -│ multi-precision arithmetic so no precision │ -│ is lost; default is '0' │ +│ TEXT Imaginary part of the center point; this can be a float │ +│ (ex: "0.34") or a fraction of ints (rational number, ex: │ +│ "123/451") and the number will be fed directly to │ +│ multi-precision arithmetic so no precision is lost; default │ +│ is '0' │ │ │ -│ f_width [F_WIDTH] Width of the frame in the real plane; this │ -│ can be a float (ex: "0.34") or a fraction │ -│ of ints (rational number, ex: "123/451") │ -│ and the number will be fed directly to │ -│ multi-precision arithmetic so no precision │ -│ is lost; default is '2.5' │ +│ TEXT Width of the frame in the real plane; this can be a float │ +│ (ex: "0.34") or a fraction of ints (rational number, ex: │ +│ "123/451") and the number will be fed directly to │ +│ multi-precision arithmetic so no precision is lost; default │ +│ is '2.5' │ │ │ -│ f_height [F_HEIGHT] Height of the frame in the imaginary │ -│ plane; this can be a float (ex: "0.34") or │ -│ a fraction of ints (rational number, ex: │ -│ "123/451") and the number will be fed │ -│ directly to multi-precision arithmetic so │ -│ no precision is lost; default is None, │ -│ i.e, the same as width │ -│ dest_magnification_10 [DEST_MAGNIFICATION_10] Magnification magnitude to go through in │ -│ the animation zoom; this can be a float │ -│ (ex: "0.34") or a fraction of ints │ -│ (rational number, ex: "123/451") and the │ -│ number will be fed directly to │ -│ multi-precision arithmetic so no precision │ -│ is lost; -10000.0 ≤ mag ≤ 10000.0; │ -│ ATTENTION!! this is exponential 10**mag, │ -│ so a value of 2.0 means 10**2 = 100x zoom; │ -│ default is 1, i.e., 10.00x zoom │ +│ TEXT Height of the frame in the imaginary plane; this can be a │ +│ float (ex: "0.34") or a fraction of ints (rational number, │ +│ ex: "123/451") and the number will be fed directly to │ +│ multi-precision arithmetic so no precision is lost; default │ +│ is None, i.e, the same as width │ +│ TEXT Magnification magnitude to go through in the animation │ +│ zoom; this can be a float (ex: "0.34") or a fraction of │ +│ ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no │ +│ precision is lost; -10000.0 ≤ mag ≤ 10000.0; ATTENTION!! │ +│ this is exponential 10**mag, so a value of 2.0 means 10**2 │ +│ = 100x zoom; default is 1, i.e., 10.00x zoom │ │ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮ @@ -1110,29 +1096,28 @@ Usage: tranz zoom manual [OPTIONS] [CENTER_RE] [CENTER_IM] [F_WIDTH] [F_HEIGHT] Manually navigate a Mandelbrot zoom search (no AI). ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────╮ -│ center_re [CENTER_RE] Real part of the center point; this can be a float (ex: "0.34") or │ -│ a fraction of ints (rational number, ex: "123/451") and the number │ -│ will be fed directly to multi-precision arithmetic so no precision │ -│ is lost; ALTERNATIVELY: you can use this to input an existing PNG │ -│ image path, and it will read the frame from the given image's │ -│ metadata (overriding/ignoring the other CLI frame parameters!); │ -│ default is '-0.75' │ +│ TEXT Real part of the center point; this can be a float (ex: "0.34") or a │ +│ fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ ALTERNATIVELY: you can use this to input an existing PNG image path, │ +│ and it will read the frame from the given image's metadata │ +│ (overriding/ignoring the other CLI frame parameters!); default is │ +│ '-0.75' │ │ │ -│ center_im [CENTER_IM] Imaginary part of the center point; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '0' │ +│ TEXT Imaginary part of the center point; this can be a float (ex: "0.34") or │ +│ a fraction of ints (rational number, ex: "123/451") and the number will │ +│ be fed directly to multi-precision arithmetic so no precision is lost; │ +│ default is '0' │ │ │ -│ f_width [F_WIDTH] Width of the frame in the real plane; this can be a float (ex: │ -│ "0.34") or a fraction of ints (rational number, ex: "123/451") and │ -│ the number will be fed directly to multi-precision arithmetic so │ -│ no precision is lost; default is '2.5' │ +│ TEXT Width of the frame in the real plane; this can be a float (ex: "0.34") │ +│ or a fraction of ints (rational number, ex: "123/451") and the number │ +│ will be fed directly to multi-precision arithmetic so no precision is │ +│ lost; default is '2.5' │ │ │ -│ f_height [F_HEIGHT] Height of the frame in the imaginary plane; this can be a float │ -│ (ex: "0.34") or a fraction of ints (rational number, ex: │ -│ "123/451") and the number will be fed directly to multi-precision │ -│ arithmetic so no precision is lost; default is None, i.e, the same │ -│ as width │ +│ TEXT Height of the frame in the imaginary plane; this can be a float (ex: │ +│ "0.34") or a fraction of ints (rational number, ex: "123/451") and the │ +│ number will be fed directly to multi-precision arithmetic so no │ +│ precision is lost; default is None, i.e, the same as width │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮ │ --help Show this message and exit. │