From 62f1a95029523802cb3ccb6f235443e611d9fa2b Mon Sep 17 00:00:00 2001 From: Alessio Giuliano <112626492+alessio-giuliano-pix4d@users.noreply.github.com> Date: Wed, 22 May 2024 12:38:14 +0200 Subject: [PATCH] pyopf 1.2.0 (#9) Co-authored-by: pix4d_concourse_developers --- CHANGELOG.md | 19 +- README.md | 59 +- poetry.lock | 1518 ++++++++++++----- pyproject.toml | 78 +- src/opf_tools/merge/merger.py | 876 ---------- src/opf_tools/opf2colmap/__main__.py | 6 + src/opf_tools/opf2colmap/converter.py | 433 +++++ src/opf_tools/{merge => opf2las}/__main__.py | 2 +- src/opf_tools/opf2las/converter.py | 130 ++ src/opf_tools/opf2ply/__main__.py | 6 + src/opf_tools/opf2ply/converter.py | 108 ++ src/pyopf/VersionInfo.py | 11 + src/pyopf/cameras/calibrated_cameras.py | 26 +- src/pyopf/cameras/camera_list.py | 11 +- src/pyopf/cameras/gps_bias.py | 16 +- src/pyopf/cameras/input_cameras.py | 66 +- src/pyopf/cameras/input_rig_relatives.py | 12 +- src/pyopf/cameras/projected_input_cameras.py | 27 +- src/pyopf/cameras/sensor_internals.py | 26 +- src/pyopf/cps/calibrated_control_points.py | 6 +- src/pyopf/cps/constraints.py | 25 +- src/pyopf/cps/input_control_points.py | 24 +- src/pyopf/cps/projected_control_points.py | 8 +- src/pyopf/crs/crs.py | 15 +- src/pyopf/crs/geolocation.py | 6 +- src/pyopf/crs/scene_reference_frame.py | 27 +- src/pyopf/ext/__init__.py | 32 + ...ix4d_calibrated_intersection_tie_points.py | 52 + src/pyopf/ext/pix4d_input_depth_map.py | 19 +- .../pix4d_input_intersection_tie_points.py | 193 +++ src/pyopf/ext/pix4d_planes.py | 29 +- src/pyopf/ext/pix4d_polygonal_mesh.py | 289 ++++ src/pyopf/ext/pix4d_region_of_interest.py | 6 +- src/pyopf/ext/plane.py | 10 +- src/pyopf/io/__init__.py | 2 +- src/pyopf/io/loaders.py | 81 +- src/pyopf/io/savers.py | 3 +- src/pyopf/items.py | 17 +- src/pyopf/pointcloud/merge.py | 13 +- src/pyopf/pointcloud/pcl.py | 63 +- src/pyopf/pointcloud/utils.py | 35 +- src/pyopf/project/project.py | 32 +- src/pyopf/resolve/resolver.py | 18 +- src/pyopf/uid64.py | 6 + src/pyopf/versions.py | 15 + 45 files changed, 2801 insertions(+), 1655 deletions(-) delete mode 100644 src/opf_tools/merge/merger.py create mode 100644 src/opf_tools/opf2colmap/__main__.py create mode 100644 src/opf_tools/opf2colmap/converter.py rename src/opf_tools/{merge => opf2las}/__main__.py (57%) create mode 100644 src/opf_tools/opf2las/converter.py create mode 100644 src/opf_tools/opf2ply/__main__.py create mode 100644 src/opf_tools/opf2ply/converter.py create mode 100644 src/pyopf/ext/pix4d_calibrated_intersection_tie_points.py create mode 100644 src/pyopf/ext/pix4d_input_intersection_tie_points.py create mode 100644 src/pyopf/ext/pix4d_polygonal_mesh.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 53618a6..5003c20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## [Unreleased] +## 1.2.0 + ### Added + +- transformation_matrix property to BaseToTranslatedCanonicalCrsTransform +- OPF pointcloud to COLMAP converter +- OPF pointcloud to PLY converter +- OPF pointcloud to LAS converter +- Support for the Pix4D polygonal mesh extension +- Support for the Pix4D input and calibrated ITPs extension + ### Changed + +- Raise a KeyError exception if a required attribute is missing +- Make pyopf.io.load accept paths as strings or os.PathLike objects +- Fixed handling of pathlib.Path in pyopf.io.save +- Move to poetry as package manager + ### Removed +- OPF projects merging tool + ## 1.1.1 ### Added diff --git a/README.md b/README.md index cc9c481..f992c1c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ from pyopf.resolve import resolve from pyopf.uid64 import Uid64 # Path to the example project file. -project_path = "spec/examples/project.json" +project_path = "spec/examples/project.opf" # We are going to search for the calibrated position of the camera with this ID camera_id = Uid64(hex = "0x57282923") @@ -82,32 +82,6 @@ pcl.write(Path('out/out.gltf')) We provide a few tools as command line scripts to help manipulate OPF projects in different ways. -#### Merging - -The main use case for merging projects is to be able to process smaller sections of a project independently. -For the merging to succeed the sub projects must be in the same coordinate reference system. Note that the tool doesn't support merging the content of most OPF extensions, which will then be dropped in the merged project. -Two objects are considered identical if they have the same ID even if they are in different projects. If this assumption is violated, the merging fails. For example, the same camera ID cannot be associated with two different image URIs. -The only exception are the sensors, whose IDs are always regenerated and for which no attempt is made at finding common and equally calibrated sensors. - -The point clouds are merged based on their label. - -Only core project items support merging: -* camera list -* input cameras -* projected input cameras -* input control points -* projected control points -* calibration (calibrated cameras, calibrated control points, tracks) -* point clouds -* constraints - -All extensions are dropped. - -The merging tool can be called using - -`opf_merge project_1.opf project_2.opf project_3.opf output_directory` - - #### Undistorting A tool to undistort images is provided. The undistorted images will be stored in their original location, but in an `undistort` directory. Only images taken with a perspective camera, for which the sensor has been calibrated will be undistorted. @@ -137,6 +111,21 @@ The cropping tool can be called using `opf_crop project_to_crop.opf output_directory` +#### Convert to COLMAP model + +A tool to convert an OPF project to a COLMAP sparse model. COLMAP sparse models consist of three files `cameras.txt`, `images.txt`, and `points3D.txt`: +* `cameras.txt` contains information about the sensors, such as intrinsic parameters and distortion. +* `images.txt` contains information about the cameras, such as extrinsic parameters and the corresponding image filename. +* `points3D.txt` contains information about the tracks, such as their position and color. + +The tool can also be used to copy the images to a new directory, by specifying the `--out-img-dir` parameter. If specified, the tree structure of where input images are stored will be copied to the output image directory. In other words, if all images are stored in the same directory, the folder specified by `--out-img-dir` will only contain the images. If images are stored in different folders/subfolders, the `--out-img-dir` folder will contain the same folders/subfolders starting from the first common folder. + +Only calibrated projects with only perspective cameras are supported. Remote files are not supported. + +The conversion can be done by calling + +`opf2colmap project.opf` + #### Convert to NeRF This tool converts OPF projects to NeRF. NeRF consists of transforms file(s), which contain information about distortion, intrinsic and extrinsinc parameters of cameras. Usually it is split in `transforms_train.json` and `transforms_test.json` files, but can sometimes also have only the train one. The split can be controlled with the parameter `--train-frac`, for example `--train-frac 0.7` will randomly assign 70% of images for training, and the remaining 30% for testing. If this parameter is unspecified or set to 1.0, only the `transforms_train.json` will be generated. Sometimes an additional `transforms_val.json` is required. It is to evaluate from new points of view, but the generation of new point of views is not managed by this tool, so it can just be a copy of `transforms_test.json` renamed. @@ -145,7 +134,7 @@ The tool can also convert input images to other image formats using `--out-img-f When `--out-img-dir` is used, the tree structure of where input images are stored will be copied to the output image directory. In other words, if all images are stored in the same directory, the folder specified by `--out-img-dir` will only contain the images. If images are stored in different folders/subfolders, the `--out-img-dir` folder will contain the same folders/subfolders starting from the first common folder. -Only calibrated projects with only perspective cameras are supported. Remote files are not supported. +Only calibrated projects with perspective cameras are supported. ##### Examples @@ -157,6 +146,20 @@ DirectVoxGo only works with PNG image files, and contrary to Instant-NeRF it doe `opf2nerf project.opf --out-img-format png --out-img-dir ./images --no-camera-flip` +#### Convert to LAS + +A tool converting an OPF project's point clouds to LAS. One output for each dense and sparse point cloud will be produced. +It can be used as follows: + +`opf2las path_to/project.opf --out-dir your_output_dir` + +#### Convert to PLY + +A tool converting an OPF project's point clouds to PLY. One output for each dense and sparse point cloud will be produced. +It can be used as follows: + +`opf2ply path_to/project.opf --out-dir your_output_dir` + ## License and citation If you use this work in your research or projects, we kindly request that you cite it as follows: diff --git a/poetry.lock b/poetry.lock index 8e8a9cb..f93490a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,22 +1,31 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] [[package]] name = "cfgv" -version = "3.3.1" +version = "3.4.0" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.8" files = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -24,16 +33,93 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "contourpy" +version = "1.2.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = true +python-versions = ">=3.9" +files = [ + {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, + {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, + {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, + {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, + {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, + {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, + {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, + {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, + {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, + {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, +] + +[package.dependencies] +numpy = ">=1.20,<2.0" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] + +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = true +python-versions = ">=3.8" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "dataclasses-json" -version = "0.5.8" +version = "0.5.9" description = "Easily serialize dataclasses to and from JSON" -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "dataclasses-json-0.5.8.tar.gz", hash = "sha256:6572ac08ad9340abcb74fd8c4c8e9752db2a182a402c8e871d0a8aa119e3804e"}, - {file = "dataclasses_json-0.5.8-py3-none-any.whl", hash = "sha256:65b167c15fdf9bde27569c09ac18dd39bf1cc5b7998525024cb4678d2653946c"}, + {file = "dataclasses-json-0.5.9.tar.gz", hash = "sha256:e9ac87b73edc0141aafbce02b44e93553c3123ad574958f0fe52a534b6707e8e"}, + {file = "dataclasses_json-0.5.9-py3-none-any.whl", hash = "sha256:1280542631df1c375b7bc92e5b86d39e06c44760d7e3571a537b3b8acabf2f0c"}, ] [package.dependencies] @@ -42,13 +128,12 @@ marshmallow-enum = ">=1.5.1,<2.0.0" typing-inspect = ">=0.4.0" [package.extras] -dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=7.2.0)", "simplejson", "types-dataclasses"] +dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=7.2.0)", "setuptools", "simplejson", "twine", "types-dataclasses", "wheel"] [[package]] name = "deprecated" version = "1.2.14" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -64,26 +149,24 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "distlib" -version = "0.3.6" +version = "0.3.8" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] [[package]] name = "exceptiongroup" -version = "1.1.1" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, - {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -91,40 +174,135 @@ test = ["pytest (>=6)"] [[package]] name = "filelock" -version = "3.12.2" +version = "3.13.1" description = "A platform independent file lock." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + +[[package]] +name = "fonttools" +version = "4.47.0" +description = "Tools to manipulate font files" +optional = true +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d2404107626f97a221dc1a65b05396d2bb2ce38e435f64f26ed2369f68675d9"}, + {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01f409be619a9a0f5590389e37ccb58b47264939f0e8d58bfa1f3ba07d22671"}, + {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d986b66ff722ef675b7ee22fbe5947a41f60a61a4da15579d5e276d897fbc7fa"}, + {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8acf6dd0434b211b3bd30d572d9e019831aae17a54016629fa8224783b22df8"}, + {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:495369c660e0c27233e3c572269cbe520f7f4978be675f990f4005937337d391"}, + {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c59227d7ba5b232281c26ae04fac2c73a79ad0e236bca5c44aae904a18f14faf"}, + {file = "fonttools-4.47.0-cp310-cp310-win32.whl", hash = "sha256:59a6c8b71a245800e923cb684a2dc0eac19c56493e2f896218fcf2571ed28984"}, + {file = "fonttools-4.47.0-cp310-cp310-win_amd64.whl", hash = "sha256:52c82df66201f3a90db438d9d7b337c7c98139de598d0728fb99dab9fd0495ca"}, + {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:854421e328d47d70aa5abceacbe8eef231961b162c71cbe7ff3f47e235e2e5c5"}, + {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:511482df31cfea9f697930f61520f6541185fa5eeba2fa760fe72e8eee5af88b"}, + {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0e2c88c8c985b7b9a7efcd06511fb0a1fe3ddd9a6cd2895ef1dbf9059719d7"}, + {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7a0a8848726956e9d9fb18c977a279013daadf0cbb6725d2015a6dd57527992"}, + {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e869da810ae35afb3019baa0d0306cdbab4760a54909c89ad8904fa629991812"}, + {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dd23848f877c3754f53a4903fb7a593ed100924f9b4bff7d5a4e2e8a7001ae11"}, + {file = "fonttools-4.47.0-cp311-cp311-win32.whl", hash = "sha256:bf1810635c00f7c45d93085611c995fc130009cec5abdc35b327156aa191f982"}, + {file = "fonttools-4.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:61df4dee5d38ab65b26da8efd62d859a1eef7a34dcbc331299a28e24d04c59a7"}, + {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e3f4d61f3a8195eac784f1d0c16c0a3105382c1b9a74d99ac4ba421da39a8826"}, + {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:174995f7b057e799355b393e97f4f93ef1f2197cbfa945e988d49b2a09ecbce8"}, + {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea592e6a09b71cb7a7661dd93ac0b877a6228e2d677ebacbad0a4d118494c86d"}, + {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40bdbe90b33897d9cc4a39f8e415b0fcdeae4c40a99374b8a4982f127ff5c767"}, + {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:843509ae9b93db5aaf1a6302085e30bddc1111d31e11d724584818f5b698f500"}, + {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9acfa1cdc479e0dde528b61423855913d949a7f7fe09e276228298fef4589540"}, + {file = "fonttools-4.47.0-cp312-cp312-win32.whl", hash = "sha256:66c92ec7f95fd9732550ebedefcd190a8d81beaa97e89d523a0d17198a8bda4d"}, + {file = "fonttools-4.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8fa20748de55d0021f83754b371432dca0439e02847962fc4c42a0e444c2d78"}, + {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c75e19971209fbbce891ebfd1b10c37320a5a28e8d438861c21d35305aedb81c"}, + {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e79f1a3970d25f692bbb8c8c2637e621a66c0d60c109ab48d4a160f50856deff"}, + {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:562681188c62c024fe2c611b32e08b8de2afa00c0c4e72bed47c47c318e16d5c"}, + {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a77a60315c33393b2bd29d538d1ef026060a63d3a49a9233b779261bad9c3f71"}, + {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4fabb8cc9422efae1a925160083fdcbab8fdc96a8483441eb7457235df625bd"}, + {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a78dba8c2a1e9d53a0fb5382979f024200dc86adc46a56cbb668a2249862fda"}, + {file = "fonttools-4.47.0-cp38-cp38-win32.whl", hash = "sha256:e6b968543fde4119231c12c2a953dcf83349590ca631ba8216a8edf9cd4d36a9"}, + {file = "fonttools-4.47.0-cp38-cp38-win_amd64.whl", hash = "sha256:4a9a51745c0439516d947480d4d884fa18bd1458e05b829e482b9269afa655bc"}, + {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62d8ddb058b8e87018e5dc26f3258e2c30daad4c87262dfeb0e2617dd84750e6"}, + {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dde0eab40faaa5476133123f6a622a1cc3ac9b7af45d65690870620323308b4"}, + {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4da089f6dfdb822293bde576916492cd708c37c2501c3651adde39804630538"}, + {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:253bb46bab970e8aae254cebf2ae3db98a4ef6bd034707aa68a239027d2b198d"}, + {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1193fb090061efa2f9e2d8d743ae9850c77b66746a3b32792324cdce65784154"}, + {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:084511482dd265bce6dca24c509894062f0117e4e6869384d853f46c0e6d43be"}, + {file = "fonttools-4.47.0-cp39-cp39-win32.whl", hash = "sha256:97620c4af36e4c849e52661492e31dc36916df12571cb900d16960ab8e92a980"}, + {file = "fonttools-4.47.0-cp39-cp39-win_amd64.whl", hash = "sha256:e77bdf52185bdaf63d39f3e1ac3212e6cfa3ab07d509b94557a8902ce9c13c82"}, + {file = "fonttools-4.47.0-py3-none-any.whl", hash = "sha256:d6477ba902dd2d7adda7f0fd3bfaeb92885d45993c9e1928c9f28fc3961415f7"}, + {file = "fonttools-4.47.0.tar.gz", hash = "sha256:ec13a10715eef0e031858c1c23bfaee6cba02b97558e4a7bfa089dba4a8c2ebf"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "pycairo", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.1.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "identify" -version = "2.5.24" +version = "2.5.33" description = "File identification library for Python" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, - {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, + {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, + {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, ] [package.extras] license = ["ukkonen"] +[[package]] +name = "imageio" +version = "2.33.1" +description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." +optional = true +python-versions = ">=3.8" +files = [ + {file = "imageio-2.33.1-py3-none-any.whl", hash = "sha256:c5094c48ccf6b2e6da8b4061cd95e1209380afafcbeae4a4e280938cce227e1d"}, + {file = "imageio-2.33.1.tar.gz", hash = "sha256:78722d40b137bd98f5ec7312119f8aea9ad2049f76f434748eb306b6937cc1ce"}, +] + +[package.dependencies] +numpy = "*" +pillow = ">=8.3.2" + +[package.extras] +all-plugins = ["astropy", "av", "imageio-ffmpeg", "pillow-heif", "psutil", "tifffile"] +all-plugins-pypy = ["av", "imageio-ffmpeg", "pillow-heif", "psutil", "tifffile"] +build = ["wheel"] +dev = ["black", "flake8", "fsspec[github]", "pytest", "pytest-cov"] +docs = ["numpydoc", "pydata-sphinx-theme", "sphinx (<6)"] +ffmpeg = ["imageio-ffmpeg", "psutil"] +fits = ["astropy"] +full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "itk", "numpydoc", "pillow-heif", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx (<6)", "tifffile", "wheel"] +gdal = ["gdal"] +itk = ["itk"] +linting = ["black", "flake8"] +pillow-heif = ["pillow-heif"] +pyav = ["av"] +test = ["fsspec[github]", "pytest", "pytest-cov"] +tifffile = ["tifffile"] + [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -132,32 +310,178 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "kiwisolver" +version = "1.4.5" +description = "A fast implementation of the Cassowary constraint solver" +optional = true +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] + +[[package]] +name = "laspy" +version = "2.4.1" +description = "Native Python ASPRS LAS read/write library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "laspy-2.4.1.tar.gz", hash = "sha256:13caecc7325cb2242cb25394984d21b3b5f796c88bcb44bc2ed2d3cf1b972ac4"}, +] + +[package.dependencies] +numpy = "*" + +[package.extras] +dev = ["black (==22.3.0)", "coverage", "m2r2", "nox", "pytest", "pytest-benchmark", "rangehttpserver", "sphinx", "sphinx-rtd-theme"] +laszip = ["laszip (>=0.2.1,<0.3.0)"] +lazrs = ["lazrs (>=0.5.0,<0.6.0)"] +pyproj = ["pyproj"] +requests = ["requests"] + +[[package]] +name = "lazy-loader" +version = "0.3" +description = "lazy_loader" +optional = true +python-versions = ">=3.7" +files = [ + {file = "lazy_loader-0.3-py3-none-any.whl", hash = "sha256:1e9e76ee8631e264c62ce10006718e80b2cfc74340d17d1031e0f84af7478554"}, + {file = "lazy_loader-0.3.tar.gz", hash = "sha256:3b68898e34f5b2a29daaaac172c6555512d0f32074f147e2254e4a6d9d838f37"}, +] + +[package.extras] +lint = ["pre-commit (>=3.3)"] +test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"] + [[package]] name = "marshmallow" -version = "3.19.0" +version = "3.20.2" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"}, - {file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"}, + {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, + {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"] +dev = ["pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["pre-commit (>=2.4,<4.0)"] tests = ["pytest", "pytz", "simplejson"] [[package]] name = "marshmallow-enum" version = "1.5.1" description = "Enum field for Marshmallow" -category = "main" optional = false python-versions = "*" files = [ @@ -168,11 +492,58 @@ files = [ [package.dependencies] marshmallow = ">=2.0.0" +[[package]] +name = "matplotlib" +version = "3.8.2" +description = "Python plotting package" +optional = true +python-versions = ">=3.9" +files = [ + {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, + {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, + {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, + {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, + {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, + {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, + {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, + {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, + {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, + {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, + {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.3.1" +numpy = ">=1.21,<2" +packaging = ">=20.0" +pillow = ">=8" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" + [[package]] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -180,11 +551,28 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "networkx" +version = "3.2.1" +description = "Python package for creating and manipulating graphs and networks" +optional = true +python-versions = ">=3.9" +files = [ + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, +] + +[package.extras] +default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -197,173 +585,198 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.25.0" +version = "1.26.3" description = "Fundamental package for array computing in Python" -category = "main" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8aa130c3042052d656751df5e81f6d61edff3e289b5994edcf77f54118a8d9f4"}, - {file = "numpy-1.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e3f2b96e3b63c978bc29daaa3700c028fe3f049ea3031b58aa33fe2a5809d24"}, - {file = "numpy-1.25.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6b267f349a99d3908b56645eebf340cb58f01bd1e773b4eea1a905b3f0e4208"}, - {file = "numpy-1.25.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aedd08f15d3045a4e9c648f1e04daca2ab1044256959f1f95aafeeb3d794c16"}, - {file = "numpy-1.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d183b5c58513f74225c376643234c369468e02947b47942eacbb23c1671f25d"}, - {file = "numpy-1.25.0-cp310-cp310-win32.whl", hash = "sha256:d76a84998c51b8b68b40448ddd02bd1081bb33abcdc28beee6cd284fe11036c6"}, - {file = "numpy-1.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0dc071017bc00abb7d7201bac06fa80333c6314477b3d10b52b58fa6a6e38f6"}, - {file = "numpy-1.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c69fe5f05eea336b7a740e114dec995e2f927003c30702d896892403df6dbf0"}, - {file = "numpy-1.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c7211d7920b97aeca7b3773a6783492b5b93baba39e7c36054f6e749fc7490c"}, - {file = "numpy-1.25.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecc68f11404930e9c7ecfc937aa423e1e50158317bf67ca91736a9864eae0232"}, - {file = "numpy-1.25.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e559c6afbca484072a98a51b6fa466aae785cfe89b69e8b856c3191bc8872a82"}, - {file = "numpy-1.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6c284907e37f5e04d2412950960894b143a648dea3f79290757eb878b91acbd1"}, - {file = "numpy-1.25.0-cp311-cp311-win32.whl", hash = "sha256:95367ccd88c07af21b379be1725b5322362bb83679d36691f124a16357390153"}, - {file = "numpy-1.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:b76aa836a952059d70a2788a2d98cb2a533ccd46222558b6970348939e55fc24"}, - {file = "numpy-1.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b792164e539d99d93e4e5e09ae10f8cbe5466de7d759fc155e075237e0c274e4"}, - {file = "numpy-1.25.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7cd981ccc0afe49b9883f14761bb57c964df71124dcd155b0cba2b591f0d64b9"}, - {file = "numpy-1.25.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa48bebfb41f93043a796128854b84407d4df730d3fb6e5dc36402f5cd594c0"}, - {file = "numpy-1.25.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5177310ac2e63d6603f659fadc1e7bab33dd5a8db4e0596df34214eeab0fee3b"}, - {file = "numpy-1.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0ac6edfb35d2a99aaf102b509c8e9319c499ebd4978df4971b94419a116d0790"}, - {file = "numpy-1.25.0-cp39-cp39-win32.whl", hash = "sha256:7412125b4f18aeddca2ecd7219ea2d2708f697943e6f624be41aa5f8a9852cc4"}, - {file = "numpy-1.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:26815c6c8498dc49d81faa76d61078c4f9f0859ce7817919021b9eba72b425e3"}, - {file = "numpy-1.25.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b1b90860bf7d8a8c313b372d4f27343a54f415b20fb69dd601b7efe1029c91e"}, - {file = "numpy-1.25.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85cdae87d8c136fd4da4dad1e48064d700f63e923d5af6c8c782ac0df8044542"}, - {file = "numpy-1.25.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cc3fda2b36482891db1060f00f881c77f9423eead4c3579629940a3e12095fe8"}, - {file = "numpy-1.25.0.tar.gz", hash = "sha256:f1accae9a28dc3cda46a91de86acf69de0d1b5f4edd44a9b0c3ceb8036dfff19"}, + {file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"}, + {file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"}, + {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"}, + {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"}, + {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"}, + {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"}, + {file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"}, + {file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"}, + {file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"}, + {file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"}, + {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"}, + {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"}, + {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"}, + {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"}, + {file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"}, + {file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"}, + {file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"}, + {file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"}, + {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"}, + {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"}, + {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"}, + {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"}, + {file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"}, + {file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"}, + {file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"}, + {file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"}, + {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"}, + {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"}, + {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"}, + {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"}, + {file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"}, + {file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"}, + {file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"}, ] [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] name = "pillow" -version = "9.5.0" +version = "10.2.0" description = "Python Imaging Library (Fork)" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"}, - {file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"}, - {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"}, - {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"}, - {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"}, - {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"}, - {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"}, - {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"}, - {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"}, - {file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"}, - {file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"}, - {file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"}, - {file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"}, - {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"}, - {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"}, - {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"}, - {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"}, - {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"}, - {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"}, - {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"}, - {file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"}, - {file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"}, - {file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"}, - {file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"}, - {file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"}, - {file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"}, - {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"}, - {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"}, - {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"}, - {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"}, - {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"}, - {file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"}, - {file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"}, - {file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"}, - {file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"}, - {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"}, - {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"}, - {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"}, - {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"}, - {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"}, - {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"}, - {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"}, - {file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"}, - {file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"}, - {file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"}, - {file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"}, - {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"}, - {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"}, - {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"}, - {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"}, - {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"}, - {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"}, - {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"}, - {file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"}, - {file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"}, - {file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"}, - {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"}, - {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"}, - {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"}, - {file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"}, - {file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"}, - {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"}, - {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"}, - {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"}, - {file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"}, - {file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, + {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, + {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, + {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, + {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, + {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, + {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, + {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, + {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, + {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, + {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, + {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, + {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, + {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, + {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, + {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, + {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, ] [package.extras] docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "3.8.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"}, - {file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" -version = "1.2.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "plyfile" +version = "0.9" +description = "PLY file reader/writer" +optional = false +python-versions = ">=3.7" +files = [ + {file = "plyfile-0.9-py3-none-any.whl", hash = "sha256:5f5bb9396c3c22f055677b5d0c7224271b81d8acd227c85d3357aa821fad2060"}, + {file = "plyfile-0.9.tar.gz", hash = "sha256:42b24775c61fb294f9cc93b8fb1987dd03cdb65a041b41549289b7a8005417a4"}, +] + +[package.dependencies] +numpy = ">=1.17" + [[package]] name = "pre-commit" -version = "3.3.3" +version = "3.6.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"}, - {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"}, + {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, + {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, ] [package.dependencies] @@ -373,31 +786,113 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "pycocotools" +version = "2.0.7" +description = "Official APIs for the MS-COCO dataset" +optional = true +python-versions = ">=3.5" +files = [ + {file = "pycocotools-2.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a6683a002fcb4500edbcec94bdf48be69f578a9aa5c638db38614df1f45cc935"}, + {file = "pycocotools-2.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d517ec315e53ef8df9f6b0899ebc4c79bd61fd715383861949bb1c3fca2c6d5"}, + {file = "pycocotools-2.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eb5d46900375adaba88eedb5cbc29d8cbcf43e82505d67378df1c3b720a8c5f"}, + {file = "pycocotools-2.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:363a6be808125306ace1a163c0b9ba479ee08eceec1fbd3889a88bd8245f73dc"}, + {file = "pycocotools-2.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:623b941bbafecbfee574aedbf3cb257f7a879f4fdb79394e6d3fb9c76e7ad6cf"}, + {file = "pycocotools-2.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ac4f30bac1503c780072053e6922971392fa3628b2e6967192bfca1f14736e2"}, + {file = "pycocotools-2.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121017ca87e2eec4e9081636d1a79519b50f473959defc5671c2d1ce0eec482e"}, + {file = "pycocotools-2.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:4a8ec6f439638120e11f49120e1ddb6c66e0b1f293d7884207d02703a73d25a1"}, + {file = "pycocotools-2.0.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1a675728e459d72be6e3bb3546672bb37c7daffdc2e5335aa7b834aece2b560"}, + {file = "pycocotools-2.0.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6541340f26bae32e044eedc5d8ccdac5bd0cb64eb2b0a342dac859b696edd0aa"}, + {file = "pycocotools-2.0.7-cp37-cp37m-win_amd64.whl", hash = "sha256:8def3c46349e919999d6d5a1d6b7e587e6891524cc28f8b4a11e463bf0914621"}, + {file = "pycocotools-2.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6469089b9b36a1f645dc9ee830f29d261e99b4b3be73cb260688fd8b6d02760c"}, + {file = "pycocotools-2.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dbc429018149dc34e206ea32ee6297ff30b55a8615a3f7f4c6e3842f9df73db"}, + {file = "pycocotools-2.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66864bec8b30d47faa946bb55c8e8d6b7acb9fba0c17ff6aaa37abd78cda962a"}, + {file = "pycocotools-2.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:625388f52e543f6f798f75f1ec125fe519580f22e72ccbd75eee0355ce336e18"}, + {file = "pycocotools-2.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:73dc251ae4a06b7c10747ca7e2d29faabb4f13e5fc43760945966845581e79ae"}, + {file = "pycocotools-2.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e6f7bfa1c5fb206a614bf2382c923d56092219a12dfd0fec3b5f83c13e29e00"}, + {file = "pycocotools-2.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b29086b6ce7b73e4ddaf3045006f5c059f344a2720605cd4474814017ff2af53"}, + {file = "pycocotools-2.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:254506c0eecabb3abbde17640f82103c0c04d53148ae920657664cab9cd649fc"}, + {file = "pycocotools-2.0.7.tar.gz", hash = "sha256:da8b7815196eebf0adabf67fcc459126cbc6498bbc6ab1fd144c371465d86879"}, +] + +[package.dependencies] +matplotlib = ">=2.1.0" +numpy = "*" + [[package]] name = "pygltflib" -version = "1.15.6" +version = "1.16.1" description = "Python library for reading, writing and managing 3D objects in the Khronos Group gltf and gltf2 formats." -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "pygltflib-1.15.6.tar.gz", hash = "sha256:5f16feed008796638731d7f4db05170bd93f2f558b6e15a011f816fe0de43f70"}, + {file = "pygltflib-1.16.1.tar.gz", hash = "sha256:ccea04343382bacaa8f00f4cf0bfdaada468ba0e4f174f88d701af0695761bf3"}, ] [package.dependencies] dataclasses-json = ">=0.0.25" deprecated = "*" +[[package]] +name = "pyparsing" +version = "3.1.1" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = true +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pyproj" +version = "3.6.0" +description = "Python interface to PROJ (cartographic projections and coordinate transformations library)" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pyproj-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e600f6a2771d3b41aeb2cc1efd96771ae9a01451013da1dd48ff272e7c6e34ef"}, + {file = "pyproj-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7f6cd045df29aae960391dfe06a575c110af598f1dea5add8be6ca42332b0f5"}, + {file = "pyproj-3.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:557e6592855111c84eda176ddf6b130f55d5e2b9cb1c017b8c91b69f37f474f5"}, + {file = "pyproj-3.6.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de6288b6ceabdeeac01abf627c74414822d322d8f55dc8efe4d29dedd27c5719"}, + {file = "pyproj-3.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e427ccdbb1763872416549bdfa9fa1f5f169054653c4daf674e71480cc39cf11"}, + {file = "pyproj-3.6.0-cp310-cp310-win32.whl", hash = "sha256:1283d3c1960edbb74828f5f3405b27578a9a27f7766ab6a3956f4bd851f08239"}, + {file = "pyproj-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:9de1aab71234bfd3fd648a1152519b5ee152c43113d7d8ea52590a0140129501"}, + {file = "pyproj-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:00fab048596c17572fa8980014ef117dbb2a445e6f7ba3b9ddfcc683efc598e7"}, + {file = "pyproj-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba5e7c8ddd6ed5a3f9fcf95ea80ba44c931913723de2ece841c94bb38b200c4a"}, + {file = "pyproj-3.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08dfc5c9533c78a97afae9d53b99b810a4a8f97c3be9eb2b8f323b726c736403"}, + {file = "pyproj-3.6.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18a8bdb87aeb41b60a2e91d32f623227de3569fb83b4c64b174c3a7c5b0ed3ae"}, + {file = "pyproj-3.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfe392dfc0eba2248dc08c976a72f52ff9da2bddfddfd9ff5dcf18e8e88200c7"}, + {file = "pyproj-3.6.0-cp311-cp311-win32.whl", hash = "sha256:78276c6b0c831255c97c56dff7313a3571f327a284d8ac63d6a56437a72ed0e0"}, + {file = "pyproj-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:8fbac2eb9a0e425d7d6b7c6f4ebacd675cf3bdef0c59887057b8b4b0374e7c12"}, + {file = "pyproj-3.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:95120d65cbc5983dfd877076f28dbc18b9b329cbee38ca6e217bb7a5a043c099"}, + {file = "pyproj-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:830e6de7cfe43853967afee5ef908dfd5aa72d1ec12af9b9e3fecc179886e346"}, + {file = "pyproj-3.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e342b3010b2b20134671564ff9a8c476e5e512bf589477480aded1a5813af7c8"}, + {file = "pyproj-3.6.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23787460fab85ba2f857ee60ffb2e8e21fd9bd5db9833c51c1c05b2a6d9f0be5"}, + {file = "pyproj-3.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595376e4d3bb72b7dceeccbce0f4c43053d47561f17a1ad0224407e9980ee849"}, + {file = "pyproj-3.6.0-cp39-cp39-win32.whl", hash = "sha256:4d8a9773503085eada59b6892c96ddf686ab8cf64cfdc18ad744d13ee76dfa6f"}, + {file = "pyproj-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:137a07404f937f264b11b7130cd4cfa00002dbe4333b222e8056db84849c2ea4"}, + {file = "pyproj-3.6.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2799499a4045e4fb73e44c31bdacab0593a253a7a4b6baae6fdd27d604cf9bc2"}, + {file = "pyproj-3.6.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f04f6297c615c3b17f835df2556ac8fb9b4f51f281e960437eaf0cd80e7ae26a"}, + {file = "pyproj-3.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a4d2d438b007cb1f8d5f6f308d53d7ff9a2508cff8f9da6e2a93b76ffd98aaf"}, + {file = "pyproj-3.6.0.tar.gz", hash = "sha256:a5b111865b3f0f8b77b3983f2fbe4dd6248fc09d3730295949977c8dcd988062"}, +] + +[package.dependencies] +certifi = "*" + [[package]] name = "pytest" -version = "7.4.0" +version = "7.4.4" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -415,7 +910,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -428,226 +922,337 @@ six = ">=1.5" [[package]] name = "pyyaml" -version = "6.0" +version = "6.0.1" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "scikit-image" +version = "0.22.0" +description = "Image processing in Python" +optional = true +python-versions = ">=3.9" +files = [ + {file = "scikit_image-0.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74ec5c1d4693506842cc7c9487c89d8fc32aed064e9363def7af08b8f8cbb31d"}, + {file = "scikit_image-0.22.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:a05ae4fe03d802587ed8974e900b943275548cde6a6807b785039d63e9a7a5ff"}, + {file = "scikit_image-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a92dca3d95b1301442af055e196a54b5a5128c6768b79fc0a4098f1d662dee6"}, + {file = "scikit_image-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3663d063d8bf2fb9bdfb0ca967b9ee3b6593139c860c7abc2d2351a8a8863938"}, + {file = "scikit_image-0.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:ebdbdc901bae14dab637f8d5c99f6d5cc7aaf4a3b6f4003194e003e9f688a6fc"}, + {file = "scikit_image-0.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95d6da2d8a44a36ae04437c76d32deb4e3c993ffc846b394b9949fd8ded73cb2"}, + {file = "scikit_image-0.22.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:2c6ef454a85f569659b813ac2a93948022b0298516b757c9c6c904132be327e2"}, + {file = "scikit_image-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e87872f067444ee90a00dd49ca897208308645382e8a24bd3e76f301af2352cd"}, + {file = "scikit_image-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5c378db54e61b491b9edeefff87e49fcf7fdf729bb93c777d7a5f15d36f743e"}, + {file = "scikit_image-0.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:2bcb74adb0634258a67f66c2bb29978c9a3e222463e003b67ba12056c003971b"}, + {file = "scikit_image-0.22.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:003ca2274ac0fac252280e7179ff986ff783407001459ddea443fe7916e38cff"}, + {file = "scikit_image-0.22.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:cf3c0c15b60ae3e557a0c7575fbd352f0c3ce0afca562febfe3ab80efbeec0e9"}, + {file = "scikit_image-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5b23908dd4d120e6aecb1ed0277563e8cbc8d6c0565bdc4c4c6475d53608452"}, + {file = "scikit_image-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be79d7493f320a964f8fcf603121595ba82f84720de999db0fcca002266a549a"}, + {file = "scikit_image-0.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:722b970aa5da725dca55252c373b18bbea7858c1cdb406e19f9b01a4a73b30b2"}, + {file = "scikit_image-0.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:22318b35044cfeeb63ee60c56fc62450e5fe516228138f1d06c7a26378248a86"}, + {file = "scikit_image-0.22.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:9e801c44a814afdadeabf4dffdffc23733e393767958b82319706f5fa3e1eaa9"}, + {file = "scikit_image-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c472a1fb3665ec5c00423684590631d95f9afcbc97f01407d348b821880b2cb3"}, + {file = "scikit_image-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b7a6c89e8d6252332121b58f50e1625c35f7d6a85489c0b6b7ee4f5155d547a"}, + {file = "scikit_image-0.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:5071b8f6341bfb0737ab05c8ab4ac0261f9e25dbcc7b5d31e5ed230fd24a7929"}, + {file = "scikit_image-0.22.0.tar.gz", hash = "sha256:018d734df1d2da2719087d15f679d19285fce97cd37695103deadfaef2873236"}, +] + +[package.dependencies] +imageio = ">=2.27" +lazy_loader = ">=0.3" +networkx = ">=2.8" +numpy = ">=1.22" +packaging = ">=21" +pillow = ">=9.0.1" +scipy = ">=1.8" +tifffile = ">=2022.8.12" + +[package.extras] +build = ["Cython (>=0.29.32)", "build", "meson-python (>=0.14)", "ninja", "numpy (>=1.22)", "packaging (>=21)", "pythran", "setuptools (>=67)", "spin (==0.6)", "wheel"] +data = ["pooch (>=1.6.0)"] +developer = ["pre-commit", "tomli"] +docs = ["PyWavelets (>=1.1.1)", "dask[array] (>=2022.9.2)", "ipykernel", "ipywidgets", "kaleido", "matplotlib (>=3.5)", "myst-parser", "numpydoc (>=1.6)", "pandas (>=1.5)", "plotly (>=5.10)", "pooch (>=1.6)", "pydata-sphinx-theme (>=0.14.1)", "pytest-runner", "scikit-learn (>=1.1)", "seaborn (>=0.11)", "sphinx (>=7.2)", "sphinx-copybutton", "sphinx-gallery (>=0.14)", "sphinx_design (>=0.5)", "tifffile (>=2022.8.12)"] +optional = ["PyWavelets (>=1.1.1)", "SimpleITK", "astropy (>=5.0)", "cloudpickle (>=0.2.1)", "dask[array] (>=2021.1.0)", "matplotlib (>=3.5)", "pooch (>=1.6.0)", "pyamg", "scikit-learn (>=1.1)"] +test = ["asv", "matplotlib (>=3.5)", "numpydoc (>=1.5)", "pooch (>=1.6.0)", "pytest (>=7.0)", "pytest-cov (>=2.11.0)", "pytest-faulthandler", "pytest-localserver"] + +[[package]] +name = "scipy" +version = "1.11.4" +description = "Fundamental algorithms for scientific computing in Python" +optional = true +python-versions = ">=3.9" +files = [ + {file = "scipy-1.11.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc9a714581f561af0848e6b69947fda0614915f072dfd14142ed1bfe1b806710"}, + {file = "scipy-1.11.4-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:cf00bd2b1b0211888d4dc75656c0412213a8b25e80d73898083f402b50f47e41"}, + {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9999c008ccf00e8fbcce1236f85ade5c569d13144f77a1946bef8863e8f6eb4"}, + {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:933baf588daa8dc9a92c20a0be32f56d43faf3d1a60ab11b3f08c356430f6e56"}, + {file = "scipy-1.11.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8fce70f39076a5aa62e92e69a7f62349f9574d8405c0a5de6ed3ef72de07f446"}, + {file = "scipy-1.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:6550466fbeec7453d7465e74d4f4b19f905642c89a7525571ee91dd7adabb5a3"}, + {file = "scipy-1.11.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f313b39a7e94f296025e3cffc2c567618174c0b1dde173960cf23808f9fae4be"}, + {file = "scipy-1.11.4-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1b7c3dca977f30a739e0409fb001056484661cb2541a01aba0bb0029f7b68db8"}, + {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00150c5eae7b610c32589dda259eacc7c4f1665aedf25d921907f4d08a951b1c"}, + {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:530f9ad26440e85766509dbf78edcfe13ffd0ab7fec2560ee5c36ff74d6269ff"}, + {file = "scipy-1.11.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5e347b14fe01003d3b78e196e84bd3f48ffe4c8a7b8a1afbcb8f5505cb710993"}, + {file = "scipy-1.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:acf8ed278cc03f5aff035e69cb511741e0418681d25fbbb86ca65429c4f4d9cd"}, + {file = "scipy-1.11.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:028eccd22e654b3ea01ee63705681ee79933652b2d8f873e7949898dda6d11b6"}, + {file = "scipy-1.11.4-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2c6ff6ef9cc27f9b3db93a6f8b38f97387e6e0591600369a297a50a8e96e835d"}, + {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b030c6674b9230d37c5c60ab456e2cf12f6784596d15ce8da9365e70896effc4"}, + {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad669df80528aeca5f557712102538f4f37e503f0c5b9541655016dd0932ca79"}, + {file = "scipy-1.11.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce7fff2e23ab2cc81ff452a9444c215c28e6305f396b2ba88343a567feec9660"}, + {file = "scipy-1.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:36750b7733d960d7994888f0d148d31ea3017ac15eef664194b4ef68d36a4a97"}, + {file = "scipy-1.11.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e619aba2df228a9b34718efb023966da781e89dd3d21637b27f2e54db0410d7"}, + {file = "scipy-1.11.4-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:f3cd9e7b3c2c1ec26364856f9fbe78695fe631150f94cd1c22228456404cf1ec"}, + {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d10e45a6c50211fe256da61a11c34927c68f277e03138777bdebedd933712fea"}, + {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91af76a68eeae0064887a48e25c4e616fa519fa0d38602eda7e0f97d65d57937"}, + {file = "scipy-1.11.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6df1468153a31cf55ed5ed39647279beb9cfb5d3f84369453b49e4b8502394fd"}, + {file = "scipy-1.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:ee410e6de8f88fd5cf6eadd73c135020bfbbbdfcd0f6162c36a7638a1ea8cc65"}, + {file = "scipy-1.11.4.tar.gz", hash = "sha256:90a2b78e7f5733b9de748f589f09225013685f9b218275257f8a8168ededaeaa"}, ] +[package.dependencies] +numpy = ">=1.21.6,<1.28.0" + +[package.extras] +dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] +doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] +test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + [[package]] name = "setuptools" -version = "68.0.0" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, - {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shapely" -version = "2.0.1" +version = "2.0.2" description = "Manipulation and analysis of geometric objects" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "shapely-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b06d031bc64149e340448fea25eee01360a58936c89985cf584134171e05863f"}, - {file = "shapely-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9a6ac34c16f4d5d3c174c76c9d7614ec8fe735f8f82b6cc97a46b54f386a86bf"}, - {file = "shapely-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:865bc3d7cc0ea63189d11a0b1120d1307ed7a64720a8bfa5be2fde5fc6d0d33f"}, - {file = "shapely-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45b4833235b90bc87ee26c6537438fa77559d994d2d3be5190dd2e54d31b2820"}, - {file = "shapely-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce88ec79df55430e37178a191ad8df45cae90b0f6972d46d867bf6ebbb58cc4d"}, - {file = "shapely-2.0.1-cp310-cp310-win32.whl", hash = "sha256:01224899ff692a62929ef1a3f5fe389043e262698a708ab7569f43a99a48ae82"}, - {file = "shapely-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:da71de5bf552d83dcc21b78cc0020e86f8d0feea43e202110973987ffa781c21"}, - {file = "shapely-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:502e0a607f1dcc6dee0125aeee886379be5242c854500ea5fd2e7ac076b9ce6d"}, - {file = "shapely-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d3bbeefd8a6a1a1017265d2d36f8ff2d79d0162d8c141aa0d37a87063525656"}, - {file = "shapely-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f470a130d6ddb05b810fc1776d918659407f8d025b7f56d2742a596b6dffa6c7"}, - {file = "shapely-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4641325e065fd3e07d55677849c9ddfd0cf3ee98f96475126942e746d55b17c8"}, - {file = "shapely-2.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90cfa4144ff189a3c3de62e2f3669283c98fb760cfa2e82ff70df40f11cadb39"}, - {file = "shapely-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70a18fc7d6418e5aea76ac55dce33f98e75bd413c6eb39cfed6a1ba36469d7d4"}, - {file = "shapely-2.0.1-cp311-cp311-win32.whl", hash = "sha256:09d6c7763b1bee0d0a2b84bb32a4c25c6359ad1ac582a62d8b211e89de986154"}, - {file = "shapely-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:d8f55f355be7821dade839df785a49dc9f16d1af363134d07eb11e9207e0b189"}, - {file = "shapely-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:83a8ec0ee0192b6e3feee9f6a499d1377e9c295af74d7f81ecba5a42a6b195b7"}, - {file = "shapely-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a529218e72a3dbdc83676198e610485fdfa31178f4be5b519a8ae12ea688db14"}, - {file = "shapely-2.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91575d97fd67391b85686573d758896ed2fc7476321c9d2e2b0c398b628b961c"}, - {file = "shapely-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8b0d834b11be97d5ab2b4dceada20ae8e07bcccbc0f55d71df6729965f406ad"}, - {file = "shapely-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:b4f0711cc83734c6fad94fc8d4ec30f3d52c1787b17d9dca261dc841d4731c64"}, - {file = "shapely-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:05c51a29336e604c084fb43ae5dbbfa2c0ef9bd6fedeae0a0d02c7b57a56ba46"}, - {file = "shapely-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b519cf3726ddb6c67f6a951d1bb1d29691111eaa67ea19ddca4d454fbe35949c"}, - {file = "shapely-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:193a398d81c97a62fc3634a1a33798a58fd1dcf4aead254d080b273efbb7e3ff"}, - {file = "shapely-2.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e55698e0ed95a70fe9ff9a23c763acfe0bf335b02df12142f74e4543095e9a9b"}, - {file = "shapely-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f32a748703e7bf6e92dfa3d2936b2fbfe76f8ce5f756e24f49ef72d17d26ad02"}, - {file = "shapely-2.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a34a23d6266ca162499e4a22b79159dc0052f4973d16f16f990baa4d29e58b6"}, - {file = "shapely-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d173d24e85e51510e658fb108513d5bc11e3fd2820db6b1bd0522266ddd11f51"}, - {file = "shapely-2.0.1-cp38-cp38-win32.whl", hash = "sha256:3cb256ae0c01b17f7bc68ee2ffdd45aebf42af8992484ea55c29a6151abe4386"}, - {file = "shapely-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:c7eed1fb3008a8a4a56425334b7eb82651a51f9e9a9c2f72844a2fb394f38a6c"}, - {file = "shapely-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ac1dfc397475d1de485e76de0c3c91cc9d79bd39012a84bb0f5e8a199fc17bef"}, - {file = "shapely-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33403b8896e1d98aaa3a52110d828b18985d740cc9f34f198922018b1e0f8afe"}, - {file = "shapely-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2569a4b91caeef54dd5ae9091ae6f63526d8ca0b376b5bb9fd1a3195d047d7d4"}, - {file = "shapely-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a70a614791ff65f5e283feed747e1cc3d9e6c6ba91556e640636bbb0a1e32a71"}, - {file = "shapely-2.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c43755d2c46b75a7b74ac6226d2cc9fa2a76c3263c5ae70c195c6fb4e7b08e79"}, - {file = "shapely-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad81f292fffbd568ae71828e6c387da7eb5384a79db9b4fde14dd9fdeffca9a"}, - {file = "shapely-2.0.1-cp39-cp39-win32.whl", hash = "sha256:b50c401b64883e61556a90b89948297f1714dbac29243d17ed9284a47e6dd731"}, - {file = "shapely-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:bca57b683e3d94d0919e2f31e4d70fdfbb7059650ef1b431d9f4e045690edcd5"}, - {file = "shapely-2.0.1.tar.gz", hash = "sha256:66a6b1a3e72ece97fc85536a281476f9b7794de2e646ca8a4517e2e3c1446893"}, + {file = "shapely-2.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6ca8cffbe84ddde8f52b297b53f8e0687bd31141abb2c373fd8a9f032df415d6"}, + {file = "shapely-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:baa14fc27771e180c06b499a0a7ba697c7988c7b2b6cba9a929a19a4d2762de3"}, + {file = "shapely-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36480e32c434d168cdf2f5e9862c84aaf4d714a43a8465ae3ce8ff327f0affb7"}, + {file = "shapely-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef753200cbffd4f652efb2c528c5474e5a14341a473994d90ad0606522a46a2"}, + {file = "shapely-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9a41ff4323fc9d6257759c26eb1cf3a61ebc7e611e024e6091f42977303fd3a"}, + {file = "shapely-2.0.2-cp310-cp310-win32.whl", hash = "sha256:72b5997272ae8c25f0fd5b3b967b3237e87fab7978b8d6cd5fa748770f0c5d68"}, + {file = "shapely-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:34eac2337cbd67650248761b140d2535855d21b969d76d76123317882d3a0c1a"}, + {file = "shapely-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b0c052709c8a257c93b0d4943b0b7a3035f87e2d6a8ac9407b6a992d206422f"}, + {file = "shapely-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d217e56ae067e87b4e1731d0dc62eebe887ced729ba5c2d4590e9e3e9fdbd88"}, + {file = "shapely-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94ac128ae2ab4edd0bffcd4e566411ea7bdc738aeaf92c32a8a836abad725f9f"}, + {file = "shapely-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa3ee28f5e63a130ec5af4dc3c4cb9c21c5788bb13c15e89190d163b14f9fb89"}, + {file = "shapely-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:737dba15011e5a9b54a8302f1748b62daa207c9bc06f820cd0ad32a041f1c6f2"}, + {file = "shapely-2.0.2-cp311-cp311-win32.whl", hash = "sha256:45ac6906cff0765455a7b49c1670af6e230c419507c13e2f75db638c8fc6f3bd"}, + {file = "shapely-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:dc9342fc82e374130db86a955c3c4525bfbf315a248af8277a913f30911bed9e"}, + {file = "shapely-2.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:06f193091a7c6112fc08dfd195a1e3846a64306f890b151fa8c63b3e3624202c"}, + {file = "shapely-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eebe544df5c018134f3c23b6515877f7e4cd72851f88a8d0c18464f414d141a2"}, + {file = "shapely-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7e92e7c255f89f5cdf777690313311f422aa8ada9a3205b187113274e0135cd8"}, + {file = "shapely-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be46d5509b9251dd9087768eaf35a71360de6afac82ce87c636990a0871aa18b"}, + {file = "shapely-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5533a925d8e211d07636ffc2fdd9a7f9f13d54686d00577eeb11d16f00be9c4"}, + {file = "shapely-2.0.2-cp312-cp312-win32.whl", hash = "sha256:084b023dae8ad3d5b98acee9d3bf098fdf688eb0bb9b1401e8b075f6a627b611"}, + {file = "shapely-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:ea84d1cdbcf31e619d672b53c4532f06253894185ee7acb8ceb78f5f33cbe033"}, + {file = "shapely-2.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ed1e99702125e7baccf401830a3b94d810d5c70b329b765fe93451fe14cf565b"}, + {file = "shapely-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7d897e6bdc6bc64f7f65155dbbb30e49acaabbd0d9266b9b4041f87d6e52b3a"}, + {file = "shapely-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0521d76d1e8af01e712db71da9096b484f081e539d4f4a8c97342e7971d5e1b4"}, + {file = "shapely-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:5324be299d4c533ecfcfd43424dfd12f9428fd6f12cda38a4316da001d6ef0ea"}, + {file = "shapely-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:78128357a0cee573257a0c2c388d4b7bf13cb7dbe5b3fe5d26d45ebbe2a39e25"}, + {file = "shapely-2.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87dc2be34ac3a3a4a319b963c507ac06682978a5e6c93d71917618b14f13066e"}, + {file = "shapely-2.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:42997ac806e4583dad51c80a32d38570fd9a3d4778f5e2c98f9090aa7db0fe91"}, + {file = "shapely-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ccfd5fa10a37e67dbafc601c1ddbcbbfef70d34c3f6b0efc866ddbdb55893a6c"}, + {file = "shapely-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7c95d3379ae3abb74058938a9fcbc478c6b2e28d20dace38f8b5c587dde90aa"}, + {file = "shapely-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a21353d28209fb0d8cc083e08ca53c52666e0d8a1f9bbe23b6063967d89ed24"}, + {file = "shapely-2.0.2-cp38-cp38-win32.whl", hash = "sha256:03e63a99dfe6bd3beb8d5f41ec2086585bb969991d603f9aeac335ad396a06d4"}, + {file = "shapely-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:c6fd29fbd9cd76350bd5cc14c49de394a31770aed02d74203e23b928f3d2f1aa"}, + {file = "shapely-2.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f217d28ecb48e593beae20a0082a95bd9898d82d14b8fcb497edf6bff9a44d7"}, + {file = "shapely-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:394e5085b49334fd5b94fa89c086edfb39c3ecab7f669e8b2a4298b9d523b3a5"}, + {file = "shapely-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fd3ad17b64466a033848c26cb5b509625c87d07dcf39a1541461cacdb8f7e91c"}, + {file = "shapely-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d41a116fcad58048d7143ddb01285e1a8780df6dc1f56c3b1e1b7f12ed296651"}, + {file = "shapely-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dea9a0651333cf96ef5bb2035044e3ad6a54f87d90e50fe4c2636debf1b77abc"}, + {file = "shapely-2.0.2-cp39-cp39-win32.whl", hash = "sha256:b8eb0a92f7b8c74f9d8fdd1b40d395113f59bd8132ca1348ebcc1f5aece94b96"}, + {file = "shapely-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:794affd80ca0f2c536fc948a3afa90bd8fb61ebe37fe873483ae818e7f21def4"}, + {file = "shapely-2.0.2.tar.gz", hash = "sha256:1713cc04c171baffc5b259ba8531c58acc2a301707b7f021d88a15ed090649e7"}, ] [package.dependencies] numpy = ">=1.14" [package.extras] -docs = ["matplotlib", "numpydoc (>=1.1.0,<1.2.0)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] +docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] test = ["pytest", "pytest-cov"] [[package]] name = "simplejson" -version = "3.19.1" +version = "3.19.2" description = "Simple, fast, extensible JSON encoder/decoder for Python" -category = "main" optional = false python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - {file = "simplejson-3.19.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:412e58997a30c5deb8cab5858b8e2e5b40ca007079f7010ee74565cc13d19665"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e765b1f47293dedf77946f0427e03ee45def2862edacd8868c6cf9ab97c8afbd"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3231100edee292da78948fa0a77dee4e5a94a0a60bcba9ed7a9dc77f4d4bb11e"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:081ea6305b3b5e84ae7417e7f45956db5ea3872ec497a584ec86c3260cda049e"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:f253edf694ce836631b350d758d00a8c4011243d58318fbfbe0dd54a6a839ab4"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:5db86bb82034e055257c8e45228ca3dbce85e38d7bfa84fa7b2838e032a3219c"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:69a8b10a4f81548bc1e06ded0c4a6c9042c0be0d947c53c1ed89703f7e613950"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:58ee5e24d6863b22194020eb62673cf8cc69945fcad6b283919490f6e359f7c5"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:73d0904c2471f317386d4ae5c665b16b5c50ab4f3ee7fd3d3b7651e564ad74b1"}, - {file = "simplejson-3.19.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:66d780047c31ff316ee305c3f7550f352d87257c756413632303fc59fef19eac"}, - {file = "simplejson-3.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd4d50a27b065447c9c399f0bf0a993bd0e6308db8bbbfbc3ea03b41c145775a"}, - {file = "simplejson-3.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c16ec6a67a5f66ab004190829eeede01c633936375edcad7cbf06d3241e5865"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a963e8dd4d81061cc05b627677c1f6a12e81345111fbdc5708c9f088d752c9"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e78d79b10aa92f40f54178ada2b635c960d24fc6141856b926d82f67e56d169"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad071cd84a636195f35fa71de2186d717db775f94f985232775794d09f8d9061"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e7c70f19405e5f99168077b785fe15fcb5f9b3c0b70b0b5c2757ce294922c8c"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54fca2b26bcd1c403146fd9461d1da76199442297160721b1d63def2a1b17799"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48600a6e0032bed17c20319d91775f1797d39953ccfd68c27f83c8d7fc3b32cb"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:93f5ac30607157a0b2579af59a065bcfaa7fadeb4875bf927a8f8b6739c8d910"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b79642a599740603ca86cf9df54f57a2013c47e1dd4dd2ae4769af0a6816900"}, - {file = "simplejson-3.19.1-cp310-cp310-win32.whl", hash = "sha256:d9f2c27f18a0b94107d57294aab3d06d6046ea843ed4a45cae8bd45756749f3a"}, - {file = "simplejson-3.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:5673d27806085d2a413b3be5f85fad6fca4b7ffd31cfe510bbe65eea52fff571"}, - {file = "simplejson-3.19.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:79c748aa61fd8098d0472e776743de20fae2686edb80a24f0f6593a77f74fe86"}, - {file = "simplejson-3.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:390f4a8ca61d90bcf806c3ad644e05fa5890f5b9a72abdd4ca8430cdc1e386fa"}, - {file = "simplejson-3.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d61482b5d18181e6bb4810b4a6a24c63a490c3a20e9fbd7876639653e2b30a1a"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2541fdb7467ef9bfad1f55b6c52e8ea52b3ce4a0027d37aff094190a955daa9d"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46133bc7dd45c9953e6ee4852e3de3d5a9a4a03b068bd238935a5c72f0a1ce34"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f96def94576f857abf58e031ce881b5a3fc25cbec64b2bc4824824a8a4367af9"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f14ecca970d825df0d29d5c6736ff27999ee7bdf5510e807f7ad8845f7760ce"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:66389b6b6ee46a94a493a933a26008a1bae0cfadeca176933e7ff6556c0ce998"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:22b867205cd258050c2625325fdd9a65f917a5aff22a23387e245ecae4098e78"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c39fa911e4302eb79c804b221ddec775c3da08833c0a9120041dd322789824de"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:65dafe413b15e8895ad42e49210b74a955c9ae65564952b0243a18fb35b986cc"}, - {file = "simplejson-3.19.1-cp311-cp311-win32.whl", hash = "sha256:f05d05d99fce5537d8f7a0af6417a9afa9af3a6c4bb1ba7359c53b6257625fcb"}, - {file = "simplejson-3.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:b46aaf0332a8a9c965310058cf3487d705bf672641d2c43a835625b326689cf4"}, - {file = "simplejson-3.19.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b438e5eaa474365f4faaeeef1ec3e8d5b4e7030706e3e3d6b5bee6049732e0e6"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa9d614a612ad02492f704fbac636f666fa89295a5d22b4facf2d665fc3b5ea9"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46e89f58e4bed107626edce1cf098da3664a336d01fc78fddcfb1f397f553d44"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96ade243fb6f3b57e7bd3b71e90c190cd0f93ec5dce6bf38734a73a2e5fa274f"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed18728b90758d171f0c66c475c24a443ede815cf3f1a91e907b0db0ebc6e508"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:6a561320485017ddfc21bd2ed5de2d70184f754f1c9b1947c55f8e2b0163a268"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:2098811cd241429c08b7fc5c9e41fcc3f59f27c2e8d1da2ccdcf6c8e340ab507"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8f8d179393e6f0cf6c7c950576892ea6acbcea0a320838c61968ac7046f59228"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:eff87c68058374e45225089e4538c26329a13499bc0104b52b77f8428eed36b2"}, - {file = "simplejson-3.19.1-cp36-cp36m-win32.whl", hash = "sha256:d300773b93eed82f6da138fd1d081dc96fbe53d96000a85e41460fe07c8d8b33"}, - {file = "simplejson-3.19.1-cp36-cp36m-win_amd64.whl", hash = "sha256:37724c634f93e5caaca04458f267836eb9505d897ab3947b52f33b191bf344f3"}, - {file = "simplejson-3.19.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:74bf802debe68627227ddb665c067eb8c73aa68b2476369237adf55c1161b728"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70128fb92932524c89f373e17221cf9535d7d0c63794955cc3cd5868e19f5d38"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8090e75653ea7db75bc21fa5f7bcf5f7bdf64ea258cbbac45c7065f6324f1b50"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a755f7bfc8adcb94887710dc70cc12a69a454120c6adcc6f251c3f7b46ee6aac"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ccb2c1877bc9b25bc4f4687169caa925ffda605d7569c40e8e95186e9a5e58b"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:919bc5aa4d8094cf8f1371ea9119e5d952f741dc4162810ab714aec948a23fe5"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e333c5b62e93949f5ac27e6758ba53ef6ee4f93e36cc977fe2e3df85c02f6dc4"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3a4480e348000d89cf501b5606415f4d328484bbb431146c2971123d49fd8430"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cb502cde018e93e75dc8fc7bb2d93477ce4f3ac10369f48866c61b5e031db1fd"}, - {file = "simplejson-3.19.1-cp37-cp37m-win32.whl", hash = "sha256:f41915a4e1f059dfad614b187bc06021fefb5fc5255bfe63abf8247d2f7a646a"}, - {file = "simplejson-3.19.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3844305bc33d52c4975da07f75b480e17af3558c0d13085eaa6cc2f32882ccf7"}, - {file = "simplejson-3.19.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1cb19eacb77adc5a9720244d8d0b5507421d117c7ed4f2f9461424a1829e0ceb"}, - {file = "simplejson-3.19.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:926957b278de22797bfc2f004b15297013843b595b3cd7ecd9e37ccb5fad0b72"}, - {file = "simplejson-3.19.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b0e9a5e66969f7a47dc500e3dba8edc3b45d4eb31efb855c8647700a3493dd8a"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79d46e7e33c3a4ef853a1307b2032cfb7220e1a079d0c65488fbd7118f44935a"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344a5093b71c1b370968d0fbd14d55c9413cb6f0355fdefeb4a322d602d21776"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23fbb7b46d44ed7cbcda689295862851105c7594ae5875dce2a70eeaa498ff86"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3025e7e9ddb48813aec2974e1a7e68e63eac911dd5e0a9568775de107ac79a"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:87b190e6ceec286219bd6b6f13547ca433f977d4600b4e81739e9ac23b5b9ba9"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc935d8322ba9bc7b84f99f40f111809b0473df167bf5b93b89fb719d2c4892b"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3b652579c21af73879d99c8072c31476788c8c26b5565687fd9db154070d852a"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6aa7ca03f25b23b01629b1c7f78e1cd826a66bfb8809f8977a3635be2ec48f1a"}, - {file = "simplejson-3.19.1-cp38-cp38-win32.whl", hash = "sha256:08be5a241fdf67a8e05ac7edbd49b07b638ebe4846b560673e196b2a25c94b92"}, - {file = "simplejson-3.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:ca56a6c8c8236d6fe19abb67ef08d76f3c3f46712c49a3b6a5352b6e43e8855f"}, - {file = "simplejson-3.19.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6424d8229ba62e5dbbc377908cfee9b2edf25abd63b855c21f12ac596cd18e41"}, - {file = "simplejson-3.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:547ea86ca408a6735335c881a2e6208851027f5bfd678d8f2c92a0f02c7e7330"}, - {file = "simplejson-3.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:889328873c35cb0b2b4c83cbb83ec52efee5a05e75002e2c0c46c4e42790e83c"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cdb4e544134f305b033ad79ae5c6b9a32e7c58b46d9f55a64e2a883fbbba01"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2b3f06430cbd4fac0dae5b2974d2bf14f71b415fb6de017f498950da8159b1"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d125e754d26c0298715bdc3f8a03a0658ecbe72330be247f4b328d229d8cf67f"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:476c8033abed7b1fd8db62a7600bf18501ce701c1a71179e4ce04ac92c1c5c3c"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:199a0bcd792811c252d71e3eabb3d4a132b3e85e43ebd93bfd053d5b59a7e78b"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a79b439a6a77649bb8e2f2644e6c9cc0adb720fc55bed63546edea86e1d5c6c8"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:203412745fed916fc04566ecef3f2b6c872b52f1e7fb3a6a84451b800fb508c1"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca922c61d87b4c38f37aa706520328ffe22d7ac1553ef1cadc73f053a673553"}, - {file = "simplejson-3.19.1-cp39-cp39-win32.whl", hash = "sha256:3e0902c278243d6f7223ba3e6c5738614c971fd9a887fff8feaa8dcf7249c8d4"}, - {file = "simplejson-3.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:d396b610e77b0c438846607cd56418bfc194973b9886550a98fd6724e8c6cfec"}, - {file = "simplejson-3.19.1-py3-none-any.whl", hash = "sha256:4710806eb75e87919b858af0cba4ffedc01b463edc3982ded7b55143f39e41e1"}, - {file = "simplejson-3.19.1.tar.gz", hash = "sha256:6277f60848a7d8319d27d2be767a7546bc965535b28070e310b3a9af90604a4c"}, + {file = "simplejson-3.19.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3471e95110dcaf901db16063b2e40fb394f8a9e99b3fe9ee3acc6f6ef72183a2"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3194cd0d2c959062b94094c0a9f8780ffd38417a5322450a0db0ca1a23e7fbd2"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8a390e56a7963e3946ff2049ee1eb218380e87c8a0e7608f7f8790ba19390867"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1537b3dd62d8aae644f3518c407aa8469e3fd0f179cdf86c5992792713ed717a"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a8617625369d2d03766413bff9e64310feafc9fc4f0ad2b902136f1a5cd8c6b0"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:2c433a412e96afb9a3ce36fa96c8e61a757af53e9c9192c97392f72871e18e69"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f1c70249b15e4ce1a7d5340c97670a95f305ca79f376887759b43bb33288c973"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:287e39ba24e141b046812c880f4619d0ca9e617235d74abc27267194fc0c7835"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6f0a0b41dd05eefab547576bed0cf066595f3b20b083956b1405a6f17d1be6ad"}, + {file = "simplejson-3.19.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f98d918f7f3aaf4b91f2b08c0c92b1774aea113334f7cde4fe40e777114dbe6"}, + {file = "simplejson-3.19.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d74beca677623481810c7052926365d5f07393c72cbf62d6cce29991b676402"}, + {file = "simplejson-3.19.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7f2398361508c560d0bf1773af19e9fe644e218f2a814a02210ac2c97ad70db0"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ad331349b0b9ca6da86064a3599c425c7a21cd41616e175ddba0866da32df48"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:332c848f02d71a649272b3f1feccacb7e4f7e6de4a2e6dc70a32645326f3d428"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25785d038281cd106c0d91a68b9930049b6464288cea59ba95b35ee37c2d23a5"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18955c1da6fc39d957adfa346f75226246b6569e096ac9e40f67d102278c3bcb"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:11cc3afd8160d44582543838b7e4f9aa5e97865322844b75d51bf4e0e413bb3e"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b01fda3e95d07a6148702a641e5e293b6da7863f8bc9b967f62db9461330562c"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:778331444917108fa8441f59af45886270d33ce8a23bfc4f9b192c0b2ecef1b3"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9eb117db8d7ed733a7317c4215c35993b815bf6aeab67523f1f11e108c040672"}, + {file = "simplejson-3.19.2-cp310-cp310-win32.whl", hash = "sha256:39b6d79f5cbfa3eb63a869639cfacf7c41d753c64f7801efc72692c1b2637ac7"}, + {file = "simplejson-3.19.2-cp310-cp310-win_amd64.whl", hash = "sha256:5675e9d8eeef0aa06093c1ff898413ade042d73dc920a03e8cea2fb68f62445a"}, + {file = "simplejson-3.19.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed628c1431100b0b65387419551e822987396bee3c088a15d68446d92f554e0c"}, + {file = "simplejson-3.19.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:adcb3332979cbc941b8fff07181f06d2b608625edc0a4d8bc3ffc0be414ad0c4"}, + {file = "simplejson-3.19.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:08889f2f597ae965284d7b52a5c3928653a9406d88c93e3161180f0abc2433ba"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef7938a78447174e2616be223f496ddccdbf7854f7bf2ce716dbccd958cc7d13"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a970a2e6d5281d56cacf3dc82081c95c1f4da5a559e52469287457811db6a79b"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554313db34d63eac3b3f42986aa9efddd1a481169c12b7be1e7512edebff8eaf"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d36081c0b1c12ea0ed62c202046dca11438bee48dd5240b7c8de8da62c620e9"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a3cd18e03b0ee54ea4319cdcce48357719ea487b53f92a469ba8ca8e39df285e"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:66e5dc13bfb17cd6ee764fc96ccafd6e405daa846a42baab81f4c60e15650414"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:972a7833d4a1fcf7a711c939e315721a88b988553fc770a5b6a5a64bd6ebeba3"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3e74355cb47e0cd399ead3477e29e2f50e1540952c22fb3504dda0184fc9819f"}, + {file = "simplejson-3.19.2-cp311-cp311-win32.whl", hash = "sha256:1dd4f692304854352c3e396e9b5f0a9c9e666868dd0bdc784e2ac4c93092d87b"}, + {file = "simplejson-3.19.2-cp311-cp311-win_amd64.whl", hash = "sha256:9300aee2a8b5992d0f4293d88deb59c218989833e3396c824b69ba330d04a589"}, + {file = "simplejson-3.19.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b8d940fd28eb34a7084877747a60873956893e377f15a32ad445fe66c972c3b8"}, + {file = "simplejson-3.19.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4969d974d9db826a2c07671273e6b27bc48e940738d768fa8f33b577f0978378"}, + {file = "simplejson-3.19.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c594642d6b13d225e10df5c16ee15b3398e21a35ecd6aee824f107a625690374"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2f5a398b5e77bb01b23d92872255e1bcb3c0c719a3be40b8df146570fe7781a"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176a1b524a3bd3314ed47029a86d02d5a95cc0bee15bd3063a1e1ec62b947de6"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3c7363a8cb8c5238878ec96c5eb0fc5ca2cb11fc0c7d2379863d342c6ee367a"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:346820ae96aa90c7d52653539a57766f10f33dd4be609206c001432b59ddf89f"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de9a2792612ec6def556d1dc621fd6b2073aff015d64fba9f3e53349ad292734"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1c768e7584c45094dca4b334af361e43b0aaa4844c04945ac7d43379eeda9bc2"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:9652e59c022e62a5b58a6f9948b104e5bb96d3b06940c6482588176f40f4914b"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9c1a4393242e321e344213a90a1e3bf35d2f624aa8b8f6174d43e3c6b0e8f6eb"}, + {file = "simplejson-3.19.2-cp312-cp312-win32.whl", hash = "sha256:7cb98be113911cb0ad09e5523d0e2a926c09a465c9abb0784c9269efe4f95917"}, + {file = "simplejson-3.19.2-cp312-cp312-win_amd64.whl", hash = "sha256:6779105d2fcb7fcf794a6a2a233787f6bbd4731227333a072d8513b252ed374f"}, + {file = "simplejson-3.19.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:061e81ea2d62671fa9dea2c2bfbc1eec2617ae7651e366c7b4a2baf0a8c72cae"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4280e460e51f86ad76dc456acdbfa9513bdf329556ffc8c49e0200878ca57816"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11c39fbc4280d7420684494373b7c5904fa72a2b48ef543a56c2d412999c9e5d"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bccb3e88ec26ffa90f72229f983d3a5d1155e41a1171190fa723d4135523585b"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bb5b50dc6dd671eb46a605a3e2eb98deb4a9af787a08fcdddabe5d824bb9664"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d94245caa3c61f760c4ce4953cfa76e7739b6f2cbfc94cc46fff6c050c2390c5"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d0e5ffc763678d48ecc8da836f2ae2dd1b6eb2d27a48671066f91694e575173c"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d222a9ed082cd9f38b58923775152003765016342a12f08f8c123bf893461f28"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8434dcdd347459f9fd9c526117c01fe7ca7b016b6008dddc3c13471098f4f0dc"}, + {file = "simplejson-3.19.2-cp36-cp36m-win32.whl", hash = "sha256:c9ac1c2678abf9270e7228133e5b77c6c3c930ad33a3c1dfbdd76ff2c33b7b50"}, + {file = "simplejson-3.19.2-cp36-cp36m-win_amd64.whl", hash = "sha256:92c4a4a2b1f4846cd4364855cbac83efc48ff5a7d7c06ba014c792dd96483f6f"}, + {file = "simplejson-3.19.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0d551dc931638e2102b8549836a1632e6e7cf620af3d093a7456aa642bff601d"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73a8a4653f2e809049999d63530180d7b5a344b23a793502413ad1ecea9a0290"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40847f617287a38623507d08cbcb75d51cf9d4f9551dd6321df40215128325a3"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be893258d5b68dd3a8cba8deb35dc6411db844a9d35268a8d3793b9d9a256f80"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9eb3cff1b7d71aa50c89a0536f469cb8d6dcdd585d8f14fb8500d822f3bdee4"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d0f402e787e6e7ee7876c8b05e2fe6464820d9f35ba3f172e95b5f8b699f6c7f"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fbbcc6b0639aa09b9649f36f1bcb347b19403fe44109948392fbb5ea69e48c3e"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2fc697be37585eded0c8581c4788fcfac0e3f84ca635b73a5bf360e28c8ea1a2"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b0a3eb6dd39cce23801a50c01a0976971498da49bc8a0590ce311492b82c44b"}, + {file = "simplejson-3.19.2-cp37-cp37m-win32.whl", hash = "sha256:49f9da0d6cd17b600a178439d7d2d57c5ef01f816b1e0e875e8e8b3b42db2693"}, + {file = "simplejson-3.19.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c87c22bd6a987aca976e3d3e23806d17f65426191db36d40da4ae16a6a494cbc"}, + {file = "simplejson-3.19.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9e4c166f743bb42c5fcc60760fb1c3623e8fda94f6619534217b083e08644b46"}, + {file = "simplejson-3.19.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a48679310e1dd5c9f03481799311a65d343748fe86850b7fb41df4e2c00c087"}, + {file = "simplejson-3.19.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0521e0f07cb56415fdb3aae0bbd8701eb31a9dfef47bb57206075a0584ab2a2"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d2d5119b1d7a1ed286b8af37357116072fc96700bce3bec5bb81b2e7057ab41"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c1467d939932901a97ba4f979e8f2642415fcf02ea12f53a4e3206c9c03bc17"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49aaf4546f6023c44d7e7136be84a03a4237f0b2b5fb2b17c3e3770a758fc1a0"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60848ab779195b72382841fc3fa4f71698a98d9589b0a081a9399904487b5832"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0436a70d8eb42bea4fe1a1c32d371d9bb3b62c637969cb33970ad624d5a3336a"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:49e0e3faf3070abdf71a5c80a97c1afc059b4f45a5aa62de0c2ca0444b51669b"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ff836cd4041e16003549449cc0a5e372f6b6f871eb89007ab0ee18fb2800fded"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3848427b65e31bea2c11f521b6fc7a3145d6e501a1038529da2391aff5970f2f"}, + {file = "simplejson-3.19.2-cp38-cp38-win32.whl", hash = "sha256:3f39bb1f6e620f3e158c8b2eaf1b3e3e54408baca96a02fe891794705e788637"}, + {file = "simplejson-3.19.2-cp38-cp38-win_amd64.whl", hash = "sha256:0405984f3ec1d3f8777c4adc33eac7ab7a3e629f3b1c05fdded63acc7cf01137"}, + {file = "simplejson-3.19.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:445a96543948c011a3a47c8e0f9d61e9785df2544ea5be5ab3bc2be4bd8a2565"}, + {file = "simplejson-3.19.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a8c3cc4f9dfc33220246760358c8265dad6e1104f25f0077bbca692d616d358"}, + {file = "simplejson-3.19.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af9c7e6669c4d0ad7362f79cb2ab6784d71147503e62b57e3d95c4a0f222c01c"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:064300a4ea17d1cd9ea1706aa0590dcb3be81112aac30233823ee494f02cb78a"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9453419ea2ab9b21d925d0fd7e3a132a178a191881fab4169b6f96e118cc25bb"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e038c615b3906df4c3be8db16b3e24821d26c55177638ea47b3f8f73615111c"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16ca9c90da4b1f50f089e14485db8c20cbfff2d55424062791a7392b5a9b3ff9"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1018bd0d70ce85f165185d2227c71e3b1e446186f9fa9f971b69eee223e1e3cd"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e8dd53a8706b15bc0e34f00e6150fbefb35d2fd9235d095b4f83b3c5ed4fa11d"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:2d022b14d7758bfb98405672953fe5c202ea8a9ccf9f6713c5bd0718eba286fd"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:febffa5b1eda6622d44b245b0685aff6fb555ce0ed734e2d7b1c3acd018a2cff"}, + {file = "simplejson-3.19.2-cp39-cp39-win32.whl", hash = "sha256:4edcd0bf70087b244ba77038db23cd98a1ace2f91b4a3ecef22036314d77ac23"}, + {file = "simplejson-3.19.2-cp39-cp39-win_amd64.whl", hash = "sha256:aad7405c033d32c751d98d3a65801e2797ae77fac284a539f6c3a3e13005edc4"}, + {file = "simplejson-3.19.2-py3-none-any.whl", hash = "sha256:bcedf4cae0d47839fee7de344f96b5694ca53c786f28b5f773d4f0b265a159eb"}, + {file = "simplejson-3.19.2.tar.gz", hash = "sha256:9eb442a2442ce417801c912df68e1f6ccfcd41577ae7274953ab3ad24ef7d82c"}, ] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -655,11 +1260,27 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "tifffile" +version = "2023.12.9" +description = "Read and write TIFF files" +optional = true +python-versions = ">=3.9" +files = [ + {file = "tifffile-2023.12.9-py3-none-any.whl", hash = "sha256:9b066e4b1a900891ea42ffd33dab8ba34c537935618b9893ddef42d7d422692f"}, + {file = "tifffile-2023.12.9.tar.gz", hash = "sha256:9dd1da91180a6453018a241ff219e1905f169384355cd89c9ef4034c1b46cdb8"}, +] + +[package.dependencies] +numpy = "*" + +[package.extras] +all = ["defusedxml", "fsspec", "imagecodecs (>=2023.8.12)", "lxml", "matplotlib", "zarr"] + [[package]] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -669,42 +1290,39 @@ files = [ [[package]] name = "tqdm" -version = "4.65.0" +version = "4.66.1" description = "Fast, Extensible Progress Meter" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.65.0-py3-none-any.whl", hash = "sha256:c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671"}, - {file = "tqdm-4.65.0.tar.gz", hash = "sha256:1871fb68a86b8fb3b59ca4cdd3dcccbc7e6d613eeed31f4c332531977b89beb5"}, + {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, + {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["py-make (>=0.1.0)", "twine", "wheel"] +dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] [[package]] name = "typing-extensions" -version = "4.6.3" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, - {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] name = "typing-inspect" version = "0.9.0" description = "Runtime inspection utilities for typing module." -category = "main" optional = false python-versions = "*" files = [ @@ -718,111 +1336,107 @@ typing-extensions = ">=3.7.4" [[package]] name = "virtualenv" -version = "20.23.1" +version = "20.25.0" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.23.1-py3-none-any.whl", hash = "sha256:34da10f14fea9be20e0fd7f04aba9732f84e593dac291b757ce42e3368a39419"}, - {file = "virtualenv-20.23.1.tar.gz", hash = "sha256:8ff19a38c1021c742148edc4f81cb43d7f8c6816d2ede2ab72af5b84c749ade1"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] [package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.12,<4" -platformdirs = ">=3.5.1,<4" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "wrapt" -version = "1.15.0" +version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, - {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, - {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, - {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, - {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, - {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, - {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, - {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, - {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, - {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, - {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, - {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, - {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, - {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, - {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, - {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, - {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, - {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, - {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] +[extras] +coco = ["pycocotools", "scikit-image"] + [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "e989d8b79e90cf30a38adcd69a16ebee441a6cc40d35c80afb7b98caebfa7972" +content-hash = "70d7fdbdf17f4ecf636cc6c002a0c3460c389f222b1f61d5d6a8be672814b1e4" diff --git a/pyproject.toml b/pyproject.toml index b1d3b21..ae94b56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,23 @@ [build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" +requires = [ + "poetry-core>=1.0.0", +] +build-backend = "poetry.core.masonry.api" -[project] +[tool.poetry] name = "pyopf" -version = "1.1.1" +version = "1.2.0" description = "Python library for I/O and manipulation of projects under the Open Photogrammetry Format (OPF)" -requires-python = ">=3.10" -dependencies = ["numpy>=1.24.1", "pygltflib>=1.15.3", "shapely>=2.0.1", "argparse>=1.4.0", "python-dateutil>=2.8.2", "pillow>=9.5.0", "tqdm>=4.65.0"] +authors = [ + "Pix4D", +] +license = "Apache-2.0" readme = "README.md" -license = { file = "LICENSE" } +packages = [ + { include = "pyopf", from = "src" }, + { include = "opf_tools", from = "src" }, +] +homepage = "https://pix4d.github.io/opf-spec/specification/project.html" classifiers = [ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", @@ -18,46 +26,11 @@ classifiers = [ "Development Status :: 5 - Production/Stable", "Operating System :: OS Independent", ] -keywords = ["photogrammetry", "OPF"] - -[project.urls] -Homepage = "https://pix4d.github.io/opf-spec/specification/project.html" - -[project.optional-dependencies] -tests = [ - "simplejson>=18.3" +keywords = [ + "photogrammetry", + "OPF", ] -[project.scripts] -opf_crop = "opf_tools.crop.cropper:main" -opf_merge = "opf_tools.merge.merger:main" -opf_convert = "opf_tools.convert.converter:main" -opf_undistort = "opf_tools.undistort.undistorter:main" -opf2nerf = "opf_tools.opf2nerf.converter:main" - -[tool.hatch.build] -only_packages = true - -[tool.hatch.build.targets.wheel] -packages = ["src/pyopf", "src/opf_tools"] - -[tool.pytest.ini_options] -minversion = 6.0 -addopts = ["--import-mode=importlib"] -testpaths = ["tests"] -norecursedirs = ["spec"] -pythonpath = ["src", "tests"] - -[tool.isort] -multi_line_output = 3 -include_trailing_comma = true - -[tool.poetry] -name = "pyopf" -version = "1.1.1" -description = "Python library for I/O and manipulation of projects under the Open Photogrammetry Format (OPF)" -authors = ["Pix4D"] - [tool.poetry.dependencies] python = ">=3.10" numpy = "*" @@ -65,9 +38,16 @@ pygltflib = "*" shapely = "*" python-dateutil = "*" simplejson = "*" -pillow = "^9.5.0" +pillow = "~10" tqdm = "^4.65.0" +laspy = "2.4.1" +pyproj = "3.6.0" +plyfile = "0.9" -[tool.poetry.dev-dependencies] -pytest = "*" -pre-commit = "*" +[tool.poetry.scripts] +opf_crop = "opf_tools.crop.cropper:main" +opf_undistort = "opf_tools.undistort.undistorter:main" +opf2nerf = "opf_tools.opf2nerf.converter:main" +opf2colmap = "opf_tools.opf2colmap.converter:main" +opf2las = "opf_tools.opf2las.converter:main" +opf2ply = "opf_tools.opf2ply.converter:main" diff --git a/src/opf_tools/merge/merger.py b/src/opf_tools/merge/merger.py deleted file mode 100644 index 7f8ce86..0000000 --- a/src/opf_tools/merge/merger.py +++ /dev/null @@ -1,876 +0,0 @@ -import argparse -import copy -import os -import warnings -from collections import defaultdict -from pathlib import Path -from typing import Any, Optional, TypeVar, overload -from uuid import UUID - -import numpy as np - -import pyopf.pointcloud.merge as pcl_merge -from pyopf.cameras import ( - CalibratedCameras, - CameraList, - Capture, - GpsBias, - InputCameras, - ProjectedCapture, - ProjectedInputCameras, - ProjectedSensor, - Sensor, -) -from pyopf.cps import ( - CalibratedControlPoint, - CalibratedControlPoints, - Constraints, - InputControlPoints, - Mark, - OrientationConstraint, - ProjectedControlPoints, - ScaleConstraint, -) -from pyopf.crs import Crs, Geolocation, SceneReferenceFrame -from pyopf.io import load, save -from pyopf.pointcloud import GlTFPointCloud -from pyopf.pointcloud.pcl import ( - opf_axis_rotation_matrix, - opf_axis_rotation_matrix_inverse, -) -from pyopf.project import ( - Calibration, - Metadata, - Project, - ProjectObjects, - ProjectSource, -) -from pyopf.resolve import resolve -from pyopf.types import OpfObject -from pyopf.uid64 import Uid64, uid64 - -Object = TypeVar("Object", bound=OpfObject) - - -def _clear_unsupported_attributes(object: Object) -> Object: - object.unknown_properties = None - object.extensions = None - return object - - -def _are_crss_equal(lhs: Crs, rhs: Crs) -> bool: - # This implementation is very naïve at the moment - return lhs.definition == rhs.definition and lhs.geoid_height == rhs.geoid_height - - -def _are_geolocations_equal( - lhs: Optional[Geolocation], rhs: Optional[Geolocation] -) -> bool: - - return (lhs is None) == (rhs is None) and ( - lhs is None - or ( - bool( - rhs is not None - and _are_crss_equal(lhs.crs, rhs.crs) - and np.equal(lhs.coordinates, rhs.coordinates).all() - and np.equal(lhs.sigmas, rhs.sigmas).all() - ) - ) - ) - - -def _find_or_remap_id(id: Uid64, mapping: dict[Uid64, Uid64]) -> Uid64: - try: - return mapping[id] - except KeyError: - # We don't do anything to avoid colissions here based on the fact that the - # probability of having a collision with 1,000,000 elements is 2.7e-8 which - # is just a bit higher than the probability of winning EuroMillions. We have - # to play this game ~ 4,000,000 times to have a 10% chance of having one or - # more collisions. - new_id = uid64() - mapping[id] = new_id - return new_id - - -def _merge_names(objects: list[Any]): - - names = [o.metadata.name for o in objects if o.metadata.name is not None] - - unnamed = len(objects) - len(names) - if unnamed == len(objects): - return None # don't give any name to a union of unamed items - if unnamed == 1: - names.append("1 unnamed item") - elif unnamed != 0: - names.append("%d unnamed items" % unnamed) - - return " + ".join(names) - - -def _make_temporary_sources(objects: list[Any]): - """This function is meant to return the union of all original sources. - The purpose is to use it after all objects are merged to replace all sources - of the same type by the object in which they have been merged""" - sources = [] - for object in objects: - if isinstance(object.metadata.sources, list): - sources += object.metadata.sources - else: - for source in object.metadata.sources.__dict__.values(): - sources.append( - ProjectSource(id=source.metadata.id, type=source.metadata.type) - ) - return sources - - -def _merge_subojects_by_key( - key, containers, shifts=None, sensor_id_mappings=None, **kwargs -): - attributes = [ - getattr(container, key) for container in containers if hasattr(container, key) - ] - for o in attributes: - if isinstance(o, list) and len(o) > 1: - raise ValueError( - "Impossible to merge objects with more than one instance per suboject type" - ) - # Flattenning the attributes which are lists to their first element only - objects = [] - for attribute in attributes: - if isinstance(attribute, list): - if len(attribute) == 1: - objects.append(attribute[0]) - elif attribute is not None: - objects.append(attribute) - - if len(objects) == 0: - return None - - kwargs = copy.copy(kwargs) - - # Filtering of arguments that are lists with as many elements as projects to pass the - # right elements depending on the presence of the current object key in each project. - def filter_list(elements): - def accept(container, key): - if not hasattr(container, key): - return False - attribute = getattr(container, key) - if isinstance(attribute, list): - return len(attribute) != 0 - else: - return attribute is not None - - return [ - element - for container, element in zip(containers, elements) - if accept(container, key) - ] - - if shifts: - kwargs["shifts"] = filter_list(shifts) - if sensor_id_mappings: - kwargs["sensor_id_mappings"] = filter_list(sensor_id_mappings) - - return merge(*objects, **kwargs) - - -def _fix_sources(project: ProjectObjects, uuid_mapping: dict[UUID, UUID]) -> None: - for key, items in project.__dict__.items(): - - if key.startswith("_"): - continue - - for item in items: - sources = { - uuid_mapping[source.id]: source.type for source in item.metadata.sources - } - item.metadata.sources = [ - ProjectSource(id=id, type=type) for id, type in sources.items() - ] - - -def _merge_labels(objs: list[Any]): - labels = list( - { - label - for o in objs - if o.metadata.labels is not None - for label in o.metadata.labels - } - ) - if len(labels) == 0: - return None - return labels - - -def _merge_scene_reference_frames( - srss: list[SceneReferenceFrame], **kwargs -) -> SceneReferenceFrame: - # Nothing smart here, just return the first one after verifying they are - # all compatible. - srs = copy.deepcopy(srss[0]) - for other in srss[1:]: - if ( - other.crs.definition != srs.crs.definition - or other.base_to_canonical.swap_xy != srs.base_to_canonical.swap_xy - or (other.base_to_canonical.scale != srs.base_to_canonical.scale).any() - ): - raise RuntimeError("Incompatible spatial reference frames for merging") - _clear_unsupported_attributes(srs) - - if srs.metadata is None: - raise RuntimeError("SceneReferenceFrame metadata is None") - - srs.metadata.sources = [] - return srs - - -def _merge_metadata(objects: list[Any]): - # This function assumes that all objects are of the same type - return Metadata( - type=objects[0].metadata.type, - name=_merge_names(objects), - labels=_merge_labels(objects), - sources=_make_temporary_sources(objects), - ) - - -def _merge_camera_lists(camera_objs: list[CameraList], **kwargs) -> CameraList: - - id_to_uri = {} - - # The consistency of the camera UIDs is checked while creating the final list of cameras - cameras = [] - for camera_list in camera_objs: - for camera in camera_list.cameras: - try: - if id_to_uri[camera.id] != camera.uri: - raise RuntimeError( - "Fatal error: Camera UID inconsistency found for UID %s" - % camera.id - ) - except KeyError: - id_to_uri[camera.id] = camera.uri - cameras.append(_clear_unsupported_attributes(copy.copy(camera))) - - result = CameraList(cameras) - result.metadata = _merge_metadata(camera_objs) - return result - - -def _merge_marks(list1: list[Mark], list2: list[Mark]) -> list[Mark]: - - marks = {m.camera_id: m for m in list1} - for mark in list2: - try: - previous = marks[mark.camera_id] - if ( - previous.position_px != mark.position_px - ).any() or previous.accuracy != mark.accuracy: - raise RuntimeError("Inconsistent marks") - except KeyError: - marks[mark.camera_id] = mark - - return list(marks.values()) - - -def _merge_input_control_points( - cps_objs: list[InputControlPoints], **kwargs -) -> InputControlPoints: - - gcps = {} - mtps = {} - - def check_gcp_compatible(lhs, rhs) -> bool: - return lhs.is_checkpoint == rhs.is_checkpoint and _are_geolocations_equal( - lhs.geolocation, rhs.geolocation - ) - - def check_mtp_compatible(lhs, rhs) -> bool: - return lhs.is_checkpoint == rhs.is_checkpoint - - def process_tie_point(tp, output, other_type_output, comparison_fun): - - if tp.id in other_type_output: - raise RuntimeError("Tie point found as both MTP and GCP") - try: - existing = output[tp.id] - if not comparison_fun(tp, existing): - raise RuntimeError( - "Two incompatible instances of the same tie point found" - ) - existing.marks = _merge_marks(existing.marks, tp.marks) - except KeyError: - output[tp.id] = _clear_unsupported_attributes(copy.deepcopy(tp)) - except RuntimeError as e: - raise RuntimeError( - "Fatal error: Merging tie point %s: %s" % (tp.id, e.args[0]) - ) from e - - for cps in cps_objs: - for gcp in cps.gcps: - process_tie_point(gcp, gcps, mtps, check_gcp_compatible) - for mtp in cps.mtps: - process_tie_point(mtp, mtps, gcps, check_mtp_compatible) - - result = InputControlPoints(gcps=list(gcps.values()), mtps=list(mtps.values())) - result.metadata = _merge_metadata(cps_objs) - return result - - -def _merge_projected_control_points(cps_objs: list[ProjectedControlPoints], **kwargs): - - gcps = {} - - shifts = kwargs.get("shifts", [np.zeros(3) for i in range(len(cps_objs))]) - - for cps, shift in zip(cps_objs, shifts): - for gcp in cps.projected_gcps: - - gcp = _clear_unsupported_attributes(copy.deepcopy(gcp)) - gcp.coordinates += shift - - try: - existing = gcps[gcp.id] - if not np.allclose( - gcp.coordinates, existing.coordinates - ) or not np.allclose(gcp.sigmas, existing.sigmas): - raise RuntimeError( - "Fatal error: Repeated ID merging incompatible projected GCP: %s" - % gcp.id - ) - except KeyError: - gcps[gcp.id] = gcp - - result = ProjectedControlPoints(projected_gcps=list(gcps.values())) - result.metadata = _merge_metadata(cps_objs) - return result - - -def _merge_orientation_constraints( - constraint_objs: list[Constraints], -) -> list[OrientationConstraint]: - - orientations = {} - for constraints in constraint_objs: - for orientation in constraints.orientation_constraints: - try: - existing = orientations[orientation.id] - if ( - existing.id_from != orientation.id_from - or existing.id_to != orientation.id_to - or existing.sigma_deg != orientation.sigma_deg - or (existing.unit_vector != orientation.unit_vector).any() - ): - raise RuntimeError( - "FatalError: Repeated ID merging incompatible orientation contraint: %s" - % orientation.id - ) - except KeyError: - orientations[orientation.id] = orientation - - return list(orientations.values()) - - -def _merge_scale_constraints( - constraint_objs: list[Constraints], -) -> list[ScaleConstraint]: - - scales = {} - for constraints in constraint_objs: - for scale in constraints.scale_constraints: - try: - existing = scales[scale.id] - if ( - existing.id_from != scale.id_from - or existing.id_to != scale.id_to - or existing.sigma != scale.sigma - or existing.distance != scale.distance - ): - raise RuntimeError( - "FatalError: Repeated ID merging incompatible scale contraint: %s" - % scale.id - ) - except KeyError: - scales[scale.id] = scale - - return list(scales.values()) - - -def _merge_constraints(constraint_objs: list[Constraints], **kwargs) -> Constraints: - - result = Constraints( - orientation_constraints=_merge_orientation_constraints(constraint_objs), - scale_constraints=_merge_scale_constraints(constraint_objs), - ) - result.metadata = _merge_metadata(constraint_objs) - return result - - -@overload -def _merge_sensors( - camera_objs: list[InputCameras], - sensor_id_mappings: list[dict[Uid64, Uid64]], - input_type_name="input cameras", -) -> list[Sensor]: - ... - - -@overload -def _merge_sensors( - camera_objs: list[ProjectedInputCameras], - sensor_id_mappings: list[dict[Uid64, Uid64]], - input_type_name="input cameras", -) -> list[ProjectedSensor]: - ... - - -def _merge_sensors( - camera_objs: list[InputCameras] | list[ProjectedInputCameras], - sensor_id_mappings: list[dict[Uid64, Uid64]], - input_type_name="input cameras", -) -> list[Sensor] | list[ProjectedSensor]: - - """Merge all sensors in a single list. - Sensors in each InputCameras object get reassigned ID based on the input mapping or - new random IDs are produced and stored in the mapping if the sensor is not found.""" - - sensors = [] - for input_cameras, mapping in zip(camera_objs, sensor_id_mappings): - used_sensor_ids = set() - for sensor in input_cameras.sensors: - if sensor.id in used_sensor_ids: - raise RuntimeError( - "Fatal error: Repeated sensor ID found in the same %s: %s" - % (input_type_name, sensor.id) - ) - used_sensor_ids.add(sensor.id) - - sensor = _clear_unsupported_attributes(copy.deepcopy(sensor)) - sensor.id = _find_or_remap_id(sensor.id, mapping) - sensors.append(sensor) - - return sensors - - -def _merge_captures( - camera_objs: list[InputCameras], sensor_id_mappings: list[dict[Uid64, Uid64]] -) -> list[Capture]: - """Merge all captures in a single list, applying a sensor_id remapping. - It's not allowed to have two captures with the same ID in two different input camera lists - or the same camera in to different captures. - """ - captures = [] - used_capture_ids = set() - used_camera_ids = set() - - for input_cameras, mapping in zip(camera_objs, sensor_id_mappings): - for capture in input_cameras.captures: - if capture.id in used_capture_ids: - raise RuntimeError( - "Fatal error: Repeated capture found in input cameras: %s" - % capture.id - ) - used_capture_ids.add(capture.id) - capture = _clear_unsupported_attributes(copy.deepcopy(capture)) - for camera in capture.cameras: - if camera.id in used_camera_ids: - raise RuntimeError( - "Fatal error: Repeated camera found in input cameras: %s" - % camera.id - ) - used_camera_ids.add(camera.id) - camera.sensor_id = _find_or_remap_id(camera.sensor_id, mapping) - - captures.append(capture) - - return captures - - -def _merge_input_cameras(camera_objs: list[InputCameras], **kwargs) -> InputCameras: - """Merges all input cameras into a single list. - Sensor IDs are remapped to ensure that each sub project uses different IDs. Camera UIDs are not - remapped as the input lists are assumed to be using non-overlapping sets of UIDs. - :param camera_objs: a list of :class:`InputCameras` - :param kwargs: may contain an input/output `sensor_id_mappings`. This parameter is a list - of dicts to be used for reusing and/or completing the sensor id mapping. Each element in the list - is the mapping to be used for each InputCameras in the same order. - :return: a :class:`InputCameras` instance - """ - mappings = kwargs.get("sensor_id_mappings", [{} for i in range(len(camera_objs))]) - sensors = _merge_sensors(camera_objs, mappings) - captures = _merge_captures(camera_objs, mappings) - - result = InputCameras(captures=captures, sensors=sensors) - result.metadata = _merge_metadata(camera_objs) - - return result - - -def _merge_projected_sensors( - camera_objs: list[ProjectedInputCameras], - sensor_id_mappings: list[dict[Uid64, Uid64]], -) -> list[ProjectedSensor]: - return _merge_sensors(camera_objs, sensor_id_mappings, "projected input cameras") - - -def _merge_projected_captures( - camera_objs: list[ProjectedInputCameras], shifts: list[np.ndarray] -) -> list[ProjectedCapture]: - """Merge all projected captures in a single list, applying a shift to projected coordinates. - It's not allowed to have two captures with the same ID in two different projected camera lists. - """ - captures = [] - used_capture_ids = set() - - for projected_cameras, shift in zip(camera_objs, shifts): - for capture in projected_cameras.captures: - if capture.id in used_capture_ids: - raise RuntimeError( - "Fatal error: Repeated capture found in projected input cameras: %s" - % capture.id - ) - used_capture_ids.add(capture.id) - capture = _clear_unsupported_attributes(copy.deepcopy(capture)) - if capture.geolocation is not None: - capture.geolocation.position += shift - - captures.append(capture) - - return captures - - -def _merge_projected_input_cameras( - camera_objs: list[ProjectedInputCameras], **kwargs -) -> ProjectedInputCameras: - """Merges all projected input cameras into a single list. - Sensor IDs are remapped to ensure that each sub project uses different IDs. Camera UIDs are not - remapped as the input lists are assumed to be using non-overlapping sets of UIDs. - :param camera_objs: a list of :class:`ProjectedInputCameras` - :param kwargs: may contain: - * a 'shifts' parameter with the shifts to apply to projected coordinates in each item - * an input/output `sensor_id_mappings`. This parameter is a list - of dicts to be used for reusing and/or completing the sensor id mapping. Each element in - the list is the mapping to be used for each InputCameras in the same order. - :return: a :class:`ProjectedInputCameras` instance - """ - mappings = kwargs.get("sensor_id_mappings", [{} for i in range(len(camera_objs))]) - sensors = _merge_projected_sensors(camera_objs, mappings) - - shifts = kwargs.get("shifts", [np.zeros(3) for i in range(len(camera_objs))]) - captures = _merge_projected_captures(camera_objs, shifts) - - result = ProjectedInputCameras(captures=captures, sensors=sensors) - result.metadata = _merge_metadata(camera_objs) - - return result - - -def _merge_calibrated_cameras( - camera_objs: list[CalibratedCameras], **kwargs -) -> CalibratedCameras: - - mappings = kwargs.get("sensor_id_mappings", [{} for i in range(len(camera_objs))]) - shifts = kwargs.get("shifts", [np.zeros(3) for i in range(len(camera_objs))]) - - sensors = [] - cameras = [] - used_camera_ids = set() - - for calibrated_cameras, shift, mapping in zip(camera_objs, shifts, mappings): - for sensor in calibrated_cameras.sensors: - sensor = _clear_unsupported_attributes(copy.deepcopy(sensor)) - sensor.id = _find_or_remap_id(sensor.id, mapping) - sensors.append(sensor) - - for camera in calibrated_cameras.cameras: - camera = _clear_unsupported_attributes(copy.deepcopy(camera)) - if camera.id in used_camera_ids: - raise RuntimeError( - "Fatal error: Repeated camera found in calibrated cameras: %s" - % camera.id - ) - used_camera_ids.add(camera.id) - camera.sensor_id = _find_or_remap_id(camera.sensor_id, mapping) - camera.position += shift - cameras.append(camera) - - # No metadata needs to be merged or considered because this is not a top level project item - return CalibratedCameras(cameras=cameras, sensors=sensors) - - -def _merge_calibrated_control_points( - cp_objs: list[CalibratedControlPoints], **kwargs -) -> CalibratedControlPoints: - - shifts = kwargs.get("shifts", [np.zeros(3) for i in range(len(cp_objs))]) - - points = defaultdict(list) - for calibrated_cps, shift in zip(cp_objs, shifts): - for point in calibrated_cps.points: - points[point.id].append(point.coordinates + shift) - - # No metadata needs to be merged or considered because this is not a top level project item - return CalibratedControlPoints( - points=[ - CalibratedControlPoint(id=id, coordinates=np.mean(coords, 0)) - for id, coords in points.items() - ] - ) - - -def _merge_gps_bias(gps_bias_objs: list[GpsBias], **kwargs): - warnings.warn( - "GPS bias resources cannot be merged, the output will not contain any" - ) - - -def _merge_calibrations(calibrations: list[Calibration], **kwargs) -> Calibration: - - result = Calibration() - result.metadata = _merge_metadata(calibrations) - - kwargs = copy.copy(kwargs) - shifts = kwargs.pop("shifts", [np.zeros(3) for i in range(len(calibrations))]) - sensor_id_mappings = kwargs.pop( - "sensor_id_mappings", [{} for i in range(len(calibrations))] - ) - - kwargs["base_dir"] = kwargs.get("base_dir", Path(".")) / str(result.metadata.id) - - keys = { - key - for calibration in calibrations - for key in calibration.__dict__ - if not key.startswith("_") - } - for key in keys: - merged_item = _merge_subojects_by_key( - key, calibrations, shifts, sensor_id_mappings, **kwargs - ) - if merged_item: - setattr(result, key, [merged_item]) - - return result - - -def _verify_calibrated_control_point_consistency( - projects: list[ProjectObjects], **kwargs -): - """Verifies that the standard deviation of the distribution of calibrated control points positions - is consistent with the measurement error given in the input control points. - Raises an error in case of inconsistency.""" - pass - - -def _merge_point_clouds(point_clouds: list[GlTFPointCloud], **kwargs) -> GlTFPointCloud: - - shifts = kwargs.get("shifts", [np.zeros(3) for i in range(len(point_clouds))]) - base_dir = kwargs.get("base_dir", Path(".")) - - if hasattr(point_clouds[0], "metadata"): - metadata = _merge_metadata(point_clouds) - output_dir = base_dir / str(metadata.id) - else: - metadata = None - output_dir = base_dir - - result = pcl_merge.concatenate(point_clouds) - - shifts = [ - shift - for shift, point_cloud in zip(shifts, point_clouds) - for i in range(len(point_cloud.nodes)) - ] - - for node, shift in zip(result.nodes, shifts): - if not (shift == np.zeros(3)).all(): - if node.matrix is not None: - node.matrix = opf_axis_rotation_matrix_inverse @ node.matrix - node.matrix[0, 3] += shift[0] - node.matrix[1, 3] += shift[1] - node.matrix[2, 3] += shift[2] - node.matrix = opf_axis_rotation_matrix @ node.matrix - else: - # Since there was no matrix, we can't assume much about - # the origin of the data. - node.matrix = np.array( - [ - [1, 0, 0, shift[0]], - [0, 1, 0, shift[1]], - [0, 0, 1, shift[2]], - [0, 0, 0, 1], - ] - ) - - os.mkdir(output_dir) - - result = pcl_merge.collapse(result, output_dir) - if metadata: - result.metadata = metadata - - return result - - -def _merge_project_objects(projects: list[ProjectObjects], **kwargs) -> ProjectObjects: - - assert len(projects) > 1 # This is guaranteed by the public merge function - - result = ProjectObjects() - - result.metadata.name = "Merged project" - result.metadata.description = "Merge of projects: " + ", ".join( - [str(project.metadata.id) for project in projects] - ) - - # This contains the mapping from the original item UUIDs to the UUID of the merged item, - uuid_mapping = {} - - def merge_by_key(key, shifts=None, sensor_id_mappings=None, **kwargs): - - result = _merge_subojects_by_key( - key, projects, shifts, sensor_id_mappings, **kwargs - ) - - if result is None: - return None - - for project in projects: - try: - for object in getattr(project, key): - uuid_mapping[object.metadata.id] = result.metadata.id - except AttributeError: - pass - - return result - - # The scene reference frames require special treatment - scene_reference_frame = merge_by_key("scene_reference_frame_objs") - if scene_reference_frame: - setattr(result, "scene_reference_frame_objs", [scene_reference_frame]) - - if scene_reference_frame is None: - raise RuntimeError("Could not obtain the scene reference frame") - - shifts = [] - for project in projects: - if project.scene_reference_frame is not None: - shifts.append( - scene_reference_frame.base_to_canonical.shift - - project.scene_reference_frame.base_to_canonical.shift - ) - else: - shifts.append(None) - sensor_id_mappings = [{} for i in range(len(projects))] - - keys = { - key - for project in projects - for key in project.__dict__ - if key != "scene_reference_frame_objs" and not key.startswith("_") - } - for key in keys: - merged_item = merge_by_key(key, shifts, sensor_id_mappings, **kwargs) - if merged_item: - setattr(result, key, [merged_item]) - - _fix_sources(result, uuid_mapping) - _verify_calibrated_control_point_consistency(projects) - - return result - - -def _merge_projects(projects: list[Project], **kwargs): - return _merge_project_objects([resolve(project) for project in projects], **kwargs) - - -def merge(first, *rest, **kwargs): - - for x in rest: - if type(first) != type(x): - raise TypeError("Objects of mixed types cannot be merged") - - objects = [first] + list(rest) - - for t, fun in [ - (Calibration, _merge_calibrations), - (CalibratedCameras, _merge_calibrated_cameras), - (CalibratedControlPoints, _merge_calibrated_control_points), - (CameraList, _merge_camera_lists), - (Constraints, _merge_constraints), - (GlTFPointCloud, _merge_point_clouds), - (GpsBias, _merge_gps_bias), - (InputCameras, _merge_input_cameras), - (InputControlPoints, _merge_input_control_points), - (Project, _merge_projects), - (ProjectObjects, _merge_project_objects), - (ProjectedControlPoints, _merge_projected_control_points), - (ProjectedInputCameras, _merge_projected_input_cameras), - (SceneReferenceFrame, _merge_scene_reference_frames), - ]: - - if type(first) == t: - return fun(objects, **kwargs) - - raise TypeError("Unknown OPF type to merge: %s" % type(first)) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Simple OPF project merging tool") - parser.add_argument( - "input", - metavar="project.json", - type=str, - nargs="+", - help="A list of OPF project files", - ) - parser.add_argument( - "outdir", type=str, help="Output directory for the merged project" - ) - parser.add_argument( - "-f", - "--force", - dest="force", - action="store_true", - default=False, - help="Do not ask for confirmation when overwriting output files", - ) - - return parser.parse_args() - - -def main(): - - args = parse_args() - - if len(args.input) == 1: - print("Only one input project was given, is the output directory missing?") - return 0 - - output_dir = args.outdir - if os.path.exists(output_dir): - if len(os.listdir(output_dir)) != 0 and not args.force: - while True: - try: - answer = input( - "The output directory is not empty do you want to procced [yN]? " - ) - except KeyboardInterrupt: - print() - exit(-1) - except EOFError: - answer = "" - if answer == "n" or answer == "N" or answer == "": - exit(0) - if answer == "y" or answer == "Y": - break - else: - os.makedirs(output_dir) - - projects = [load(input) for input in args.input] - - merged_project = merge(*projects, base_dir=Path(output_dir)) - - save(merged_project, output_dir + "/project.opf") diff --git a/src/opf_tools/opf2colmap/__main__.py b/src/opf_tools/opf2colmap/__main__.py new file mode 100644 index 0000000..ed17ae0 --- /dev/null +++ b/src/opf_tools/opf2colmap/__main__.py @@ -0,0 +1,6 @@ +import sys + +from opf_tools.opf2colmap.converter import main + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/opf_tools/opf2colmap/converter.py b/src/opf_tools/opf2colmap/converter.py new file mode 100644 index 0000000..7b0fa26 --- /dev/null +++ b/src/opf_tools/opf2colmap/converter.py @@ -0,0 +1,433 @@ +import argparse +import os +import shutil +from urllib.parse import ParseResult, urlparse +from urllib.request import url2pathname + +import numpy as np +from PIL import Image +from tqdm import tqdm + +from pyopf.io import load +from pyopf.project import ProjectObjects +from pyopf.resolve import resolve + + +def compile_tracks(project: ProjectObjects) -> tuple[dict, list]: + """Compile tracks to have data easily usable to generate colmap files.""" + project_track = project.calibration.tracks.nodes[0] + + # create list of camera uid corresponding to each match + hex_matched_uid = np.asarray([uid.hex for uid in project_track.matches.camera_uids]) + matches_cam_uid = hex_matched_uid[project_track.matches.camera_ids.flatten()] + # create lists of projected tracks (2d coordinates) per image + argsort_matches_cam_uid = np.argsort(matches_cam_uid) + camd_uids, uid_to_idx = np.unique( + matches_cam_uid[argsort_matches_cam_uid], return_index=True + ) + coords_2d = np.split( + project_track.matches.image_points.pixelCoordinates[argsort_matches_cam_uid], + uid_to_idx[1:], + ) + # create lists of 3d point IDs corresponding to the projected tracks + idx_range = np.asarray(project_track.matches.point_index_ranges) + argsort_matches = np.argsort(idx_range[:, 0]) + point3D_id = np.split( + np.repeat(argsort_matches, idx_range[:, 1][argsort_matches])[ + argsort_matches_cam_uid + ], + uid_to_idx[1:], + ) + point3D_id = np.array(point3D_id, dtype=object) + # create dictionary: camera_uid -> (list of projected tracks, list of point3D_id) + tracks_2Dcoords = dict(zip(camd_uids, zip(coords_2d, point3D_id))) + + # create lists of camera uids per track, and corresponding index + track_cam_uids = np.empty(len(project_track), dtype=object) + track_cam_uids[...] = [[] for _ in range(track_cam_uids.shape[0])] + track_indices = np.empty(len(project_track), dtype=object) + track_indices[...] = [[] for _ in range(track_indices.shape[0])] + # fill in from the already generated point3D_id + for cam_uid, points3D in tqdm(zip(camd_uids, point3D_id), total=len(camd_uids)): + for track_index, track in enumerate(points3D): + track_cam_uids[track].append(cam_uid) + track_indices[track].append(track_index) + # create track list where each row index is a point3d_id: (list of camera uids, list of indices) + tracks_attributes = list(zip(track_cam_uids, track_indices)) + + return tracks_2Dcoords, tracks_attributes + + +def orient_pos_computation( + orient_deg: np.ndarray, position: np.ndarray +) -> tuple[np.ndarray, np.ndarray]: + """Transform orientation and position of OPF cameras to colmap format.""" + orient_rad = np.deg2rad(orient_deg) + + cosO = np.cos(orient_rad[0]) + sinO = np.sin(orient_rad[0]) + cosP = np.cos(orient_rad[1]) + sinP = np.sin(orient_rad[1]) + cosK = np.cos(orient_rad[2]) + sinK = np.sin(orient_rad[2]) + + rot = np.zeros((3, 3), dtype=np.float64) + rot[0][0] = cosP * cosK + rot[0][1] = cosO * sinK + sinO * sinP * cosK + rot[0][2] = sinO * sinK - cosO * sinP * cosK + rot[1][0] = cosP * sinK + rot[1][1] = -cosO * cosK + sinO * sinP * sinK + rot[1][2] = -sinO * cosK - cosO * sinP * sinK + rot[2][0] = -sinP + rot[2][1] = sinO * cosP + rot[2][2] = -cosO * cosP + + quat = np.zeros(4) + quat[0] = 0.5 * np.sqrt(1 + rot[0][0] + rot[1][1] + rot[2][2]) + quat[1] = (rot[2][1] - rot[1][2]) / (4 * quat[0]) + quat[2] = (rot[0][2] - rot[2][0]) / (4 * quat[0]) + quat[3] = (rot[1][0] - rot[0][1]) / (4 * quat[0]) + + pos = np.matmul(-rot, position) + return quat, pos + + +def generate_cameras( + project: ProjectObjects, sensors_uid_to_id: dict, user_config: dict +) -> None: + """Generate the colmap file 'cameras.txt', storing sensors information.""" + sensors = project.calibration.calibrated_cameras.sensors + + file_header = "Camera list with one line of data per camera:\n" + file_header += " CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]\n" + file_header += " FULL_OPENCV model: CAMERA_ID FULL_OPENCV WIDTH HEIGHT fx fy cx cy k1 k2 p1 p2 k3 k4 k5 k6\n" + file_header += "Number of cameras: " + str(len(sensors)) + + cameras_data = np.zeros( + len(sensors), + dtype=[ + ("id", np.int32), + ("model", " None: + """Generate the colmap file 'images.txt', storing cameras information.""" + cameras = project.calibration.calibrated_cameras.cameras + + tracks_count_per_camera = [ + len(point3D_ids) for _, point3D_ids in tracks_2Dcoords.values() + ] + + file_header = "Image list with two lines of data per image:\n" + file_header += " IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME\n" + file_header += " POINTS2D[] as (X, Y, POINT3D_ID)\n" + file_header += ( + "Number of images: " + + str(len(cameras)) + + " , mean observations per image: " + + str(sum(tracks_count_per_camera) / len(tracks_count_per_camera)) + ) + + images_data = np.full(2 * len(cameras), "", dtype=object) + + for row, camera in enumerate(cameras): + image_filename = cam_paths_dict[camera.id]["output_relative"] + orient, pos = orient_pos_computation(camera.orientation_deg, camera.position) + + track_list = [0] * (3 * len(tracks_2Dcoords[camera.id.hex][1])) + track_list[::3] = tracks_2Dcoords[camera.id.hex][0][:, 0] + track_list[1::3] = tracks_2Dcoords[camera.id.hex][0][:, 1] + track_list[2::3] = tracks_2Dcoords[camera.id.hex][1][:] + + images_data[2 * row] = f"{cameras_uid_to_id[camera.id.hex]}" + images_data[ + 2 * row + ] += f" {' '.join(map(str, orient))} {' '.join(map(str, pos))}" + images_data[ + 2 * row + ] += f" {sensors_uid_to_id[camera.sensor_id.hex]} {image_filename}" + images_data[2 * row + 1] = " ".join(map(str, track_list)) + + output_file = os.path.join(user_config["out_dir"], "images.txt") + np.savetxt(output_file, images_data, fmt="%s", header=file_header) + + +def generate_points3D( + project: ProjectObjects, + camera_uid_to_id: dict, + tracks_attributes: list, + user_config: dict, +) -> None: + """Generate the colmap file 'points3D.txt', storing tracks information.""" + tracks = project.calibration.tracks.nodes[0] + + cameras_per_track = list(map(lambda track: len(track[0]), tracks_attributes)) + + tracks_color = np.zeros((len(tracks), 3), dtype=np.uint8) + if project.calibration.tracks.nodes[0].color is not None: + tracks_color = project.calibration.tracks.nodes[0].color[:, 0:3] + + file_header = "3D point list with one line of data per point:\n" + file_header += ( + " POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)\n" + ) + file_header += ( + "Number of points: " + + str(len(tracks)) + + ", mean track length: " + + str(sum(cameras_per_track) / len(cameras_per_track)) + ) + + track_image_data = np.full(len(tracks), "", dtype=object) + + # correction because gltf assumes Y is up, colmap assumes Z is up + rotation_matrix = np.array( + [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=np.float64 + ) + # apply rotation correction and gltf node transform + positions_aug = np.c_[tracks.position.astype(np.float64), np.ones(len(tracks))] + positions_aug = ( + rotation_matrix @ (tracks.matrix.astype(np.float64) @ positions_aug.T) + ).T + tracks_position = positions_aug[:, 0:3] + + for point3D_id in range(len(tracks)): + image_point2d_list = [0] * (2 * len(tracks_attributes[point3D_id][0])) + image_point2d_list[::2] = map( + camera_uid_to_id.get, tracks_attributes[point3D_id][0] + ) + image_point2d_list[1::2] = tracks_attributes[point3D_id][1] + track_image_data[point3D_id] = " ".join(map(str, image_point2d_list)) + + points3D_data = np.column_stack( + ( + np.arange(len(tracks)), + tracks_position, + tracks_color, + np.zeros(len(tracks)), + track_image_data, + ) + ) + + output_file = os.path.join(user_config["out_dir"], "points3D.txt") + np.savetxt(output_file, points3D_data, fmt="%s", header=file_header) + + +def generate_colmap( + project: ProjectObjects, + user_config: dict, + cam_paths_dict: dict, +) -> None: + """Generate the colmap files 'cameras.txt', 'images.txt', and 'points3D.txt' from the OPF project.""" + list_sensor_hex = [ + sensor.id.hex for sensor in project.calibration.calibrated_cameras.sensors + ] + sensors_uid_to_id = dict(zip(list_sensor_hex, np.arange(len(list_sensor_hex)) + 1)) + + list_cam_hex = [ + camera.id.hex for camera in project.calibration.calibrated_cameras.cameras + ] + cameras_uid_to_id = dict(zip(list_cam_hex, np.arange(len(list_cam_hex)) + 1)) + + tracks_2Dcoords, tracks_attributes = compile_tracks(project) + + os.makedirs(user_config["out_dir"], exist_ok=True) + generate_cameras(project, sensors_uid_to_id, user_config) + generate_images( + project, + sensors_uid_to_id, + cameras_uid_to_id, + tracks_2Dcoords, + cam_paths_dict, + user_config, + ) + generate_points3D(project, cameras_uid_to_id, tracks_attributes, user_config) + + +def cam_input_output_paths( + project: ProjectObjects, opf_project_folder: str, user_config: dict +) -> dict: + """Compute/store the input and output paths (in absolute) of images. If output + paths are different from input, copy the tree structure of input images. + """ + cam_in_out_paths_dict = {} + + for camera in project.calibration.calibrated_cameras.cameras: + camera_uri = [ + temp_camera.uri + for temp_camera in project.camera_list.cameras + if temp_camera.id == camera.id + ][0] + cam_input_path = url2pathname(urlparse(camera_uri).path) + if not os.path.isabs(cam_input_path): + # if path relative to opf_project_folder, make absolute + cam_input_path = os.path.abspath( + os.path.join(opf_project_folder, cam_input_path) + ) + + cam_in_out_paths_dict[camera.id] = {"input": cam_input_path} + + common_input_prefix = os.path.commonpath( + [paths["input"] for paths in cam_in_out_paths_dict.values()] + ) + + for camera in project.calibration.calibrated_cameras.cameras: + cam_output_path = cam_in_out_paths_dict[camera.id]["input"] + + cam_in_out_paths_dict[camera.id]["output_relative"] = os.path.relpath( + cam_output_path, common_input_prefix + ) + + if user_config["out_img_dir"] is not None: + # remove from paths common path, and add copy dir + cam_output_path = os.path.join( + os.path.abspath(user_config["out_img_dir"]), + os.path.relpath(cam_output_path, common_input_prefix), + ) + cam_in_out_paths_dict[camera.id]["output"] = cam_output_path + + return cam_in_out_paths_dict + + +def file_is_local(url: ParseResult) -> bool: + """Check if file is stored locally.""" + return (url.hostname is None or url.hostname == "localhost") and ( + url.scheme == "file" or url.scheme == "" + ) + + +def check_project_supported(project: ProjectObjects) -> None: + """Check that the project is supported by this converter tool.""" + # check project is calibrated + if ( + (project.input_cameras is None) + or (project.camera_list is None) + or (project.calibration is None) + or (project.calibration.calibrated_cameras is None) + ): + raise ValueError("Only calibrated projects can be converted") + + # check all sensors are perspective + for sensor in project.calibration.calibrated_cameras.sensors: + if sensor.internals.type != "perspective": + raise ValueError("Only perspective sensors are supported.") + + # check if all cameras are stored locally + list_camera_url = [urlparse(camera.uri) for camera in project.camera_list.cameras] + if not all(file_is_local(url) for url in list_camera_url): + raise ValueError("Remote files are not supported.") + + +def copy_images(project: ProjectObjects, cam_paths_dict: dict) -> None: + """Copy images to output image directory.""" + pbar = tqdm(project.calibration.calibrated_cameras.cameras) + for camera in pbar: + pbar.set_postfix_str( + os.path.basename(cam_paths_dict[camera.id]["input"]) + + "->" + + cam_paths_dict[camera.id]["output"] + ) + + os.makedirs(os.path.dirname(cam_paths_dict[camera.id]["output"]), exist_ok=True) + + shutil.copyfile( + cam_paths_dict[camera.id]["input"], cam_paths_dict[camera.id]["output"] + ) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Convert an OPF project to a sparse colmap model, consisting of three files: cameras, images and points3D.\ + These will contain information about the intrinsic and extrinsic parameters of the cameras, as well as the tracks. ", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + parser.add_argument( + "opf_project", + type=str, + help="An OPF project file", + ) + + parser.add_argument( + "--out-dir", + type=str, + default=".", + help="Output folder of colmap model.", + ) + + parser.add_argument( + "--out-img-dir", + type=str, + default=None, + help="If specified, the images will be copied to this directory.", + ) + + return parser.parse_args() + + +def main(): + args = parse_args() + user_config = { + "out_dir": args.out_dir, + "out_img_dir": args.out_img_dir, + } + + opf_project = args.opf_project + opf_project_folder = os.path.dirname(opf_project) + project = load(opf_project) + project = resolve(project) + cam_paths_dict = cam_input_output_paths(project, opf_project_folder, user_config) + + check_project_supported(project) + + print("Generating colmap files:") + generate_colmap(project, user_config, cam_paths_dict) + + if args.out_img_dir is not None: + print("Copying images:") + copy_images(project, cam_paths_dict) diff --git a/src/opf_tools/merge/__main__.py b/src/opf_tools/opf2las/__main__.py similarity index 57% rename from src/opf_tools/merge/__main__.py rename to src/opf_tools/opf2las/__main__.py index 21ac314..44c3d37 100644 --- a/src/opf_tools/merge/__main__.py +++ b/src/opf_tools/opf2las/__main__.py @@ -1,6 +1,6 @@ import sys -from opf_tools.merge.merger import main +from opf_tools.opf2las.converter import main if __name__ == "__main__": sys.exit(main()) diff --git a/src/opf_tools/opf2las/converter.py b/src/opf_tools/opf2las/converter.py new file mode 100644 index 0000000..60b75cc --- /dev/null +++ b/src/opf_tools/opf2las/converter.py @@ -0,0 +1,130 @@ +import argparse +from enum import Enum +from pathlib import Path + +import laspy +from pyproj import CRS + +from pyopf.crs.crs import Crs +from pyopf.formats import CoreFormat +from pyopf.io import load +from pyopf.pointcloud.pcl import GlTFPointCloud +from pyopf.pointcloud.utils import apply_affine_transform +from pyopf.resolve import resolve + +LAS_FILE_EXTENSION = ".las" +LAS_VERSION = laspy.header.Version(1, 4) +PF_WITHOUT_COLOR = laspy.PointFormat(1) +PF_WITH_COLOR = laspy.PointFormat(2) + +PRECISION = 10000 # 10^coords_decimals_to_keep + + +class Dim(str, Enum): + """Dimension names to use with the PointRecord class from laspy.""" + + X = "X" + Y = "Y" + Z = "Z" + R = "red" + G = "green" + B = "blue" + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Export a LAS 1.4 pointcloud file from an OPF project.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + parser.add_argument( + "opf_path", + type=str, + help="[REQUIRED] The path to your project.opf file.", + ) + + parser.add_argument( + "--out-dir", + "-o", + type=str, + default=str(Path.cwd()), + help="Output folder for the converted file.", + ) + + return parser.parse_args() + + +def gltf_to_las( + gltf: GlTFPointCloud, output_path: Path, crs: Crs | None = None +) -> None: + """Write a LAS pointcloud from a GlTFPointCloud object and an optional Crs.""" + + point_format = ( + PF_WITH_COLOR if gltf.nodes[0].color is not None else PF_WITHOUT_COLOR + ) + + header = laspy.header.LasHeader(version=LAS_VERSION) + header.offset = [0 for coord in range(3)] + header.scale = [1 / PRECISION for coord in range(3)] + + if crs is not None: + crs = CRS.from_wkt(crs.definition) + try: + header.add_crs(crs) + except RuntimeError: + print( + "CRS issue, the output LAS file will be written without georeferencing." + ) + + header.point_format = point_format + + las = laspy.create(point_format=point_format, file_version=LAS_VERSION) + las.header = header + las.write(str(output_path)) + + COORDINATES = [Dim.X, Dim.Y, Dim.Z] + COLORS = [Dim.R, Dim.G, Dim.B] + + for chunk in gltf.chunk_iterator(yield_indices=False): + apply_affine_transform(chunk.position, chunk.matrix) + coords = chunk.position.transpose() * PRECISION + colors = chunk.color.transpose() + + point_record = laspy.PackedPointRecord.empty(point_format) + for i in range(3): + point_record[COORDINATES[i]] = coords[i] + point_record[COLORS[i]] = colors[i] + + with laspy.open(output_path, "a") as file: + file.append_points(point_record) + + +def main(): + args = parse_args() + + opf_path = args.opf_path + + project = load(opf_path) + resolved_project = resolve(project) + pointcloud_counter = 0 + for item in project.items: + for resource in item.resources: + if resource.format == CoreFormat.GLTF_MODEL: + gltf_path = Path(opf_path).parent / resource.uri + output_path = ( + Path(args.out_dir) + / f"{project.name}_{item.name}_{pointcloud_counter}{LAS_FILE_EXTENSION}" + ) + pointcloud_counter += 1 + + print(f"Converting pointcloud {gltf_path} to {output_path}") + + gltf = GlTFPointCloud.open(gltf_path) + gltf_to_las( + gltf, output_path, resolved_project.scene_reference_frame.crs + ) + print(f"LAS file successfully written: {output_path}\n") + + +if __name__ == "__main__": + main() diff --git a/src/opf_tools/opf2ply/__main__.py b/src/opf_tools/opf2ply/__main__.py new file mode 100644 index 0000000..44c3d37 --- /dev/null +++ b/src/opf_tools/opf2ply/__main__.py @@ -0,0 +1,6 @@ +import sys + +from opf_tools.opf2las.converter import main + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/opf_tools/opf2ply/converter.py b/src/opf_tools/opf2ply/converter.py new file mode 100644 index 0000000..481f09c --- /dev/null +++ b/src/opf_tools/opf2ply/converter.py @@ -0,0 +1,108 @@ +import argparse +from pathlib import Path +from tempfile import mkdtemp + +import numpy as np +from plyfile import PlyData, PlyElement + +from pyopf.formats import CoreFormat +from pyopf.io import load +from pyopf.pointcloud import GlTFPointCloud +from pyopf.pointcloud.utils import apply_affine_transform + +PLY_FILE_EXTENSION = ".ply" + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Export all point clouds from an OPF project as PLY files.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + parser.add_argument( + "opf_path", + type=str, + help="[REQUIRED] The path to your project.opf file.", + ) + + parser.add_argument( + "--out-dir", + "-o", + type=str, + default=str(Path.cwd()), + help="Output folder for the converted file.", + ) + + return parser.parse_args() + + +def gltf_to_ply(gltf: GlTFPointCloud, output_path: Path) -> None: + """Write a PLY pointcloud from a GlTFPointCloud object.""" + + COORDS_DTYPE = "f4" + COLORS_DTYPE = "u1" + NORMALS_DTYPE = "f4" + + dtype = [(coord, COORDS_DTYPE) for coord in ["x", "y", "z"]] + + total_gltf_len = sum([len(node) for node in gltf.nodes]) + if total_gltf_len: + node = gltf.nodes[0] + + has_color = node.color is not None + has_normal = node.normal is not None + + if has_color: + dtype += [(color, COLORS_DTYPE) for color in ["red", "green", "blue"]] + + if has_normal: + dtype += [(axis, NORMALS_DTYPE) for axis in ["nx", "ny", "nz"]] + + points = np.memmap( + mkdtemp() / Path("tempfile"), + dtype=dtype, + mode="w+", + shape=total_gltf_len, + ) + + for chunk, start, end in gltf.chunk_iterator(): + apply_affine_transform(chunk.position, chunk.matrix) + + points[start:end] = list( + zip( + *[chunk.position[:, i] for i in range(3)], + *[chunk.color[:, i] for i in range(3) if has_color], + *[chunk.normal[:, i] for i in range(3) if has_normal], + ) + ) + + elements = [PlyElement.describe(points, "vertex")] + + PlyData(elements).write(str(output_path)) + + +def main(): + args = parse_args() + + opf_path = args.opf_path + + project = load(opf_path) + pointcloud_counter = 0 + for item in project.items: + for resource in item.resources: + if resource.format == CoreFormat.GLTF_MODEL: + gltf_path = Path(opf_path).parent / resource.uri + output_path = ( + Path(args.out_dir) + / f"{project.name}_{item.name}_{pointcloud_counter}{PLY_FILE_EXTENSION}" + ) + pointcloud_counter += 1 + + print(f"Converting pointcloud {gltf_path} to {output_path}") + + gltf = GlTFPointCloud.open(gltf_path) + gltf_to_ply(gltf, output_path) + + +if __name__ == "__main__": + main() diff --git a/src/pyopf/VersionInfo.py b/src/pyopf/VersionInfo.py index 33a0830..d69c061 100644 --- a/src/pyopf/VersionInfo.py +++ b/src/pyopf/VersionInfo.py @@ -81,6 +81,17 @@ def parse(cls, version: str): return cls(major, minor, prerelease) + def compatible_with(self, other): + if self.major != other.major or self.prerelease != other.prerelease: + return False + if self.major > 0: + if self.prerelease is not None and self.minor != other.minor: + return False + elif self.major == 0 and self.minor != other.minor: + return False + + return True + def __eq__(self, other): return self.to_tuple() == other.to_tuple() diff --git a/src/pyopf/cameras/calibrated_cameras.py b/src/pyopf/cameras/calibrated_cameras.py index c594e5d..eaa738a 100644 --- a/src/pyopf/cameras/calibrated_cameras.py +++ b/src/pyopf/cameras/calibrated_cameras.py @@ -59,13 +59,13 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "CalibratedCamera": assert isinstance(obj, dict) - id = Uid64(int=int(obj.get("id"))) - orientation_deg = vector_from_list(obj.get("orientation_deg"), 3, 3) - position = vector_from_list(obj.get("position"), 3, 3) + id = Uid64(int=int(obj["id"])) + orientation_deg = vector_from_list(obj["orientation_deg"], 3, 3) + position = vector_from_list(obj["position"], 3, 3) rolling_shutter = from_union( [lambda x: vector_from_list(x, 3, 3), from_none], obj.get("rolling_shutter") ) - sensor_id = Uid64(int=int(obj.get("sensor_id"))) + sensor_id = Uid64(int=int(obj["sensor_id"])) result = CalibratedCamera( id, sensor_id, orientation_deg, position, rolling_shutter ) @@ -107,8 +107,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "CalibratedRigRelatives": assert isinstance(obj, dict) - rotation_angles_deg = vector_from_list(obj.get("rotation_angles_deg"), 3, 3) - translation = vector_from_list(obj.get("translation"), 3, 3) + rotation_angles_deg = vector_from_list(obj["rotation_angles_deg"], 3, 3) + translation = vector_from_list(obj["translation"], 3, 3) result = CalibratedRigRelatives(rotation_angles_deg, translation) result._extract_unknown_properties_and_extensions(obj) return result @@ -142,14 +142,14 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "CalibratedSensor": assert isinstance(obj, dict) - id = Uid64(int=int(obj.get("id"))) + id = Uid64(int=int(obj["id"])) internals = from_union( [ SphericalInternals.from_dict, PerspectiveInternals.from_dict, FisheyeInternals.from_dict, ], - obj.get("internals"), + obj["internals"], ) rig_relatives = from_union( [CalibratedRigRelatives.from_dict, from_none], obj.get("rig_relatives") @@ -182,19 +182,19 @@ def __init__( self, cameras: List[CalibratedCamera], sensors: List[CalibratedSensor], - format: CoreFormat = CoreFormat.CALIBRATED_CAMERAS, + pformat: CoreFormat = CoreFormat.CALIBRATED_CAMERAS, version: VersionInfo = FormatVersion.CALIBRATED_CAMERAS, ) -> None: - super(CalibratedCameras, self).__init__(format=format, version=version) - + super(CalibratedCameras, self).__init__(format=pformat, version=version) + assert self.format == CoreFormat.CALIBRATED_CAMERAS self.cameras = cameras self.sensors = sensors @staticmethod def from_dict(obj: Any) -> "CalibratedCameras": base = CoreItem.from_dict(obj) - cameras = from_list(CalibratedCamera.from_dict, obj.get("cameras")) - sensors = from_list(CalibratedSensor.from_dict, obj.get("sensors")) + cameras = from_list(CalibratedCamera.from_dict, obj["cameras"]) + sensors = from_list(CalibratedSensor.from_dict, obj["sensors"]) result = CalibratedCameras(cameras, sensors, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cameras/camera_list.py b/src/pyopf/cameras/camera_list.py index ed003dd..d5e32c3 100644 --- a/src/pyopf/cameras/camera_list.py +++ b/src/pyopf/cameras/camera_list.py @@ -28,8 +28,8 @@ def __init__(self, id: Uid64, uri: str) -> None: @staticmethod def from_dict(obj: Any) -> "CameraData": assert isinstance(obj, dict) - id = Uid64(int=int(obj.get("id"))) - uri = from_str(obj.get("uri")) + id = Uid64(int=int(obj["id"])) + uri = from_str(obj["uri"]) result = CameraData(id, uri) result._extract_unknown_properties_and_extensions(obj) return result @@ -50,18 +50,17 @@ class CameraList(CoreItem): def __init__( self, cameras: List[CameraData], - format: CoreFormat = CoreFormat.CAMERA_LIST, + pformat: CoreFormat = CoreFormat.CAMERA_LIST, version: VersionInfo = FormatVersion.CAMERA_LIST, ) -> None: - super(CameraList, self).__init__(format=format, version=version) - + super(CameraList, self).__init__(format=pformat, version=version) assert self.format == CoreFormat.CAMERA_LIST self.cameras = cameras @staticmethod def from_dict(obj: Any) -> "CameraList": base = CoreItem.from_dict(obj) - cameras = from_list(CameraData.from_dict, obj.get("cameras")) + cameras = from_list(CameraData.from_dict, obj["cameras"]) result = CameraList(cameras, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cameras/gps_bias.py b/src/pyopf/cameras/gps_bias.py index 57eb738..cc448e2 100644 --- a/src/pyopf/cameras/gps_bias.py +++ b/src/pyopf/cameras/gps_bias.py @@ -1,11 +1,10 @@ -from typing import Any, Dict, List, Optional +from typing import Any import numpy as np from ..formats import CoreFormat from ..items import CoreItem from ..types import OpfObject, VersionInfo -from ..uid64 import Uid64 from ..util import from_float, from_list, to_class, to_float, vector_from_list from ..versions import FormatVersion, format_and_version_to_type @@ -34,9 +33,9 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "RigidTransformationWithScaling": assert isinstance(obj, dict) - rotation_deg = vector_from_list(obj.get("rotation_deg"), 3, 3) - scale = from_float(obj.get("scale")) - translation = vector_from_list(obj.get("translation"), 3, 3) + rotation_deg = vector_from_list(obj["rotation_deg"], 3, 3) + scale = from_float(obj["scale"]) + translation = vector_from_list(obj["translation"], 3, 3) result = RigidTransformationWithScaling(rotation_deg, scale, translation) result._extract_unknown_properties_and_extensions(obj) return result @@ -63,16 +62,17 @@ class GpsBias(CoreItem): def __init__( self, transform: RigidTransformationWithScaling, - format: CoreFormat = CoreFormat.GPS_BIAS, + pformat: CoreFormat = CoreFormat.GPS_BIAS, version: VersionInfo = FormatVersion.GPS_BIAS, ) -> None: - super(GpsBias, self).__init__(format=format, version=version) + super(GpsBias, self).__init__(format=pformat, version=version) + assert self.format == CoreFormat.GPS_BIAS self.transform = transform @staticmethod def from_dict(obj: Any) -> "GpsBias": base = CoreItem.from_dict(obj) - transform = RigidTransformationWithScaling.from_dict(obj.get("transform")) + transform = RigidTransformationWithScaling.from_dict(obj["transform"]) result = GpsBias(transform, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cameras/input_cameras.py b/src/pyopf/cameras/input_cameras.py index 3b607bc..7ddfdaa 100644 --- a/src/pyopf/cameras/input_cameras.py +++ b/src/pyopf/cameras/input_cameras.py @@ -66,8 +66,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "StaticPixelRange": assert isinstance(obj, dict) - max = from_float(obj.get("max")) - min = from_float(obj.get("min")) + max = from_float(obj["max"]) + min = from_float(obj["min"]) result = StaticPixelRange(min, max) result._extract_unknown_properties_and_extensions(obj) return result @@ -103,7 +103,7 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "DynamicPixelRange": assert isinstance(obj, dict) - percentile = from_float(obj.get("percentile")) + percentile = from_float(obj["percentile"]) result = DynamicPixelRange(percentile) result._extract_unknown_properties_and_extensions(obj) return result @@ -166,17 +166,17 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Camera": assert isinstance(obj, dict) - id = Uid64(int=int(obj.get("id"))) + id = Uid64(int=int(obj["id"])) image_orientation = from_union( [from_int, from_none], obj.get("image_orientation") ) - model_source = ModelSource(obj.get("model_source")) + model_source = ModelSource(obj["model_source"]) pixel_range = from_union( [StaticPixelRange.from_dict, DynamicPixelRange.from_dict], - obj.get("pixel_range"), + obj["pixel_range"], ) - pixel_type = PixelType(obj.get("pixel_type")) - sensor_id = Uid64(int=int(obj.get("sensor_id"))) + pixel_type = PixelType(obj["pixel_type"]) + sensor_id = Uid64(int=int(obj["sensor_id"])) result = Camera( id, model_source, @@ -230,10 +230,10 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "YprOrientation": assert isinstance(obj, dict) - assert obj.get("type") == YprOrientation.type + assert obj["type"] == YprOrientation.type - angles_deg = vector_from_list(obj.get("angles_deg"), 3, 3) - sigmas_deg = vector_from_list(obj.get("sigmas_deg"), 3, 3) + angles_deg = vector_from_list(obj["angles_deg"], 3, 3) + sigmas_deg = vector_from_list(obj["sigmas_deg"], 3, 3) result = YprOrientation(angles_deg, sigmas_deg) result._extract_unknown_properties_and_extensions(obj) return result @@ -276,11 +276,11 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "OpkOrientation": assert isinstance(obj, dict) - assert obj.get("type") == OpkOrientation.type + assert obj["type"] == OpkOrientation.type - angles_deg = vector_from_list(obj.get("angles_deg"), 3, 3) - sigmas_deg = vector_from_list(obj.get("sigmas_deg"), 3, 3) - crs = from_str(obj.get("crs")) + angles_deg = vector_from_list(obj["angles_deg"], 3, 3) + sigmas_deg = vector_from_list(obj["sigmas_deg"], 3, 3) + crs = from_str(obj["crs"]) result = OpkOrientation(angles_deg, sigmas_deg, crs) result._extract_unknown_properties_and_extensions(obj) @@ -349,21 +349,21 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Capture": assert isinstance(obj, dict) - cameras = from_list(Camera.from_dict, obj.get("cameras")) + cameras = from_list(Camera.from_dict, obj["cameras"]) geolocation = from_union( [Geolocation.from_dict, from_none], obj.get("geolocation") ) height_above_takeoff_m = from_union( [from_float, from_none], obj.get("height_above_takeoff_m") ) - id = Uid64(int=int(obj.get("id"))) + id = Uid64(int=obj["id"]) orientation = from_union( [YprOrientation.from_dict, OpkOrientation.from_dict, from_none], obj.get("orientation"), ) - reference_camera_id = Uid64(int=int(obj.get("reference_camera_id"))) - rig_model_source = RigModelSource(obj.get("rig_model_source")) - time = dateutil.parser.isoparse(str(obj.get("time"))) + reference_camera_id = Uid64(int=int(obj["reference_camera_id"])) + rig_model_source = RigModelSource(obj["rig_model_source"]) + time = dateutil.parser.isoparse(str(obj["time"])) result = Capture( id, cameras, @@ -420,7 +420,7 @@ def __init__( def from_dict(obj: Any) -> "BandInformation": assert isinstance(obj, dict) name = from_union([from_str, from_none], obj.get("name")) - weight = from_float(obj.get("weight")) + weight = from_float(obj["weight"]) result = BandInformation(weight, name) result._extract_unknown_properties_and_extensions(obj) return result @@ -483,23 +483,23 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Sensor": assert isinstance(obj, dict) - bands = from_list(BandInformation.from_dict, obj.get("bands")) - id = Uid64(int=int(obj.get("id"))) - image_size_px = vector_from_list(obj.get("image_size_px"), 2, 2, dtype=int) + bands = from_list(BandInformation.from_dict, obj["bands"]) + id = Uid64(int=int(obj["id"])) + image_size_px = vector_from_list(obj["image_size_px"], 2, 2, dtype=int) internals = from_union( [ SphericalInternals.from_dict, PerspectiveInternals.from_dict, FisheyeInternals.from_dict, ], - obj.get("internals"), + obj["internals"], ) - name = from_str(obj.get("name")) - pixel_size_um = from_float(obj.get("pixel_size_um")) + name = from_str(obj["name"]) + pixel_size_um = from_float(obj["pixel_size_um"]) rig_relatives = from_union( [InputRigRelatives.from_dict, from_none], obj.get("rig_relatives") ) - shutter_type = ShutterType(obj.get("shutter_type")) + shutter_type = ShutterType(obj["shutter_type"]) result = Sensor( id, name, @@ -544,11 +544,11 @@ def __init__( self, captures: List[Capture], sensors: List[Sensor], - format: CoreFormat = CoreFormat.INPUT_CAMERAS, + pformat: CoreFormat = CoreFormat.INPUT_CAMERAS, version: VersionInfo = FormatVersion.INPUT_CAMERAS, ) -> None: - super(InputCameras, self).__init__(format=format, version=version) - + super(InputCameras, self).__init__(format=pformat, version=version) + assert self.format == CoreFormat.INPUT_CAMERAS self.captures = captures self.sensors = sensors @@ -556,8 +556,8 @@ def __init__( def from_dict(obj: Any) -> "InputCameras": base = CoreItem.from_dict(obj) - captures = from_list(Capture.from_dict, obj.get("captures")) - sensors = from_list(Sensor.from_dict, obj.get("sensors")) + captures = from_list(Capture.from_dict, obj["captures"]) + sensors = from_list(Sensor.from_dict, obj["sensors"]) result = InputCameras(captures, sensors, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cameras/input_rig_relatives.py b/src/pyopf/cameras/input_rig_relatives.py index 52492db..7740b81 100644 --- a/src/pyopf/cameras/input_rig_relatives.py +++ b/src/pyopf/cameras/input_rig_relatives.py @@ -26,8 +26,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "RigRelativeRotation": assert isinstance(obj, dict) - angles_deg = vector_from_list(obj.get("angles_deg"), 3, 3) - sigmas_deg = vector_from_list(obj.get("sigmas_deg"), 3, 3) + angles_deg = vector_from_list(obj["angles_deg"], 3, 3) + sigmas_deg = vector_from_list(obj["sigmas_deg"], 3, 3) result = RigRelativeRotation(angles_deg, sigmas_deg) result._extract_unknown_properties_and_extensions(obj) return result @@ -57,8 +57,8 @@ def __init__(self, sigmas_m: np.ndarray, values_m: np.ndarray) -> None: @staticmethod def from_dict(obj: Any) -> "RigRelativeTranslation": assert isinstance(obj, dict) - sigmas_m = vector_from_list(obj.get("sigmas_m"), 3, 3) - values_m = vector_from_list(obj.get("values_m"), 3, 3) + sigmas_m = vector_from_list(obj["sigmas_m"], 3, 3) + values_m = vector_from_list(obj["values_m"], 3, 3) result = RigRelativeTranslation(sigmas_m, values_m) result._extract_unknown_properties_and_extensions(obj) return result @@ -91,8 +91,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "InputRigRelatives": assert isinstance(obj, dict) - rotation = RigRelativeRotation.from_dict(obj.get("rotation")) - translation = RigRelativeTranslation.from_dict(obj.get("translation")) + rotation = RigRelativeRotation.from_dict(obj["rotation"]) + translation = RigRelativeTranslation.from_dict(obj["translation"]) result = InputRigRelatives(rotation, translation) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cameras/projected_input_cameras.py b/src/pyopf/cameras/projected_input_cameras.py index 277472a..64a4759 100644 --- a/src/pyopf/cameras/projected_input_cameras.py +++ b/src/pyopf/cameras/projected_input_cameras.py @@ -37,8 +37,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectedGeolocation": assert isinstance(obj, dict) - position = vector_from_list(obj.get("position"), 3, 3) - sigmas = vector_from_list(obj.get("sigmas"), 3, 3) + position = vector_from_list(obj["position"], 3, 3) + sigmas = vector_from_list(obj["sigmas"], 3, 3) result = ProjectedGeolocation(position, sigmas) result._extract_unknown_properties_and_extensions(obj) return result @@ -72,8 +72,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectedOrientation": assert isinstance(obj, dict) - angles_deg = vector_from_list(obj.get("angles_deg"), 3, 3) - sigmas_deg = vector_from_list(obj.get("sigmas_deg"), 3, 3) + angles_deg = vector_from_list(obj["angles_deg"], 3, 3) + sigmas_deg = vector_from_list(obj["sigmas_deg"], 3, 3) result = ProjectedOrientation(angles_deg, sigmas_deg) result._extract_unknown_properties_and_extensions(obj) return result @@ -110,7 +110,7 @@ def from_dict(obj: Any) -> "ProjectedCapture": geolocation = from_union( [ProjectedGeolocation.from_dict, from_none], obj.get("geolocation") ) - id = Uid64(int=int(obj.get("id"))) + id = Uid64(int=int(obj["id"])) orientation = from_union( [ProjectedOrientation.from_dict, from_none], obj.get("orientation") ) @@ -157,8 +157,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectedRigTranslation": assert isinstance(obj, dict) - sigmas = vector_from_list(obj.get("sigmas"), 3, 3) - values = vector_from_list(obj.get("values"), 3, 3) + sigmas = vector_from_list(obj["sigmas"], 3, 3) + values = vector_from_list(obj["values"], 3, 3) result = ProjectedRigTranslation(sigmas, values) result._extract_unknown_properties_and_extensions(obj) return result @@ -189,7 +189,7 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectedSensor": assert isinstance(obj, dict) - id = Uid64(int=int(obj.get("id"))) + id = Uid64(int=int(obj["id"])) rig_translation = from_union( [ProjectedRigTranslation.from_dict, from_none], obj.get("rig_translation") ) @@ -225,20 +225,19 @@ def __init__( self, captures: List[ProjectedCapture], sensors: List[ProjectedSensor], - format: CoreFormat = CoreFormat.PROJECTED_INPUT_CAMERAS, + pformat: CoreFormat = CoreFormat.PROJECTED_INPUT_CAMERAS, version: VersionInfo = FormatVersion.PROJECTED_INPUT_CAMERAS, ) -> None: - super(ProjectedInputCameras, self).__init__(format=format, version=version) - + super(ProjectedInputCameras, self).__init__(format=pformat, version=version) + assert self.format == CoreFormat.PROJECTED_INPUT_CAMERAS self.captures = captures self.sensors = sensors @staticmethod def from_dict(obj: Any) -> "ProjectedInputCameras": base = CoreItem.from_dict(obj) - - captures = from_list(ProjectedCapture.from_dict, obj.get("captures")) - sensors = from_list(ProjectedSensor.from_dict, obj.get("sensors")) + captures = from_list(ProjectedCapture.from_dict, obj["captures"]) + sensors = from_list(ProjectedSensor.from_dict, obj["sensors"]) result = ProjectedInputCameras(captures, sensors, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cameras/sensor_internals.py b/src/pyopf/cameras/sensor_internals.py index 5dcdf82..662af00 100644 --- a/src/pyopf/cameras/sensor_internals.py +++ b/src/pyopf/cameras/sensor_internals.py @@ -31,9 +31,9 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "SphericalInternals": assert isinstance(obj, dict) - assert obj.get("type") == SphericalInternals.type + assert obj["type"] == SphericalInternals.type - principal_point_px = vector_from_list(obj.get("principal_point_px"), 2, 2) + principal_point_px = vector_from_list(obj["principal_point_px"], 2, 2) result = SphericalInternals(principal_point_px) result._extract_unknown_properties_and_extensions(obj, ["type"]) return result @@ -75,12 +75,12 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "PerspectiveInternals": assert isinstance(obj, dict) - assert obj.get("type") == PerspectiveInternals.type + assert obj["type"] == PerspectiveInternals.type - focal_length_px = from_float(obj.get("focal_length_px")) - principal_point_px = vector_from_list(obj.get("principal_point_px"), 2, 2) - radial_distortion = vector_from_list(obj.get("radial_distortion"), 3, 3) - tangential_distortion = vector_from_list(obj.get("tangential_distortion"), 2, 2) + focal_length_px = from_float(obj["focal_length_px"]) + principal_point_px = vector_from_list(obj["principal_point_px"], 2, 2) + radial_distortion = vector_from_list(obj["radial_distortion"], 3, 3) + tangential_distortion = vector_from_list(obj["tangential_distortion"], 2, 2) result = PerspectiveInternals( principal_point_px, @@ -140,13 +140,13 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "FisheyeInternals": assert isinstance(obj, dict) - assert obj.get("type") == FisheyeInternals.type + assert obj["type"] == FisheyeInternals.type - principal_point_px = vector_from_list(obj.get("principal_point_px"), 2, 2) - affine = vector_from_list(obj.get("affine"), 4, 4) - is_p0_zero = from_bool(obj.get("is_p0_zero")) - is_symmetric_affine = from_bool(obj.get("is_symmetric_affine")) - polynomial = np.array(from_list(from_float, obj.get("polynomial"))) + principal_point_px = vector_from_list(obj["principal_point_px"], 2, 2) + affine = vector_from_list(obj["affine"], 4, 4) + is_p0_zero = from_bool(obj["is_p0_zero"]) + is_symmetric_affine = from_bool(obj["is_symmetric_affine"]) + polynomial = np.array(from_list(from_float, obj["polynomial"])) result = FisheyeInternals( principal_point_px, diff --git a/src/pyopf/cps/calibrated_control_points.py b/src/pyopf/cps/calibrated_control_points.py index 972cfc0..46abdaa 100644 --- a/src/pyopf/cps/calibrated_control_points.py +++ b/src/pyopf/cps/calibrated_control_points.py @@ -24,8 +24,8 @@ def __init__(self, id: str, coordinates: np.ndarray) -> None: @staticmethod def from_dict(obj: Any) -> "CalibratedControlPoint": assert isinstance(obj, dict) - coordinates = vector_from_list(obj.get("coordinates"), 3, 3) - id = from_str(obj.get("id")) + coordinates = vector_from_list(obj["coordinates"], 3, 3) + id = from_str(obj["id"]) result = CalibratedControlPoint(id, coordinates) result._extract_unknown_properties_and_extensions(obj) return result @@ -60,7 +60,7 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "CalibratedControlPoints": base = CoreItem.from_dict(obj) - points = from_list(CalibratedControlPoint.from_dict, obj.get("points")) + points = from_list(CalibratedControlPoint.from_dict, obj["points"]) result = CalibratedControlPoints(points, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cps/constraints.py b/src/pyopf/cps/constraints.py index a6f801c..a96d774 100644 --- a/src/pyopf/cps/constraints.py +++ b/src/pyopf/cps/constraints.py @@ -51,11 +51,11 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "OrientationConstraint": assert isinstance(obj, dict) - id = from_str(obj.get("id")) - id_from = from_str(obj.get("id_from")) - id_to = from_str(obj.get("id_to")) - sigma_deg = from_float(obj.get("sigma_deg")) - unit_vector = vector_from_list(obj.get("unit_vector"), 3, 3) + id = from_str(obj["id"]) + id_from = from_str(obj["id_from"]) + id_to = from_str(obj["id_to"]) + sigma_deg = from_float(obj["sigma_deg"]) + unit_vector = vector_from_list(obj["unit_vector"], 3, 3) result = OrientationConstraint(id, id_from, id_to, unit_vector, sigma_deg) result._extract_unknown_properties_and_extensions(obj) return result @@ -101,11 +101,11 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ScaleConstraint": assert isinstance(obj, dict) - distance = from_float(obj.get("distance")) - id = from_str(obj.get("id")) - id_from = from_str(obj.get("id_from")) - id_to = from_str(obj.get("id_to")) - sigma = from_float(obj.get("sigma")) + distance = from_float(obj["distance"]) + id = from_str(obj["id"]) + id_from = from_str(obj["id_from"]) + id_to = from_str(obj["id_to"]) + sigma = from_float(obj["sigma"]) result = ScaleConstraint(id, id_from, id_to, distance, sigma) result._extract_unknown_properties_and_extensions(obj) return result @@ -136,7 +136,6 @@ def __init__( version: VersionInfo = FormatVersion.CONSTRAINTS, ) -> None: super(Constraints, self).__init__(format=format, version=version) - assert self.format == CoreFormat.CONSTRAINTS self.orientation_constraints = orientation_constraints self.scale_constraints = scale_constraints @@ -146,10 +145,10 @@ def from_dict(obj: Any) -> "Constraints": base = CoreItem.from_dict(obj) orientation_constraints = from_list( - OrientationConstraint.from_dict, obj.get("orientation_constraints") + OrientationConstraint.from_dict, obj["orientation_constraints"] ) scale_constraints = from_list( - ScaleConstraint.from_dict, obj.get("scale_constraints") + ScaleConstraint.from_dict, obj["scale_constraints"] ) result = Constraints( orientation_constraints, scale_constraints, base.format, base.version diff --git a/src/pyopf/cps/input_control_points.py b/src/pyopf/cps/input_control_points.py index 95b77a1..aae2461 100644 --- a/src/pyopf/cps/input_control_points.py +++ b/src/pyopf/cps/input_control_points.py @@ -46,9 +46,9 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Mark": assert isinstance(obj, dict) - accuracy = from_float(obj.get("accuracy")) - camera_id = Uid64(int=int(obj.get("camera_id"))) - position_px = vector_from_list(obj.get("position_px"), 2, 2) + accuracy = from_float(obj["accuracy"]) + camera_id = Uid64(int=int(obj["camera_id"])) + position_px = vector_from_list(obj["position_px"], 2, 2) result = Mark(accuracy, camera_id, position_px) result._extract_unknown_properties_and_extensions(obj) return result @@ -88,10 +88,10 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Gcp": assert isinstance(obj, dict) - geolocation = Geolocation.from_dict(obj.get("geolocation")) - id = from_str(obj.get("id")) - is_checkpoint = from_bool(obj.get("is_checkpoint")) - marks = from_list(Mark.from_dict, obj.get("marks")) + geolocation = Geolocation.from_dict(obj["geolocation"]) + id = from_str(obj["id"]) + is_checkpoint = from_bool(obj["is_checkpoint"]) + marks = from_list(Mark.from_dict, obj["marks"]) result = Gcp(id, geolocation, is_checkpoint, marks) result._extract_unknown_properties_and_extensions(obj) return result @@ -130,9 +130,9 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Mtp": assert isinstance(obj, dict) - id = from_str(obj.get("id")) - is_checkpoint = from_bool(obj.get("is_checkpoint")) - marks = from_list(Mark.from_dict, obj.get("marks")) + id = from_str(obj["id"]) + is_checkpoint = from_bool(obj["is_checkpoint"]) + marks = from_list(Mark.from_dict, obj["marks"]) result = Mtp(id, is_checkpoint, marks) result._extract_unknown_properties_and_extensions(obj) return result @@ -169,8 +169,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "InputControlPoints": base = CoreItem.from_dict(obj) - gcps = from_list(Gcp.from_dict, obj.get("gcps")) - mtps = from_list(Mtp.from_dict, obj.get("mtps")) + gcps = from_list(Gcp.from_dict, obj["gcps"]) + mtps = from_list(Mtp.from_dict, obj["mtps"]) result = InputControlPoints(gcps, mtps, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/cps/projected_control_points.py b/src/pyopf/cps/projected_control_points.py index 36047d9..a9f970d 100644 --- a/src/pyopf/cps/projected_control_points.py +++ b/src/pyopf/cps/projected_control_points.py @@ -43,9 +43,9 @@ def __init__( def from_dict(obj: Any) -> "ProjectedGcp": assert isinstance(obj, dict) - coordinates = vector_from_list(obj.get("coordinates"), 3, 3) - sigmas = vector_from_list(obj.get("sigmas"), 3, 3) - id = from_str(obj.get("id")) + coordinates = vector_from_list(obj["coordinates"], 3, 3) + sigmas = vector_from_list(obj["sigmas"], 3, 3) + id = from_str(obj["id"]) result = ProjectedGcp(id, coordinates, sigmas) result._extract_unknown_properties_and_extensions(obj) @@ -83,7 +83,7 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectedControlPoints": base = CoreItem.from_dict(obj) - projected_gcps = from_list(ProjectedGcp.from_dict, obj.get("projected_gcps")) + projected_gcps = from_list(ProjectedGcp.from_dict, obj["projected_gcps"]) result = ProjectedControlPoints(projected_gcps, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/crs/crs.py b/src/pyopf/crs/crs.py index 4a1742e..ab5117c 100644 --- a/src/pyopf/crs/crs.py +++ b/src/pyopf/crs/crs.py @@ -1,14 +1,7 @@ -from typing import Any, Dict, Optional +from typing import Any, Optional -from ..types import Extensions, OpfObject -from ..util import ( - from_float, - from_none, - from_str, - from_union, - to_class, - to_float, -) +from ..types import OpfObject +from ..util import from_float, from_none, from_str, from_union, to_float class Crs(OpfObject): @@ -38,7 +31,7 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Crs": assert isinstance(obj, dict) - definition = from_str(obj.get("definition")) + definition = from_str(obj["definition"]) geoid_height = from_union([from_float, from_none], obj.get("geoid_height")) result = Crs(definition, geoid_height) result._extract_unknown_properties_and_extensions(obj) diff --git a/src/pyopf/crs/geolocation.py b/src/pyopf/crs/geolocation.py index 2f783c8..b3f6500 100644 --- a/src/pyopf/crs/geolocation.py +++ b/src/pyopf/crs/geolocation.py @@ -44,9 +44,9 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Geolocation": assert isinstance(obj, dict) - coordinates = vector_from_list(obj.get("coordinates"), 3, 3) - crs = Crs.from_dict(obj.get("crs")) - sigmas = vector_from_list(obj.get("sigmas"), 3, 3) + coordinates = vector_from_list(obj["coordinates"], 3, 3) + crs = Crs.from_dict(obj["crs"]) + sigmas = vector_from_list(obj["sigmas"], 3, 3) result = Geolocation(coordinates, crs, sigmas) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/crs/scene_reference_frame.py b/src/pyopf/crs/scene_reference_frame.py index 41468f8..53db9fd 100644 --- a/src/pyopf/crs/scene_reference_frame.py +++ b/src/pyopf/crs/scene_reference_frame.py @@ -35,9 +35,9 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "BaseToTranslatedCanonicalCrsTransform": assert isinstance(obj, dict) - scale = vector_from_list(obj.get("scale"), 3, 3) - shift = vector_from_list(obj.get("shift"), 3, 3) - swap_xy = from_bool(obj.get("swap_xy")) + scale = vector_from_list(obj["scale"], 3, 3) + shift = vector_from_list(obj["shift"], 3, 3) + swap_xy = from_bool(obj["swap_xy"]) result = BaseToTranslatedCanonicalCrsTransform(scale, shift, swap_xy) result._extract_unknown_properties_and_extensions(obj) return result @@ -49,6 +49,23 @@ def to_dict(self) -> dict: result["swap_xy"] = from_bool(self.swap_xy) return result + @property + def transformation_matrix(self) -> np.ndarray: + scale_transf = np.eye(4) + for i in range(3): + scale_transf[i, i] = self.scale[i] + + shift_transf = np.eye(4) + shift_transf[:3, 3] = self.shift + + swap_transf = ( + np.asarray([[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) + if self.swap_xy + else np.eye(4) + ) + + return shift_transf @ swap_transf @ scale_transf + class SceneReferenceFrame(CoreItem): """An object that specifies a base Cartesian CRS and the transformation parameters to a @@ -75,9 +92,9 @@ def __init__( def from_dict(obj: Any) -> "SceneReferenceFrame": base = CoreItem.from_dict(obj) base_to_canonical = BaseToTranslatedCanonicalCrsTransform.from_dict( - obj.get("base_to_canonical") + obj["base_to_canonical"] ) - crs = Crs.from_dict(obj.get("crs")) + crs = Crs.from_dict(obj["crs"]) result = SceneReferenceFrame(base_to_canonical, crs, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result diff --git a/src/pyopf/ext/__init__.py b/src/pyopf/ext/__init__.py index 479d05f..b80f7c8 100644 --- a/src/pyopf/ext/__init__.py +++ b/src/pyopf/ext/__init__.py @@ -1,7 +1,39 @@ +from . import ( + pix4d_calibrated_intersection_tie_points, + pix4d_input_intersection_tie_points, +) from .pix4d_planes import Pix4dPlanes from .pix4d_planes import format as pix4d_planes_format from .pix4d_planes import version as pix4d_planes_version +from .pix4d_polygonal_mesh import ( + Edge, + EdgeMark, + Face, + Pix4DPolygonalMeshes, + PolygonalMesh, + Vertex, + VertexMark, +) from .pix4d_region_of_interest import Pix4DRegionOfInterest from .pix4d_region_of_interest import format as region_of_interest_format from .pix4d_region_of_interest import version as region_of_interest_version from .plane import Plane + +pix4d_input_intersection_tie_points_version = ( + pix4d_input_intersection_tie_points.version +) +pix4d_input_intersection_tie_points_format = pix4d_input_intersection_tie_points.format + +Pix4DInputIntersectionTiePoints = ( + pix4d_input_intersection_tie_points.Pix4DInputIntersectionTiePoints +) + +pix4d_calibrated_intersection_tie_points_version = ( + pix4d_calibrated_intersection_tie_points.version +) +pix4d_calibrated_intersection_tie_points_format = ( + pix4d_calibrated_intersection_tie_points.format +) +Pix4DCalibratedIntersectionTiePoints = ( + pix4d_calibrated_intersection_tie_points.Pix4DCalibratedIntersectionTiePoints +) diff --git a/src/pyopf/ext/pix4d_calibrated_intersection_tie_points.py b/src/pyopf/ext/pix4d_calibrated_intersection_tie_points.py new file mode 100644 index 0000000..d1ac1a1 --- /dev/null +++ b/src/pyopf/ext/pix4d_calibrated_intersection_tie_points.py @@ -0,0 +1,52 @@ +from typing import Any, List + +from ..cps import CalibratedControlPoint +from ..formats import ExtensionFormat +from ..items import ExtensionItem +from ..util import from_list, to_class +from ..versions import VersionInfo, format_and_version_to_type + +format = ExtensionFormat( + "application/ext-pix4d-calibrated-intersection-tie-points+json" +) +version = VersionInfo(1, 0, "draft2") + + +class Pix4DCalibratedIntersectionTiePoints(ExtensionItem): + """Definition of calibrated intersection tie points, which are the optimised intersection + tie points with coordinates expressed in the processing CRS. + """ + + """List of calibrated intersection tie points.""" + points: List[CalibratedControlPoint] + + def __init__( + self, + points: List[CalibratedControlPoint], + format_: ExtensionFormat = format, + version_: VersionInfo = version, + ) -> None: + super(Pix4DCalibratedIntersectionTiePoints, self).__init__( + format=format_, version=version_ + ) + + assert self.format == format + self.points = points + + @staticmethod + def from_dict(obj: Any) -> "Pix4DCalibratedIntersectionTiePoints": + base = ExtensionItem.from_dict(obj) + points = from_list(CalibratedControlPoint.from_dict, obj["points"]) + result = Pix4DCalibratedIntersectionTiePoints(points, base.format, base.version) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result = super(Pix4DCalibratedIntersectionTiePoints, self).to_dict() + result["points"] = from_list( + lambda x: to_class(CalibratedControlPoint, x), self.points + ) + return result + + +format_and_version_to_type[(format, version)] = Pix4DCalibratedIntersectionTiePoints diff --git a/src/pyopf/ext/pix4d_input_depth_map.py b/src/pyopf/ext/pix4d_input_depth_map.py index 5154879..57f2ff8 100644 --- a/src/pyopf/ext/pix4d_input_depth_map.py +++ b/src/pyopf/ext/pix4d_input_depth_map.py @@ -29,20 +29,24 @@ class DepthMapConfidence(OpfPropertyExtObject): max: float """Minimum confidence value to consider a depth measurement valid.""" min: float + """Hint on the minimum (inclusive) confidence value to consider a depth measurement reliable.""" + threshold: float - def __init__(self, id: Uid64, max: float, min: float) -> None: + def __init__(self, id: Uid64, max: float, min: float, threshold: float) -> None: super(DepthMapConfidence, self).__init__() self.id = id self.max = max self.min = min + self.threshold = threshold @staticmethod def from_dict(obj: Any) -> "DepthMapConfidence": assert isinstance(obj, dict) - id = Uid64(int=obj.get("id")) - max = from_float(obj.get("max")) - min = from_float(obj.get("min")) - result = DepthMapConfidence(id, max, min) + id = Uid64(int=obj["id"]) + max = from_float(obj["max"]) + min = from_float(obj["min"]) + threshold = from_float(obj["threshold"]) + result = DepthMapConfidence(id, max, min, threshold) result._extract_unknown_properties_and_extensions(obj) return result @@ -51,6 +55,7 @@ def to_dict(self) -> dict: result["id"] = self.id.int result["max"] = to_float(self.max) result["min"] = to_float(self.min) + result["threshold"] = to_float(self.threshold) return result @@ -90,9 +95,9 @@ def from_dict(obj: Any) -> "Pix4dInputDepthMap": [DepthMapConfidence.from_dict, from_none], obj.get("confidence") ) - id = Uid64(obj.get("id")) + id = Uid64(obj["id"]) unit_to_meters = from_union([from_float, from_none], obj.get("unit_to_meters")) - version = from_union([from_version_info, VersionInfo.parse], obj.get("version")) + version = from_union([from_version_info, VersionInfo.parse], obj["version"]) result = Pix4dInputDepthMap(id, unit_to_meters, confidence, version) result._extract_unknown_properties_and_extensions(obj) diff --git a/src/pyopf/ext/pix4d_input_intersection_tie_points.py b/src/pyopf/ext/pix4d_input_intersection_tie_points.py new file mode 100644 index 0000000..ff6bf03 --- /dev/null +++ b/src/pyopf/ext/pix4d_input_intersection_tie_points.py @@ -0,0 +1,193 @@ +from enum import Enum +from typing import Any, List, Optional + +import numpy as np + +from ..formats import ExtensionFormat +from ..items import ExtensionItem +from ..types import OpfObject, VersionInfo +from ..uid64 import Uid64 +from ..util import ( + from_bool, + from_float, + from_list, + from_none, + from_str, + from_union, + to_class, + to_enum, + to_float, + vector_from_list, +) +from ..versions import format_and_version_to_type + +format = ExtensionFormat("application/ext-pix4d-input-intersection-tie-points+json") +version = VersionInfo(1, 0, "draft3") + + +class CreationMethodType(Enum): + AUTOMATIC = "automatic" + MANUAL = "manual" + + +class CreationMethod(OpfObject): + """The method that was used to create the mark. A mark that is edited by a user should be + defined as manual. + """ + + type: Optional[CreationMethodType] + + def __init__(self, type: Optional[CreationMethodType]) -> None: + self.type = type + + @staticmethod + def from_dict(obj: Any) -> "CreationMethod": + assert isinstance(obj, dict) + type = from_union([CreationMethodType, from_none], obj.get("type")) + result = CreationMethod(type) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result = super(CreationMethod, self).to_dict() + if self.type is not None: + result["type"] = to_enum(CreationMethodType, self.type) + return result + + +class MarkWithSegments(OpfObject): + """2D image mark, defined as the intersection of a set of line segments.""" + + camera_id: Uid64 + """Camera ID for the image on which the mark is defined.""" + common_endpoint_px: np.ndarray # vector of size 2 + """Pixel location of the common endpoint of all intersecting segments marked on this image.""" + creation_method: CreationMethod + """The method that was used to create the mark. A mark that is edited by a user should be + defined as manual. + """ + other_endpoints_px: List[np.ndarray] # list of vectors of size 2 + """Array of pixel locations, each of these endpoints and common_endpoint_px defines a + segment. + """ + accuracy: Optional[float] + """A number representing the accuracy of the mark, used by the calibration algorithm to + estimate the position error of the mark. + """ + + def __init__( + self, + camera_id: Uid64, + common_endpoint_px: np.ndarray, + creation_method: CreationMethod, + other_endpoints_px: List[np.ndarray], + accuracy: Optional[float], + ) -> None: + super(MarkWithSegments, self).__init__() + self.camera_id = camera_id + self.common_endpoint_px = common_endpoint_px + self.creation_method = creation_method + self.other_endpoints_px = other_endpoints_px + self.accuracy = accuracy + + @staticmethod + def from_dict(obj: Any) -> "MarkWithSegments": + assert isinstance(obj, dict) + camera_id = Uid64(int=int(obj["camera_id"])) + common_endpoint_px = vector_from_list(obj["common_endpoint_px"], 2, 2) + creation_method = CreationMethod.from_dict(obj["creation_method"]) + other_endpoints_px = from_list( + lambda x: vector_from_list(x, 2, 2), obj["other_endpoints_px"] + ) + accuracy = from_union([from_float, from_none], obj.get("accuracy")) + result = MarkWithSegments( + camera_id, common_endpoint_px, creation_method, other_endpoints_px, accuracy + ) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result = super(MarkWithSegments, self).to_dict() + result["camera_id"] = self.camera_id.int + result["common_endpoint_px"] = from_list(to_float, self.common_endpoint_px) + result["creation_method"] = to_class(CreationMethod, self.creation_method) + result["other_endpoints_px"] = from_list( + lambda x: from_list(to_float, x), self.other_endpoints_px + ) + if self.accuracy is not None: + result["accuracy"] = from_union([to_float, from_none], self.accuracy) + return result + + +class IntersectionTiePoint(OpfObject): + + id: str + """A unique string that identifies the ITP amongst all control points.""" + marks: List[MarkWithSegments] + """List of marks with line segments in the images that correspond to the projections of a 3D + point. + """ + modified_by_user: bool + """If true, indicates that the ITP was modified by the user.""" + + def __init__( + self, id: str, marks: List[MarkWithSegments], modified_by_user: bool + ) -> None: + self.id = id + self.marks = marks + self.modified_by_user = modified_by_user + + @staticmethod + def from_dict(obj: Any) -> "IntersectionTiePoint": + assert isinstance(obj, dict) + id = from_str(obj["id"]) + marks = from_list(MarkWithSegments.from_dict, obj["marks"]) + modified_by_user = from_bool(obj["modified_by_user"]) + result = IntersectionTiePoint(id, marks, modified_by_user) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result = super(IntersectionTiePoint, self).to_dict() + result["id"] = from_str(self.id) + result["marks"] = from_list(lambda x: to_class(MarkWithSegments, x), self.marks) + result["modified_by_user"] = from_bool(self.modified_by_user) + return result + + +class Pix4DInputIntersectionTiePoints(ExtensionItem): + """Definition of Intersection Tie Points""" + + itps: List[IntersectionTiePoint] + """List of input ITPs.""" + + def __init__( + self, + itps: List[IntersectionTiePoint], + format_: ExtensionFormat = format, + version_: VersionInfo = version, + ) -> None: + super(Pix4DInputIntersectionTiePoints, self).__init__( + format=format_, version=version_ + ) + + assert self.format == format + self.itps = itps + + @staticmethod + def from_dict(obj: Any) -> "Pix4DInputIntersectionTiePoints": + base = ExtensionItem.from_dict(obj) + itps = from_list(IntersectionTiePoint.from_dict, obj["itps"]) + result = Pix4DInputIntersectionTiePoints(itps, base.format, base.version) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result = super(Pix4DInputIntersectionTiePoints, self).to_dict() + result["itps"] = from_list( + lambda x: to_class(IntersectionTiePoint, x), self.itps + ) + return result + + +format_and_version_to_type[(format, version)] = Pix4DInputIntersectionTiePoints diff --git a/src/pyopf/ext/pix4d_planes.py b/src/pyopf/ext/pix4d_planes.py index 6471d7b..9d576e5 100644 --- a/src/pyopf/ext/pix4d_planes.py +++ b/src/pyopf/ext/pix4d_planes.py @@ -5,7 +5,14 @@ from ..formats import ExtensionFormat from ..items import ExtensionItem from ..uid64 import Uid64 -from ..util import IntType, from_bool, from_list, to_class +from ..util import ( + IntType, + from_bool, + from_list, + from_none, + from_union, + to_class, +) from ..versions import VersionInfo, format_and_version_to_type from .plane import Plane @@ -15,11 +22,11 @@ class ExtendedPlane(Plane): - is_plane_oriented: bool + is_plane_oriented: Optional[bool] """If True, indicates that the normal vector points towards the visible half-space defined by the plane. Otherwise, the normal can point in either direction.""" - viewing_cameras: List[Uid64] + viewing_cameras: Optional[List[Uid64]] """List of camera ids from the input cameras which are known to view the plane or part of it.""" def __init__( @@ -27,8 +34,8 @@ def __init__( vertices3d: List[np.ndarray], normal_vector: np.ndarray, outer_boundary: List[IntType], - is_plane_oriented: bool, - viewing_cameras: List[Uid64], + is_plane_oriented: Optional[bool] = None, + viewing_cameras: Optional[List[Uid64]] = None, inner_boundaries: Optional[List[List[IntType]]] = None, ) -> None: super(ExtendedPlane, self).__init__( @@ -42,7 +49,10 @@ def from_dict(obj: Any) -> "ExtendedPlane": assert isinstance(obj, dict) plane = Plane.from_dict(obj) is_plane_oriented = from_bool(obj.get("is_plane_oriented")) - viewing_cameras = from_list(lambda x: Uid64(int=x), obj.get("viewing_cameras")) + viewing_cameras = from_union( + [lambda x: from_list(lambda x: Uid64(int=x), x), from_none], + obj.get("viewing_cameras"), + ) result = ExtendedPlane( plane.vertices3d, @@ -58,7 +68,8 @@ def from_dict(obj: Any) -> "ExtendedPlane": def to_dict(self) -> dict: result = super(ExtendedPlane, self).to_dict() result["is_plane_oriented"] = self.is_plane_oriented - result["viewing_cameras"] = [int(x) for x in self.viewing_cameras] + if self.viewing_cameras is not None: + result["viewing_cameras"] = [int(x) for x in self.viewing_cameras] return result @@ -80,16 +91,14 @@ def __init__( def from_dict(obj: Any) -> "Pix4dPlanes": assert isinstance(obj, dict) base = ExtensionItem.from_dict(obj) - planes = from_list(ExtendedPlane.from_dict, obj.get("planes")) + planes = from_list(ExtendedPlane.from_dict, obj["planes"]) result = Pix4dPlanes(planes, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) return result def to_dict(self) -> dict: result: dict = super(Pix4dPlanes, self).to_dict() - result["planes"] = from_list(lambda x: to_class(ExtendedPlane, x), self.planes) - return result diff --git a/src/pyopf/ext/pix4d_polygonal_mesh.py b/src/pyopf/ext/pix4d_polygonal_mesh.py new file mode 100644 index 0000000..3357494 --- /dev/null +++ b/src/pyopf/ext/pix4d_polygonal_mesh.py @@ -0,0 +1,289 @@ +from typing import Any, List, Optional + +import numpy as np + +from pyopf.types import OpfObject + +from ..formats import ExtensionFormat +from ..items import ExtensionItem +from ..uid64 import Uid64 +from ..util import ( + IntType, + from_int, + from_list, + from_none, + from_uid, + from_union, + to_class, + to_float, + vector_from_list, +) +from ..versions import VersionInfo, format_and_version_to_type + +format = ExtensionFormat("application/ext-pix4d-polygonal-meshes+json") +version = VersionInfo(1, 0, "draft1") + + +class VertexMark(OpfObject): + + camera_uid: Uid64 + """ Camera id corresponding to this mark """ + position_px: np.ndarray + """ The position of the mark inside the image """ + + def __init__(self, camera_uid: Uid64, position_px: np.ndarray) -> None: + super(VertexMark, self).__init__() + self.camera_uid = camera_uid + self.position_px = position_px + + @staticmethod + def from_dict(obj: Any) -> "VertexMark": + assert isinstance(obj, dict) + camera_uid = from_uid(obj["camera_uid"]) + position_px = vector_from_list(obj["position_px"], 2, 2) + result = VertexMark(camera_uid, position_px) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result: dict = {} + result["camera_uid"] = self.camera_uid.int + result["position_px"] = from_list(lambda x: x, self.position_px) + return result + + +class Vertex(OpfObject): + + position: np.ndarray + """ The vertex position """ + marks: Optional[List[VertexMark]] + """ The image marks corresponding to this vertex """ + + def __init__( + self, position: np.ndarray, marks: Optional[List[VertexMark]] = None + ) -> None: + super(Vertex, self).__init__() + self.position = position + self.marks = marks + + @staticmethod + def from_dict(obj: Any) -> "Vertex": + assert isinstance(obj, dict) + position = vector_from_list(obj["position"], 3, 3) + marks = from_union( + [lambda x: from_list(lambda x: VertexMark.from_dict(x), x), from_none], + obj.get("marks"), + ) + result = Vertex(position, marks) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result: dict = {} + result["position"] = from_list(to_float, self.position) + if self.marks is not None: + result["marks"] = from_union( + [lambda x: from_list(lambda x: to_class(VertexMark, x), x), from_none], + self.marks, + ) + return result + + +class EdgeMark(OpfObject): + + camera_uid: Uid64 + """ Camera id corresponding to this mark """ + segment_px: List[np.ndarray] + """ The position of the mark inside the image """ + + def __init__(self, camera_uid: Uid64, segment_px: List[np.ndarray]) -> None: + super(EdgeMark, self).__init__() + self.camera_uid = camera_uid + self.segment_px = segment_px + + def __eq__(self, other): + return ( + self.camera_uid == other.camera_uid and self.segment_px == other.segment_px + ) + + @staticmethod + def from_dict(obj: Any) -> "EdgeMark": + assert isinstance(obj, dict) + camera_uid = from_uid(obj["camera_uid"]) + segment_px = from_list(lambda x: vector_from_list(x, 2, 2), obj["segment_px"]) + result = EdgeMark(camera_uid, segment_px) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result: dict = {} + result["camera_uid"] = self.camera_uid.int + result["segment_px"] = from_list( + lambda x: from_list(lambda x: x, x), self.segment_px + ) + return result + + +class Edge(OpfObject): + + vertex_indices: List[IntType] + """ The indices of the two vertices connected by the edge """ + marks: Optional[List[EdgeMark]] + """ List of edge image marks """ + + def __init__( + self, vertex_indices: List[IntType], marks: Optional[List[EdgeMark]] = None + ) -> None: + super(Edge, self).__init__() + self.vertex_indices = vertex_indices + self.marks = marks + + def __eq__(self, other): + return ( + set(self.vertex_indices) == set(other.vertex_indices) + and self.marks == other.marks + ) + + @staticmethod + def from_dict(obj: Any) -> "Edge": + assert isinstance(obj, dict) + vertex_indices = from_list(int, obj["vertex_indices"]) + marks = from_union( + [lambda x: from_list(lambda x: EdgeMark.from_dict(x), x), from_none], + obj.get("marks"), + ) + result = Edge(vertex_indices, marks) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result: dict = {} + result["vertex_indices"] = from_list(from_int, self.vertex_indices) + if self.marks is not None: + result["marks"] = from_union( + [lambda x: from_list(lambda x: to_class(EdgeMark, x), x), from_none], + self.marks, + ) + return result + + +class Face(OpfObject): + + outer_edge_indices: List[IntType] + """ The indices of the (undirected) edges forming the polygonal face outer loop """ + inner_edge_indices: Optional[List[List[IntType]]] + """ The indices of the (undirected) edges forming the polygonal face inner loops, if any """ + + def __init__(self, outer_edge_indices, inner_edge_indices=None): + super(Face, self).__init__() + self.outer_edge_indices = outer_edge_indices + self.inner_edge_indices = inner_edge_indices + + @staticmethod + def from_dict(obj: Any) -> "Face": + assert isinstance(obj, dict) + outer_edge_indices = from_list(from_int, obj["outer_edge_indices"]) + inner_edge_indices = from_union( + [lambda x: from_list(lambda x: from_list(from_int, x), x), from_none], + obj.get("inner_edge_indices"), + ) + result = Face(outer_edge_indices, inner_edge_indices) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result: dict = {} + if self.inner_edge_indices is not None: + result["inner_edge_indices"] = from_union( + [lambda x: from_list(lambda x: from_list(from_int, x), x), from_none], + self.inner_edge_indices, + ) + result["outer_edge_indices"] = from_list(from_int, self.outer_edge_indices) + return result + + +class PolygonalMesh(OpfObject): + + vertices: List[Vertex] + """ List of vertices """ + edges: List[Edge] + """ List of edges """ + faces: List[Face] + """ List of faces """ + triangulation: Optional[List[np.ndarray]] + """ Array of vertex indices triplets defining a triangulation of the polygonal mesh """ + + def __init__( + self, + vertices: List[Vertex], + edges: List[Edge], + faces: List[Face], + triangulation: Optional[List[np.ndarray]] = None, + ) -> None: + super(PolygonalMesh, self).__init__() + self.vertices = vertices + self.edges = edges + self.faces = faces + self.triangulation = triangulation + + @staticmethod + def from_dict(obj: Any) -> "PolygonalMesh": + assert isinstance(obj, dict) + vertices = from_list(lambda x: Vertex.from_dict(x), obj["vertices"]) + edges = from_list(lambda x: Edge.from_dict(x), obj["edges"]) + faces = from_list(lambda x: Face.from_dict(x), obj["faces"]) + triangulation = from_union( + [ + lambda x: from_list(lambda x: vector_from_list(x, 3, 3, int), x), + from_none, + ], + obj.get("triangulation"), + ) + + result = PolygonalMesh(vertices, edges, faces, triangulation) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result = {} + result["vertices"] = from_list(lambda x: to_class(Vertex, x), self.vertices) + result["edges"] = from_list(lambda x: to_class(Edge, x), self.edges) + result["faces"] = from_list(lambda x: to_class(Face, x), self.faces) + if self.triangulation is not None: + result["triangulation"] = from_union( + [lambda x: from_list(lambda x: from_list(from_int, x), x), from_none], + self.triangulation, + ) + return result + + +class Pix4DPolygonalMeshes(ExtensionItem): + + meshes: List[PolygonalMesh] + """ A list of meshes """ + + def __init__( + self, + meshes: List[PolygonalMesh], + pformat: ExtensionFormat = format, + version: VersionInfo = version, + ) -> None: + super(Pix4DPolygonalMeshes, self).__init__(format=pformat, version=version) + assert self.format == format + self.meshes = meshes + + @staticmethod + def from_dict(obj: Any) -> "Pix4DPolygonalMeshes": + base = ExtensionItem.from_dict(obj) + meshes = from_list(PolygonalMesh.from_dict, obj["meshes"]) + result = Pix4DPolygonalMeshes(meshes, base.format, base.version) + result._extract_unknown_properties_and_extensions(obj) + return result + + def to_dict(self) -> dict: + result = super(Pix4DPolygonalMeshes, self).to_dict() + result["meshes"] = from_list(lambda x: to_class(PolygonalMesh, x), self.meshes) + return result + + +format_and_version_to_type[(format, version)] = Pix4DPolygonalMeshes diff --git a/src/pyopf/ext/pix4d_region_of_interest.py b/src/pyopf/ext/pix4d_region_of_interest.py index bbe1d00..e5fe94b 100644 --- a/src/pyopf/ext/pix4d_region_of_interest.py +++ b/src/pyopf/ext/pix4d_region_of_interest.py @@ -28,10 +28,10 @@ def __init__( self, plane: Plane, height: Optional[float], - format: ExtensionFormat = format, + pformat: ExtensionFormat = format, version: VersionInfo = version, ) -> None: - super(Pix4DRegionOfInterest, self).__init__(format=format, version=version) + super(Pix4DRegionOfInterest, self).__init__(format=pformat, version=version) assert self.format == format self.plane = plane @@ -40,7 +40,7 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Pix4DRegionOfInterest": base = ExtensionItem.from_dict(obj) - plane = Plane.from_dict(obj.get("plane")) + plane = Plane.from_dict(obj["plane"]) height = from_union([from_float, from_none], obj.get("height")) result = Pix4DRegionOfInterest(plane, height, base.format, base.version) result._extract_unknown_properties_and_extensions(obj) diff --git a/src/pyopf/ext/plane.py b/src/pyopf/ext/plane.py index 4ef3d1c..ac2b702 100644 --- a/src/pyopf/ext/plane.py +++ b/src/pyopf/ext/plane.py @@ -44,10 +44,12 @@ def from_dict(obj: Any) -> "Plane": [lambda x: from_list(lambda x: from_list(from_int, x), x), from_none], obj.get("inner_boundaries"), ) - normal_vector = vector_from_list(obj.get("normal_vector")) - outer_boundary = from_list(from_int, obj.get("outer_boundary")) - vertices3d = from_list(lambda x: vector_from_list(x), obj.get("vertices3d")) - return Plane(vertices3d, normal_vector, outer_boundary, inner_boundaries) + normal_vector = vector_from_list(obj["normal_vector"], 3, 3) + outer_boundary = from_list(from_int, obj["outer_boundary"]) + vertices3d = from_list(lambda x: vector_from_list(x, 3, 3), obj["vertices3d"]) + result = Plane(vertices3d, normal_vector, outer_boundary, inner_boundaries) + result._extract_unknown_properties_and_extensions(obj) + return result def to_dict(self) -> dict: result: dict = {} diff --git a/src/pyopf/io/__init__.py b/src/pyopf/io/__init__.py index eeafeed..434ae68 100644 --- a/src/pyopf/io/__init__.py +++ b/src/pyopf/io/__init__.py @@ -1,2 +1,2 @@ -from .loaders import UnsupportedResource, load +from .loaders import UnsupportedResource, UnsupportedVersion, load from .savers import save diff --git a/src/pyopf/io/loaders.py b/src/pyopf/io/loaders.py index c85729c..1c8fd0a 100644 --- a/src/pyopf/io/loaders.py +++ b/src/pyopf/io/loaders.py @@ -1,19 +1,21 @@ import json +import os from pathlib import Path from typing import Any, Optional -from urllib.parse import unquote, urljoin, urlparse +from urllib.parse import ParseResult, unquote, urljoin, urlparse from urllib.request import url2pathname from ..formats import CoreFormat, format_from_str from ..pointcloud.pcl import GlTFPointCloud from ..project import ProjectResource from ..types import VersionInfo -from ..versions import format_and_version_to_type +from ..versions import Format, get_compatible_type -def join_uris(uri: str, base_uri: Optional[str]) -> Path: - """Resolve a URI relative to an absolute base URI if the input URI - is a relative URI reference, otherwise return the URI unmodified. +def join_uris(uri: str, base_uri: Optional[str]) -> ParseResult: + """Resolve a URI relative to an absolute base URI if the input URI is a relative URI + reference, otherwise return the URI unmodified. + The return value is wrapped as a urllib.parse.ParseResult. """ if base_uri is not None: uri = urljoin(base_uri + "/", uri) @@ -25,10 +27,14 @@ def join_uris(uri: str, base_uri: Optional[str]) -> Path: " referring to the localhost are supported" ) + return url + + +def url_to_path(url: ParseResult) -> Path: if url.scheme == "file" or url.scheme == "": return Path(url2pathname(url.path)) - raise RuntimeError("Non-file URIs are not supported") + raise RuntimeError("A non-file URIs is not accepted") def _load_from_json(uri: Path) -> Any: @@ -44,12 +50,9 @@ def _load_from_json(uri: Path) -> Any: except KeyError: raise RuntimeError("Input file is not a valid OPF JSON resource") - try: - cls = format_and_version_to_type[(format, version)] - except KeyError: - raise RuntimeError( - f"Unsupported resource format and version: {format}, {version}" - ) + cls = get_compatible_type(format, version) + if cls is None: + raise UnsupportedVersion(format, version) try: object = cls.from_dict(d) @@ -65,40 +68,46 @@ def _load_from_json(uri: Path) -> Any: raise RuntimeError(f"Error decoding JSON resource {format}, {version}") from e +def _ensure_uri(uri: str | os.PathLike) -> str: + path = Path(uri) # This doesn't throw if given something like "file:///foo" + if path.is_absolute(): + return path.as_uri() + else: + return str(path) + + def _test_json_resource( - resource: str | ProjectResource, base_uri: str, _ + resource: str | ProjectResource | os.PathLike, base_uri: str, _ ) -> tuple[bool, Optional[list[Any]]]: - - if isinstance(resource, str): - uri = join_uris(resource, base_uri) + if isinstance(resource, ProjectResource): + path = url_to_path(join_uris(resource.uri, base_uri)) else: - uri = join_uris(resource.uri, base_uri) + path = url_to_path(join_uris(_ensure_uri(resource), base_uri)) - if uri.suffix == ".json" or uri.suffix == ".opf": - return (True, [uri]) + if path.suffix == ".json" or path.suffix == ".opf": + return (True, [path]) return (False, None) def _test_gltf_model_resource( - resource: str | ProjectResource, base_uri: str, _ + resource: str | ProjectResource | os.PathLike, base_uri: str, _ ) -> tuple[bool, Optional[list[Any]]]: - - if isinstance(resource, str): - uri = join_uris(resource, base_uri) - elif resource.format == CoreFormat.GLTF_MODEL: - uri = join_uris(resource.uri, base_uri) + if isinstance(resource, ProjectResource): + if resource.format == CoreFormat.GLTF_MODEL: + path = url_to_path(join_uris(resource.uri, base_uri)) + else: + return (False, None) else: - return (False, None) + path = url_to_path(join_uris(_ensure_uri(resource), base_uri)) - if uri.suffix == ".gltf": - return (True, [uri]) + if path.suffix == ".gltf": + return (True, [path]) return (False, None) def _test_gltf_binary_resource( - resource: str | ProjectResource, base_uri: str, _ + resource: str | ProjectResource | os.PathLike, base_uri: str, _ ) -> tuple[bool, Optional[list[Any]]]: - if ( isinstance(resource, ProjectResource) and resource.format == CoreFormat.GLTF_BUFFER @@ -126,13 +135,21 @@ def __init__(self, uri=None): self.uri = uri +class UnsupportedVersion(RuntimeError): + def __init__(self, _format: Format, version: VersionInfo): + self._format = _format + self.version = version + self.message = f"Unsupported resource format and version: {_format}, {version}" + + def load( - resource: str | ProjectResource, + resource: str | ProjectResource | os.PathLike, base_uri: Optional[str] = None, additional_resources: Optional[list[ProjectResource]] = None, ) -> Any: """Loads a resource from a URI - :param uri: The URI of the resource to load + :param resource: a resource to be loaded. It must be a ProjectResource, a string with a URI or path, or + a os.PathLike object :param base_uri: Base URI to use to resolve relative URI references :param additional_resouces: Additional resources for resources that require multiple not referenced by the main resource file. diff --git a/src/pyopf/io/savers.py b/src/pyopf/io/savers.py index 6209290..ac79838 100644 --- a/src/pyopf/io/savers.py +++ b/src/pyopf/io/savers.py @@ -3,6 +3,7 @@ from pathlib import Path from typing import Any from urllib.parse import quote, unquote, urlparse +from urllib.request import url2pathname from ..items import CoreItem, ExtensionItem from ..pointcloud.pcl import GlTFPointCloud @@ -199,7 +200,7 @@ def save(obj: Any, uri: str | Path, **kwargs) -> list[ProjectResource]: """ if not isinstance(uri, Path): - uri = Path(unquote(urlparse(uri).path)).absolute() + uri = Path(url2pathname(urlparse(uri).path)).absolute() for obj_type, saver in savers: if isinstance(obj, obj_type): diff --git a/src/pyopf/items.py b/src/pyopf/items.py index ef9526a..9a528f7 100644 --- a/src/pyopf/items.py +++ b/src/pyopf/items.py @@ -7,7 +7,7 @@ format_to_str, from_format, ) -from .types import OpfObject, OpfPropertyExtObject +from .types import OpfObject from .util import from_union, from_version_info from .VersionInfo import VersionInfo @@ -40,8 +40,8 @@ def to_dict(self) -> dict: @staticmethod def from_dict(obj: Any) -> "CoreItem": assert isinstance(obj, dict) - format = from_union([from_format, format_from_str], obj.get("format")) - version = from_union([from_version_info, VersionInfo.parse], obj.get("version")) + format = from_union([from_format, format_from_str], obj["format"]) + version = from_union([from_version_info, VersionInfo.parse], obj["version"]) return CoreItem(format, version) @@ -73,6 +73,13 @@ def to_dict(self) -> dict: @staticmethod def from_dict(obj: Any) -> "ExtensionItem": assert isinstance(obj, dict) - format = from_union([from_format, format_from_str], obj.get("format")) - version = from_union([from_version_info, VersionInfo.parse], obj.get("version")) + format = from_union([from_format, format_from_str], obj["format"]) + version = from_union([from_version_info, VersionInfo.parse], obj["version"]) return ExtensionItem(format, version) + + def _extract_unknown_properties_and_extensions( + self, obj: dict, ignore_keys=set() + ) -> None: + super(ExtensionItem, self)._extract_unknown_properties_and_extensions( + obj, ignore_keys={"format", "version"}.union(ignore_keys) + ) diff --git a/src/pyopf/pointcloud/merge.py b/src/pyopf/pointcloud/merge.py index ce0113f..2718476 100644 --- a/src/pyopf/pointcloud/merge.py +++ b/src/pyopf/pointcloud/merge.py @@ -13,7 +13,7 @@ opf_axis_rotation_matrix, opf_axis_rotation_matrix_inverse, ) -from .utils import merge_arrays +from .utils import apply_affine_transform, merge_arrays def _check_property(objs: list[Any], prop: str): @@ -33,15 +33,6 @@ def _check_property(objs: list[Any], prop: str): return all(flags) -def _apply_affine_transform(array: np.ndarray | np.memmap, matrix: np.ndarray) -> None: - """Applies in-place the affine transform represented by matrix to the points of array. - :raise ValueError: If array does not have the shape (,3) or if matrix does not have the shape (4,4) - """ - upper_left_matrix = matrix[:3, :3] - translation = matrix[:3, 3] - array[:] = array @ upper_left_matrix.transpose() + translation - - def _merge_image_points( image_points: list[ImagePoints], output_gltf_dir: Path ) -> ImagePoints: @@ -208,7 +199,7 @@ def collapse(pointcloud: GlTFPointCloud, output_gltf_dir: Path) -> GlTFPointClou count = len(node.position) matrix = node.matrix if node.matrix is not None else np.eye(4) matrix = opf_axis_rotation_matrix_inverse @ matrix - _apply_affine_transform(position[offset : offset + count], matrix) + apply_affine_transform(position[offset : offset + count], matrix) offset += count pointcloud.nodes[0].position = position diff --git a/src/pyopf/pointcloud/pcl.py b/src/pyopf/pointcloud/pcl.py index 3896e97..230bda7 100644 --- a/src/pyopf/pointcloud/pcl.py +++ b/src/pyopf/pointcloud/pcl.py @@ -1,7 +1,8 @@ +import math import os from dataclasses import fields from pathlib import Path -from typing import Literal, Optional, Type +from typing import Iterator, Literal, Optional, Type import numpy as np import pygltflib @@ -173,9 +174,13 @@ class Matches: """Used by the OPF_mesh_primitive_matches extension""" camera_uids: list[Uid64] + """List with all cameras UIDs used in this set of matches.""" camera_ids: np.memmap | np.ndarray + """Flat list of camera groups. Each groups is a sublist of indices in the camera_uids list.""" point_index_ranges: PointIndexRanges + """Per point camera index ranges defining the group of cameras matched at that point.""" image_points: Optional[ImagePoints] + """Additional optional information about the matches. The different groups are indexed as camera_ids.""" def __init__(self): self.camera_uids = [] @@ -538,12 +543,17 @@ def _open_accessors( if buffer_view_offset is None: raise RuntimeError("BufferView is missing byteOffset") + if gl_to_numpy_shape(accessor.type) == 1: + shape = accessor.count + else: + shape = (accessor.count, gl_to_numpy_shape(accessor.type)) + new_accessor = np.memmap( base_dir / buffer_uri, mode=mode, dtype=gl_to_numpy_type(accessor.componentType), offset=buffer_view_offset, - shape=(accessor.count, gl_to_numpy_shape(accessor.type)), + shape=shape, ) accessors.append(new_accessor) @@ -591,6 +601,12 @@ def open(gltf_path: Path, mode: mode_type = "r"): return pcl + def __enter__(self) -> "GlTFPointCloud": + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.nodes = [] + def __len__(self) -> int: """The number of nodes in the glTF Point Cloud""" return len(self.nodes) @@ -658,3 +674,46 @@ def write(self, output_gltf_file: Path, save_buffers=True): return [buffer.filepath for buffer in buffers.values()] else: return [path for node in self.nodes for path in node.buffer_filepaths] + + def chunk_iterator( + self, max_chunk_size: int = 10000, yield_indices: bool = True + ) -> Iterator[Node] | Iterator[tuple[Node, int, int]]: + """Access the pointcloud chunk by chunk. Yields node chunks (copied) for each node in the glTF. + This function does not yield matches for memory usage efficiency. + + :param int max_chunk_size: The maximum number of points contained in each node chunk. (default 10'000) + :param yield_indices: If true, will yield a tuple containing the node chunk, and the start and end indices of the + points in the chunk in relation to the total number of points in the glTF. (default True) + :rtype: Iterator[Node] | Iterator[tuple[Node, int, int]] + """ + prev_nodes_len = 0 # Keep track of the points in the previous nodes to yield relevant indices. + + for node in self.nodes: + for i in range(math.ceil(len(node) / max_chunk_size)): + start = i * max_chunk_size + end = start + len(node.position[start : start + max_chunk_size]) + + result = Node() + result.position = node.position[start:end].copy() + + if node.color is not None: + result.color = node.color[start:end].copy() + + if node.normal is not None: + result.normal = node.normal[start:end].copy() + + result.matrix = node.matrix.copy() + + if node.custom_attributes is not None: + result.custom_attributes = { + name: values[start:end] + for name, values in node.custom_attributes.items() + } + + yield ( + result, + start + prev_nodes_len, + end + prev_nodes_len, + ) if yield_indices else result + + prev_nodes_len += len(node) diff --git a/src/pyopf/pointcloud/utils.py b/src/pyopf/pointcloud/utils.py index a9cc739..6d625c4 100644 --- a/src/pyopf/pointcloud/utils.py +++ b/src/pyopf/pointcloud/utils.py @@ -83,7 +83,7 @@ def _numpy_to_gl_shape(count: int) -> str: def merge_arrays(arrays: list[np.ndarray | np.memmap], output_file: Path) -> np.ndarray: - """Merge multiple 2D numpy arrays in a single memory mapped array, along the first dimension. The second dimension must be the same. + """Merge multiple 1D or 2D numpy arrays in a single memory mapped array, along the first dimension. The second dimension must be the same. :param arrays: The list of numpy arrays to merge. :param output_file: The path to the memory mapped file to write. If the file is present, it will be overwritten. @@ -93,11 +93,19 @@ def merge_arrays(arrays: list[np.ndarray | np.memmap], output_file: Path) -> np. :raise ValueError: If any of the arrays is not bi-dimensional, if they do not have matching data types or do not agree in the second dimension """ + if len(arrays) == 0: + raise ValueError("The array list cannot be empty") + + dims = len(arrays[0].shape) + sub_shape = arrays[0].shape[1:] + for a in arrays: - if len(a.shape) != 2: - raise ValueError("Can only merge bi-dimensional arrays") - if a.shape[1] != arrays[0].shape[1]: - raise ValueError("Arrays do not have the same number of columns") + if len(a.shape) != dims: + raise ValueError("Can only merge arrays of the same number of dimensions") + if a.shape[1:] != sub_shape: + raise ValueError( + "Arrays do the same number of elements on all but the first dimension" + ) if a.dtype != arrays[0].dtype: raise ValueError("Arrays do not have the same data types") @@ -108,17 +116,26 @@ def merge_arrays(arrays: list[np.ndarray | np.memmap], output_file: Path) -> np. mode="w+", dtype=arrays[0].dtype, offset=0, - shape=(total_rows, arrays[0].shape[1]), + shape=(total_rows, *sub_shape), ) written_so_far = 0 for a in arrays: - newAccessor[written_so_far : written_so_far + a.shape[0], :] = a + newAccessor[written_so_far : written_so_far + a.shape[0], ...] = a written_so_far += a.shape[0] return newAccessor +def apply_affine_transform(array: np.ndarray | np.memmap, matrix: np.ndarray) -> None: + """Applies in-place the affine transform represented by matrix to the points of array. + :raise ValueError: If array does not have the shape (,3) or if matrix does not have the shape (4,4) + """ + upper_left_matrix = matrix[:3, :3] + translation = matrix[:3, 3] + array[:] = array @ upper_left_matrix.transpose() + translation + + class Buffer: """An abstraction of a glTF buffer whose data is shared by multiple arrays. The arrays are merged into a file before writing. @@ -203,10 +220,12 @@ def add_accessor( buffer_id = buffers[filepath].buffer_id + dims = len(data.shape) + gltf.accessors.append( pygltflib.Accessor( bufferView=buffer_view_id, - type=_numpy_to_gl_shape(data.shape[1]), + type=_numpy_to_gl_shape(data.shape[1] if dims > 1 else 1), count=data.shape[0], componentType=_numpy_to_gl_type(data.dtype), min=None, diff --git a/src/pyopf/project/project.py b/src/pyopf/project/project.py index debc4ed..7f44a73 100644 --- a/src/pyopf/project/project.py +++ b/src/pyopf/project/project.py @@ -45,8 +45,8 @@ def __init__(self, name: str, version: str) -> None: @staticmethod def from_dict(obj: Any) -> "Generator": assert isinstance(obj, dict) - name = from_str(obj.get("name")) - version = from_str(obj.get("version")) + name = from_str(obj["name"]) + version = from_str(obj["version"]) return Generator(name, version) def to_dict(self) -> dict: @@ -78,8 +78,8 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectResource": assert isinstance(obj, dict) - format = from_union([from_format, format_from_str], obj.get("format")) - uri = from_str(obj.get("uri")) + format = from_union([from_format, format_from_str], obj["format"]) + uri = from_str(obj["uri"]) result = ProjectResource(format, uri) result._extract_unknown_properties_and_extensions(obj) return result @@ -110,9 +110,9 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectSource": assert isinstance(obj, dict) - id = UUID(obj.get("id")) + id = UUID(obj["id"]) type = from_union( - [from_project_item_type, project_item_type_from_str], obj.get("type") + [from_project_item_type, project_item_type_from_str], obj["type"] ) result = ProjectSource(id, type) result._extract_unknown_properties_and_extensions(obj) @@ -158,12 +158,12 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "ProjectItem": assert isinstance(obj, dict) - id = UUID(obj.get("id")) + id = UUID(obj["id"]) name = from_union([from_str, from_none], obj.get("name")) - resources = from_list(ProjectResource.from_dict, obj.get("resources")) - sources = from_list(ProjectSource.from_dict, obj.get("sources")) + resources = from_list(ProjectResource.from_dict, obj["resources"]) + sources = from_list(ProjectSource.from_dict, obj["sources"]) type = from_union( - [from_project_item_type, project_item_type_from_str], obj.get("type") + [from_project_item_type, project_item_type_from_str], obj["type"] ) labels = from_union( [lambda x: from_list(from_str, x), from_none], obj.get("labels") @@ -237,14 +237,14 @@ def __init__( @staticmethod def from_dict(obj: Any) -> "Project": assert isinstance(obj, dict) - description = from_str(obj.get("description")) - assert from_str(obj.get("format")) == CoreFormat.PROJECT + description = from_str(obj["description"]) + assert from_str(obj["format"]) == CoreFormat.PROJECT generator = from_union([Generator.from_dict, from_none], obj.get("generator")) - id = UUID(obj.get("id")) - items = from_list(ProjectItem.from_dict, obj.get("items")) - name = from_str(obj.get("name")) - version = from_union([from_version_info, VersionInfo.parse], obj.get("version")) + id = UUID(obj["id"]) + items = from_list(ProjectItem.from_dict, obj["items"]) + name = from_str(obj["name"]) + version = from_union([from_version_info, VersionInfo.parse], obj["version"]) result = Project( id, name, diff --git a/src/pyopf/resolve/resolver.py b/src/pyopf/resolve/resolver.py index 13aa0fe..4b1d322 100644 --- a/src/pyopf/resolve/resolver.py +++ b/src/pyopf/resolve/resolver.py @@ -74,8 +74,13 @@ def resolve(project: Project, supported_extensions=[]): calibration.metadata = Metadata.from_item(item) for resource in item.resources: - - obj = io.load(resource, project.base_uri, item.resources) + try: + obj = io.load(resource, project.base_uri, item.resources) + except io.UnsupportedVersion as e: + print( + f"{e.message}. The entire {calibration.metadata.name} will be ignored." + ) + break if obj is None: continue @@ -84,7 +89,7 @@ def resolve(project: Project, supported_extensions=[]): # Only one GPS bias resource is acceptable if calibration.gps_bias is not None: raise RuntimeError( - "A calibration cannnot contain multiple GPS bias resources" + "A calibration cannot contain multiple GPS bias resources" ) calibration.gps_bias = obj else: @@ -93,7 +98,12 @@ def resolve(project: Project, supported_extensions=[]): result.calibration_objs.append(calibration) elif len(item.resources) == 1 and (is_core_item or is_supported_extension): - obj = io.load(item.resources[0].uri, project.base_uri) + try: + obj = io.load(item.resources[0].uri, project.base_uri) + except io.UnsupportedVersion as e: + if is_core_item: + raise + print(f"{e.message}. The item will be ignored.") obj.metadata = Metadata.from_item(item) if obj.format != item.resources[0].format: diff --git a/src/pyopf/uid64.py b/src/pyopf/uid64.py index 712263f..735386f 100644 --- a/src/pyopf/uid64.py +++ b/src/pyopf/uid64.py @@ -64,6 +64,12 @@ def __hash__(self): def __deepcopy__(self, _memo): return self + def __getstate__(self): + return self.int + + def __setstate__(self, int): + object.__setattr__(self, "int", int) + def uid64(): return Uid64(bytes=os.urandom(8)) diff --git a/src/pyopf/versions.py b/src/pyopf/versions.py index e9ad59a..7b99fb6 100644 --- a/src/pyopf/versions.py +++ b/src/pyopf/versions.py @@ -1,3 +1,4 @@ +from .formats import Format from .VersionInfo import VersionInfo @@ -18,3 +19,17 @@ class FormatVersion: format_and_version_to_type = {} + + +def get_compatible_type(_format: Format, version: VersionInfo) -> type | None: + """Return one of the compatible types for the selected format and version, or None if there are no compatible types.""" + _type = format_and_version_to_type.get((_format, version)) + if _type is None: + for ( + item_format, + item_version, + ), type_candidate in format_and_version_to_type.items(): + if item_format == _format and version.compatible_with(item_version): + _type = type_candidate + + return _type