diff --git a/CHANGELOG.md b/CHANGELOG.md index 9adf45f..78f3ecc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Added new internal parquet dataset processing logic using multiprocessing +- Refactored nodes intersection step from `ST_Intersects` in DuckDB to Shapely's `STRtree` +- `PbfFileReader`'s internal `geometry_filter` is additionally clipped by PBF extract geometry to speed up intersections + +### Added + +- `geoarrow-rust-core` library to the main dependencies +- Test for hashing geometry filter with mixed order +- Test for parquet multiprocessing logic +- Test for new intersection step + ## [0.8.1] - 2024-05-11 ### Added diff --git a/README.md b/README.md index a7b6f27..abafac7 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ Required: - `shapely (>=2.0)`: For parsing WKT and GeoJSON strings and fixing geometries +- `geoarrow-rust-core (>=0.2)`: For transforming Arrow data to Shapely objects + - `polars (>=0.19.4)`: For faster OSM ways grouping operation - `typeguard (>=3.0)`: For internal validation of types diff --git a/pdm.lock b/pdm.lock index 31bbe14..cc953a5 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev", "docs", "license", "lint", "test", "cli", "cli-dev"] strategy = ["cross_platform"] lock_version = "4.4.1" -content_hash = "sha256:18fee9a786c0aec34cb18f9b7237e359068dbb412a2efb5c8a42d2b428875cad" +content_hash = "sha256:063d0250f963dbfe8ed2308871284c9803545f93f8d25713764978768a6a265f" [[package]] name = "adjusttext" @@ -945,6 +945,20 @@ files = [ {file = "geoarrow_pyarrow-0.1.2-py3-none-any.whl", hash = "sha256:c0be5545374fde7ded77f5aef2013cf1ab0e9001cbe4e3b489f55530c6f12c45"}, ] +[[package]] +name = "geoarrow-rust-core" +version = "0.2.0" +requires_python = ">=3.8" +summary = "Efficient, vectorized geospatial operations in Python." +files = [ + {file = "geoarrow_rust_core-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1b16edae465bd39a274918a42f052ec8ff279650d45e48923b2f05eb52480fd1"}, + {file = "geoarrow_rust_core-0.2.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:68f0be67f362dcb97bc3ef48a741a2d3549a311e4489e8df38ef9efc23dd513c"}, + {file = "geoarrow_rust_core-0.2.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:824e184a3d5e29f652ef024fc34bcebc8aea8ae454d9999ed65aa1f2551ed3c1"}, + {file = "geoarrow_rust_core-0.2.0-cp38-abi3-win32.whl", hash = "sha256:834eb61ae91aa6bdf402f4e924b1019526661d5e7d7efefff153c9c86a2272c1"}, + {file = "geoarrow_rust_core-0.2.0-cp38-abi3-win_amd64.whl", hash = "sha256:80e2c773235e50e2bee1819c7b44cf3d298c37e334c47111ed58345804f09319"}, + {file = "geoarrow_rust_core-0.2.0.tar.gz", hash = "sha256:4f293c7e36ff2206d3e7dd96342897c1b2634618c2cfb9175574ef2705ea825f"}, +] + [[package]] name = "geopandas" version = "0.14.4" @@ -986,15 +1000,15 @@ files = [ [[package]] name = "griffe" -version = "0.44.0" +version = "0.45.0" requires_python = ">=3.8" summary = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." dependencies = [ "colorama>=0.4", ] files = [ - {file = "griffe-0.44.0-py3-none-any.whl", hash = "sha256:8a4471c469ba980b87c843f1168850ce39d0c1d0c7be140dca2480f76c8e5446"}, - {file = "griffe-0.44.0.tar.gz", hash = "sha256:34aee1571042f9bf00529bc715de4516fb6f482b164e90d030300601009e0223"}, + {file = "griffe-0.45.0-py3-none-any.whl", hash = "sha256:90fe5c90e1b0ca7dd6fee78f9009f4e01b37dbc9ab484a9b2c1578915db1e571"}, + {file = "griffe-0.45.0.tar.gz", hash = "sha256:85cb2868d026ea51c89bdd589ad3ccc94abc5bd8d5d948e3d4450778a2a05b4a"}, ] [[package]] @@ -1492,7 +1506,7 @@ files = [ [[package]] name = "jupyterlab" -version = "4.1.8" +version = "4.2.0" requires_python = ">=3.8" summary = "JupyterLab computational environment" dependencies = [ @@ -1512,8 +1526,8 @@ dependencies = [ "traitlets", ] files = [ - {file = "jupyterlab-4.1.8-py3-none-any.whl", hash = "sha256:c3baf3a2f91f89d110ed5786cd18672b9a357129d4e389d2a0dead15e11a4d2c"}, - {file = "jupyterlab-4.1.8.tar.gz", hash = "sha256:3384aded8680e7ce504fd63b8bb89a39df21c9c7694d9e7dc4a68742cdb30f9b"}, + {file = "jupyterlab-4.2.0-py3-none-any.whl", hash = "sha256:0dfe9278e25a145362289c555d9beb505697d269c10e99909766af7c440ad3cc"}, + {file = "jupyterlab-4.2.0.tar.gz", hash = "sha256:356e9205a6a2ab689c47c8fe4919dba6c076e376d03f26baadc05748c2435dd5"}, ] [[package]] @@ -1806,7 +1820,7 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.4" +version = "3.9.0" requires_python = ">=3.9" summary = "Python plotting package" dependencies = [ @@ -1815,41 +1829,42 @@ dependencies = [ "fonttools>=4.22.0", "importlib-resources>=3.2.0; python_version < \"3.10\"", "kiwisolver>=1.3.1", - "numpy>=1.21", + "numpy>=1.23", "packaging>=20.0", "pillow>=8", "pyparsing>=2.3.1", "python-dateutil>=2.7", ] files = [ - {file = "matplotlib-3.8.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014"}, - {file = "matplotlib-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106"}, - {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10"}, - {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0"}, - {file = "matplotlib-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef"}, - {file = "matplotlib-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338"}, - {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"}, - {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"}, - {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"}, - {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"}, - {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"}, - {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"}, - {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"}, - {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"}, - {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"}, - {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"}, - {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"}, - {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"}, - {file = "matplotlib-3.8.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6"}, - {file = "matplotlib-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67"}, - {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc"}, - {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9"}, - {file = "matplotlib-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54"}, - {file = "matplotlib-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"}, - {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"}, + {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, + {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, + {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, + {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, + {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, + {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, + {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, + {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, + {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, + {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, + {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, ] [[package]] @@ -1867,15 +1882,15 @@ files = [ [[package]] name = "mdit-py-plugins" -version = "0.4.0" +version = "0.4.1" requires_python = ">=3.8" summary = "Collection of plugins for markdown-it-py" dependencies = [ "markdown-it-py<4.0.0,>=1.0.0", ] files = [ - {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"}, - {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"}, + {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, + {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, ] [[package]] @@ -2027,7 +2042,7 @@ files = [ [[package]] name = "mkdocs-material" -version = "9.5.21" +version = "9.5.23" requires_python = ">=3.8" summary = "Documentation that simply works" dependencies = [ @@ -2044,8 +2059,8 @@ dependencies = [ "requests~=2.26", ] files = [ - {file = "mkdocs_material-9.5.21-py3-none-any.whl", hash = "sha256:210e1f179682cd4be17d5c641b2f4559574b9dea2f589c3f0e7c17c5bd1959bc"}, - {file = "mkdocs_material-9.5.21.tar.gz", hash = "sha256:049f82770f40559d3c2aa2259c562ea7257dbb4aaa9624323b5ef27b2d95a450"}, + {file = "mkdocs_material-9.5.23-py3-none-any.whl", hash = "sha256:ffd08a5beaef3cd135aceb58ded8b98bbbbf2b70e5b656f6a14a63c917d9b001"}, + {file = "mkdocs_material-9.5.23.tar.gz", hash = "sha256:4627fc3f15de2cba2bde9debc2fd59b9888ef494beabfe67eb352e23d14bf288"}, ] [[package]] @@ -2100,16 +2115,16 @@ files = [ [[package]] name = "mkdocstrings-python" -version = "1.10.0" +version = "1.10.2" requires_python = ">=3.8" summary = "A Python handler for mkdocstrings." dependencies = [ "griffe>=0.44", - "mkdocstrings>=0.24.2", + "mkdocstrings>=0.25", ] files = [ - {file = "mkdocstrings_python-1.10.0-py3-none-any.whl", hash = "sha256:ba833fbd9d178a4b9d5cb2553a4df06e51dc1f51e41559a4d2398c16a6f69ecc"}, - {file = "mkdocstrings_python-1.10.0.tar.gz", hash = "sha256:71678fac657d4d2bb301eed4e4d2d91499c095fd1f8a90fa76422a87a5693828"}, + {file = "mkdocstrings_python-1.10.2-py3-none-any.whl", hash = "sha256:e8e596b37f45c09b67bec253e035fe18988af5bbbbf44e0ccd711742eed750e5"}, + {file = "mkdocstrings_python-1.10.2.tar.gz", hash = "sha256:38a4fd41953defb458a107033440c229c7e9f98f35a24e84d888789c97da5a63"}, ] [[package]] @@ -2277,19 +2292,19 @@ files = [ [[package]] name = "notebook" -version = "7.1.3" +version = "7.2.0" requires_python = ">=3.8" summary = "Jupyter Notebook - A web-based notebook environment for interactive computing" dependencies = [ "jupyter-server<3,>=2.4.0", - "jupyterlab-server<3,>=2.22.1", - "jupyterlab<4.2,>=4.1.1", + "jupyterlab-server<3,>=2.27.1", + "jupyterlab<4.3,>=4.2.0", "notebook-shim<0.3,>=0.2", "tornado>=6.2.0", ] files = [ - {file = "notebook-7.1.3-py3-none-any.whl", hash = "sha256:919b911e59f41f6e3857ce93c9d93535ba66bb090059712770e5968c07e1004d"}, - {file = "notebook-7.1.3.tar.gz", hash = "sha256:41fcebff44cf7bb9377180808bcbae066629b55d8c7722f1ebbe75ca44f9cfc1"}, + {file = "notebook-7.2.0-py3-none-any.whl", hash = "sha256:b4752d7407d6c8872fc505df0f00d3cae46e8efb033b822adacbaa3f1f3ce8f5"}, + {file = "notebook-7.2.0.tar.gz", hash = "sha256:34a2ba4b08ad5d19ec930db7484fb79746a1784be9e1a5f8218f9af8656a141f"}, ] [[package]] @@ -2551,12 +2566,12 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.1" +version = "4.2.2" requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." files = [ - {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, - {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [[package]] @@ -2571,16 +2586,16 @@ files = [ [[package]] name = "polars" -version = "0.20.25" +version = "0.20.26" requires_python = ">=3.8" summary = "Blazingly fast DataFrame library" files = [ - {file = "polars-0.20.25-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:126e3b7d9394e4b23b4cc48919b7188203feeeb35d861ad808f281eaa06d76e2"}, - {file = "polars-0.20.25-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:3bda62b681726538714a1159638ab7c9eeca6b8633fd778d84810c3e13b9c7e3"}, - {file = "polars-0.20.25-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62c8826e81c759f07bf5c0ae00f57a537644ae05fe68737185666b8ad8430664"}, - {file = "polars-0.20.25-cp38-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:0fb5e7a4a9831fba742f1c706e01656607089b6362a5e6f8d579b134a99795ce"}, - {file = "polars-0.20.25-cp38-abi3-win_amd64.whl", hash = "sha256:9eaeb9080c853e11b207d191025e0ba8fd59ea06a36c22d410a48f2f124e18cd"}, - {file = "polars-0.20.25.tar.gz", hash = "sha256:4308d63f956874bac9ae040bdd6d62b2992d0b1e1349301bc7a3b59458189108"}, + {file = "polars-0.20.26-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:97d0e4b6ab6b47fa07798b447189ee9505d2085ec1a64a6aa8a65fdd429cd49f"}, + {file = "polars-0.20.26-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c270e366b4d8b672b204e7d48e39d255641d3d2b7bdc3a0ccd968cf53934657f"}, + {file = "polars-0.20.26-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db35d6eed508256a797c7f1b8e9dec4aae9c11b891797b2d38fac5627d072d34"}, + {file = "polars-0.20.26-cp38-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:25b00bd5cf44929722aa6389706559c5e8cedd6db2cfc38b27b706ed37e1b2af"}, + {file = "polars-0.20.26-cp38-abi3-win_amd64.whl", hash = "sha256:b22063acc815bc5c6d2e24292ff771ca0df306ecf97e8f6899924a1ec6d3f136"}, + {file = "polars-0.20.26.tar.gz", hash = "sha256:fa83d130562a5180a47f8763a7bb9f408dbbf51eafc1380e8a2951be8ce05a2c"}, ] [[package]] @@ -2682,42 +2697,42 @@ files = [ [[package]] name = "pyarrow" -version = "16.0.0" +version = "16.1.0" requires_python = ">=3.8" summary = "Python library for Apache Arrow" dependencies = [ "numpy>=1.16.6", ] files = [ - {file = "pyarrow-16.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:22a1fdb1254e5095d629e29cd1ea98ed04b4bbfd8e42cc670a6b639ccc208b60"}, - {file = "pyarrow-16.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:574a00260a4ed9d118a14770edbd440b848fcae5a3024128be9d0274dbcaf858"}, - {file = "pyarrow-16.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0815d0ddb733b8c1b53a05827a91f1b8bde6240f3b20bf9ba5d650eb9b89cdf"}, - {file = "pyarrow-16.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df0080339387b5d30de31e0a149c0c11a827a10c82f0c67d9afae3981d1aabb7"}, - {file = "pyarrow-16.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:edf38cce0bf0dcf726e074159c60516447e4474904c0033f018c1f33d7dac6c5"}, - {file = "pyarrow-16.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:91d28f9a40f1264eab2af7905a4d95320ac2f287891e9c8b0035f264fe3c3a4b"}, - {file = "pyarrow-16.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:99af421ee451a78884d7faea23816c429e263bd3618b22d38e7992c9ce2a7ad9"}, - {file = "pyarrow-16.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d22d0941e6c7bafddf5f4c0662e46f2075850f1c044bf1a03150dd9e189427ce"}, - {file = "pyarrow-16.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:266ddb7e823f03733c15adc8b5078db2df6980f9aa93d6bb57ece615df4e0ba7"}, - {file = "pyarrow-16.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cc23090224b6594f5a92d26ad47465af47c1d9c079dd4a0061ae39551889efe"}, - {file = "pyarrow-16.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56850a0afe9ef37249d5387355449c0f94d12ff7994af88f16803a26d38f2016"}, - {file = "pyarrow-16.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:705db70d3e2293c2f6f8e84874b5b775f690465798f66e94bb2c07bab0a6bb55"}, - {file = "pyarrow-16.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:5448564754c154997bc09e95a44b81b9e31ae918a86c0fcb35c4aa4922756f55"}, - {file = "pyarrow-16.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:729f7b262aa620c9df8b9967db96c1575e4cfc8c25d078a06968e527b8d6ec05"}, - {file = "pyarrow-16.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:fb8065dbc0d051bf2ae2453af0484d99a43135cadabacf0af588a3be81fbbb9b"}, - {file = "pyarrow-16.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20ce707d9aa390593ea93218b19d0eadab56390311cb87aad32c9a869b0e958c"}, - {file = "pyarrow-16.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5823275c8addbbb50cd4e6a6839952682a33255b447277e37a6f518d6972f4e1"}, - {file = "pyarrow-16.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ab8b9050752b16a8b53fcd9853bf07d8daf19093533e990085168f40c64d978"}, - {file = "pyarrow-16.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:42e56557bc7c5c10d3e42c3b32f6cff649a29d637e8f4e8b311d334cc4326730"}, - {file = "pyarrow-16.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:2a7abdee4a4a7cfa239e2e8d721224c4b34ffe69a0ca7981354fe03c1328789b"}, - {file = "pyarrow-16.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:ef2f309b68396bcc5a354106741d333494d6a0d3e1951271849787109f0229a6"}, - {file = "pyarrow-16.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:b93c9a50b965ee0bf4fef65e53b758a7e8dcc0c2d86cebcc037aaaf1b306ecc0"}, - {file = "pyarrow-16.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d831690844706e374c455fba2fb8cfcb7b797bfe53ceda4b54334316e1ac4fa4"}, - {file = "pyarrow-16.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35692ce8ad0b8c666aa60f83950957096d92f2a9d8d7deda93fb835e6053307e"}, - {file = "pyarrow-16.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dd3151d098e56f16a8389c1247137f9e4c22720b01c6f3aa6dec29a99b74d80"}, - {file = "pyarrow-16.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:bd40467bdb3cbaf2044ed7a6f7f251c8f941c8b31275aaaf88e746c4f3ca4a7a"}, - {file = "pyarrow-16.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:00a1dcb22ad4ceb8af87f7bd30cc3354788776c417f493089e0a0af981bc8d80"}, - {file = "pyarrow-16.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:fda9a7cebd1b1d46c97b511f60f73a5b766a6de4c5236f144f41a5d5afec1f35"}, - {file = "pyarrow-16.0.0.tar.gz", hash = "sha256:59bb1f1edbbf4114c72415f039f1359f1a57d166a331c3229788ccbfbb31689a"}, + {file = "pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9"}, + {file = "pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd"}, + {file = "pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b"}, + {file = "pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7"}, + {file = "pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3"}, + {file = "pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a"}, + {file = "pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315"}, ] [[package]] @@ -3176,73 +3191,73 @@ files = [ [[package]] name = "regex" -version = "2024.5.10" +version = "2024.5.15" requires_python = ">=3.8" summary = "Alternative regular expression module, to replace re." files = [ - {file = "regex-2024.5.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:eda3dd46df535da787ffb9036b5140f941ecb91701717df91c9daf64cabef953"}, - {file = "regex-2024.5.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d5bd666466c8f00a06886ce1397ba8b12371c1f1c6d1bef11013e9e0a1464a8"}, - {file = "regex-2024.5.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:32e5f3b8e32918bfbdd12eca62e49ab3031125c454b507127ad6ecbd86e62fca"}, - {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:534efd2653ebc4f26fc0e47234e53bf0cb4715bb61f98c64d2774a278b58c846"}, - {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:193b7c6834a06f722f0ce1ba685efe80881de7c3de31415513862f601097648c"}, - {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:160ba087232c5c6e2a1e7ad08bd3a3f49b58c815be0504d8c8aacfb064491cd8"}, - {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:951be1eae7b47660412dc4938777a975ebc41936d64e28081bf2e584b47ec246"}, - {file = "regex-2024.5.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8a0f0ab5453e409586b11ebe91c672040bc804ca98d03a656825f7890cbdf88"}, - {file = "regex-2024.5.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9e6d4d6ae1827b2f8c7200aaf7501c37cf3f3896c86a6aaf2566448397c823dd"}, - {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:161a206c8f3511e2f5fafc9142a2cc25d7fe9a1ec5ad9b4ad2496a7c33e1c5d2"}, - {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:44b3267cea873684af022822195298501568ed44d542f9a2d9bebc0212e99069"}, - {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:560278c9975694e1f0bc50da187abf2cdc1e4890739ea33df2bc4a85eeef143e"}, - {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:70364a097437dd0a90b31cd77f09f7387ad9ac60ef57590971f43b7fca3082a5"}, - {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:42be5de7cc8c1edac55db92d82b68dc8e683b204d6f5414c5a51997a323d7081"}, - {file = "regex-2024.5.10-cp310-cp310-win32.whl", hash = "sha256:9a8625849387b9d558d528e263ecc9c0fbde86cfa5c2f0eef43fff480ae24d71"}, - {file = "regex-2024.5.10-cp310-cp310-win_amd64.whl", hash = "sha256:903350bf44d7e4116b4d5898b30b15755d61dcd3161e3413a49c7db76f0bee5a"}, - {file = "regex-2024.5.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bf9596cba92ce7b1fd32c7b07c6e3212c7eed0edc271757e48bfcd2b54646452"}, - {file = "regex-2024.5.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:45cc13d398b6359a7708986386f72bd156ae781c3e83a68a6d4cee5af04b1ce9"}, - {file = "regex-2024.5.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ad45f3bccfcb00868f2871dce02a755529838d2b86163ab8a246115e80cfb7d6"}, - {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33d19f0cde6838c81acffff25c7708e4adc7dd02896c9ec25c3939b1500a1778"}, - {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9f89d7db5ef6bdf53e5cc8e6199a493d0f1374b3171796b464a74ebe8e508a"}, - {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c6c71cf92b09e5faa72ea2c68aa1f61c9ce11cb66fdc5069d712f4392ddfd00"}, - {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7467ad8b0eac0b28e52679e972b9b234b3de0ea5cee12eb50091d2b68145fe36"}, - {file = "regex-2024.5.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc0db93ad039fc2fe32ccd3dd0e0e70c4f3d6e37ae83f0a487e1aba939bd2fbd"}, - {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fa9335674d7c819674467c7b46154196c51efbaf5f5715187fd366814ba3fa39"}, - {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7dda3091838206969c2b286f9832dff41e2da545b99d1cfaea9ebd8584d02708"}, - {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:504b5116e2bd1821efd815941edff7535e93372a098e156bb9dffde30264e798"}, - {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:91b53dea84415e8115506cc62e441a2b54537359c63d856d73cb1abe05af4c9a"}, - {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a3903128f9e17a500618e80c68165c78c741ebb17dd1a0b44575f92c3c68b02"}, - {file = "regex-2024.5.10-cp311-cp311-win32.whl", hash = "sha256:236cace6c1903effd647ed46ce6dd5d76d54985fc36dafc5256032886736c85d"}, - {file = "regex-2024.5.10-cp311-cp311-win_amd64.whl", hash = "sha256:12446827f43c7881decf2c126762e11425de5eb93b3b0d8b581344c16db7047a"}, - {file = "regex-2024.5.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:14905ed75c7a6edf423eb46c213ed3f4507c38115f1ed3c00f4ec9eafba50e58"}, - {file = "regex-2024.5.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4fad420b14ae1970a1f322e8ae84a1d9d89375eb71e1b504060ab2d1bfe68f3c"}, - {file = "regex-2024.5.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c46a76a599fcbf95f98755275c5527304cc4f1bb69919434c1e15544d7052910"}, - {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0faecb6d5779753a6066a3c7a0471a8d29fe25d9981ca9e552d6d1b8f8b6a594"}, - {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aab65121229c2ecdf4a31b793d99a6a0501225bd39b616e653c87b219ed34a49"}, - {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50e7e96a527488334379e05755b210b7da4a60fc5d6481938c1fa053e0c92184"}, - {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba034c8db4b264ef1601eb33cd23d87c5013b8fb48b8161debe2e5d3bd9156b0"}, - {file = "regex-2024.5.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:031219782d97550c2098d9a68ce9e9eaefe67d2d81d8ff84c8354f9c009e720c"}, - {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:62b5f7910b639f3c1d122d408421317c351e213ca39c964ad4121f27916631c6"}, - {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cd832bd9b6120d6074f39bdfbb3c80e416848b07ac72910f1c7f03131a6debc3"}, - {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:e91b1976358e17197157b405cab408a5f4e33310cda211c49fc6da7cffd0b2f0"}, - {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:571452362d552de508c37191b6abbbb660028b8b418e2d68c20779e0bc8eaaa8"}, - {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5253dcb0bfda7214523de58b002eb0090cb530d7c55993ce5f6d17faf953ece7"}, - {file = "regex-2024.5.10-cp312-cp312-win32.whl", hash = "sha256:2f30a5ab8902f93930dc6f627c4dd5da2703333287081c85cace0fc6e21c25af"}, - {file = "regex-2024.5.10-cp312-cp312-win_amd64.whl", hash = "sha256:3799e36d60a35162bb35b2246d8bb012192b7437dff807ef79c14e7352706306"}, - {file = "regex-2024.5.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:15e593386ec6331e0ab4ac0795b7593f02ab2f4b30a698beb89fbdc34f92386a"}, - {file = "regex-2024.5.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ca23b41355ba95929e9505ee04e55495726aa2282003ed9b012d86f857d3e49b"}, - {file = "regex-2024.5.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c8982ee19ccecabbaeac1ba687bfef085a6352a8c64f821ce2f43e6d76a9298"}, - {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7117cb7d6ac7f2e985f3d18aa8a1728864097da1a677ffa69e970ca215baebf1"}, - {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b66421f8878a0c82fc0c272a43e2121c8d4c67cb37429b764f0d5ad70b82993b"}, - {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:224a9269f133564109ce668213ef3cb32bc72ccf040b0b51c72a50e569e9dc9e"}, - {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab98016541543692a37905871a5ffca59b16e08aacc3d7d10a27297b443f572d"}, - {file = "regex-2024.5.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51d27844763c273a122e08a3e86e7aefa54ee09fb672d96a645ece0454d8425e"}, - {file = "regex-2024.5.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:853cc36e756ff673bf984e9044ccc8fad60b95a748915dddeab9488aea974c73"}, - {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4e7eaf9df15423d07b6050fb91f86c66307171b95ea53e2d87a7993b6d02c7f7"}, - {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:169fd0acd7a259f58f417e492e93d0e15fc87592cd1e971c8c533ad5703b5830"}, - {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:334b79ce9c08f26b4659a53f42892793948a613c46f1b583e985fd5a6bf1c149"}, - {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f03b1dbd4d9596dd84955bb40f7d885204d6aac0d56a919bb1e0ff2fb7e1735a"}, - {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfa6d61a76c77610ba9274c1a90a453062bdf6887858afbe214d18ad41cf6bde"}, - {file = "regex-2024.5.10-cp39-cp39-win32.whl", hash = "sha256:249fbcee0a277c32a3ce36d8e36d50c27c968fdf969e0fbe342658d4e010fbc8"}, - {file = "regex-2024.5.10-cp39-cp39-win_amd64.whl", hash = "sha256:0ce56a923f4c01d7568811bfdffe156268c0a7aae8a94c902b92fe34c4bde785"}, - {file = "regex-2024.5.10.tar.gz", hash = "sha256:304e7e2418146ae4d0ef0e9ffa28f881f7874b45b4994cc2279b21b6e7ae50c8"}, + {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a81e3cfbae20378d75185171587cbf756015ccb14840702944f014e0d93ea09f"}, + {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b59138b219ffa8979013be7bc85bb60c6f7b7575df3d56dc1e403a438c7a3f6"}, + {file = "regex-2024.5.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0bd000c6e266927cb7a1bc39d55be95c4b4f65c5be53e659537537e019232b1"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eaa7ddaf517aa095fa8da0b5015c44d03da83f5bd49c87961e3c997daed0de7"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba68168daedb2c0bab7fd7e00ced5ba90aebf91024dea3c88ad5063c2a562cca"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e8d717bca3a6e2064fc3a08df5cbe366369f4b052dcd21b7416e6d71620dca1"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1337b7dbef9b2f71121cdbf1e97e40de33ff114801263b275aafd75303bd62b5"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9ebd0a36102fcad2f03696e8af4ae682793a5d30b46c647eaf280d6cfb32796"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9efa1a32ad3a3ea112224897cdaeb6aa00381627f567179c0314f7b65d354c62"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1595f2d10dff3d805e054ebdc41c124753631b6a471b976963c7b28543cf13b0"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b802512f3e1f480f41ab5f2cfc0e2f761f08a1f41092d6718868082fc0d27143"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a0981022dccabca811e8171f913de05720590c915b033b7e601f35ce4ea7019f"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:19068a6a79cf99a19ccefa44610491e9ca02c2be3305c7760d3831d38a467a6f"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1b5269484f6126eee5e687785e83c6b60aad7663dafe842b34691157e5083e53"}, + {file = "regex-2024.5.15-cp310-cp310-win32.whl", hash = "sha256:ada150c5adfa8fbcbf321c30c751dc67d2f12f15bd183ffe4ec7cde351d945b3"}, + {file = "regex-2024.5.15-cp310-cp310-win_amd64.whl", hash = "sha256:ac394ff680fc46b97487941f5e6ae49a9f30ea41c6c6804832063f14b2a5a145"}, + {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f5b1dff3ad008dccf18e652283f5e5339d70bf8ba7c98bf848ac33db10f7bc7a"}, + {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c6a2b494a76983df8e3d3feea9b9ffdd558b247e60b92f877f93a1ff43d26656"}, + {file = "regex-2024.5.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a32b96f15c8ab2e7d27655969a23895eb799de3665fa94349f3b2fbfd547236f"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10002e86e6068d9e1c91eae8295ef690f02f913c57db120b58fdd35a6bb1af35"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec54d5afa89c19c6dd8541a133be51ee1017a38b412b1321ccb8d6ddbeb4cf7d"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10e4ce0dca9ae7a66e6089bb29355d4432caed736acae36fef0fdd7879f0b0cb"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e507ff1e74373c4d3038195fdd2af30d297b4f0950eeda6f515ae3d84a1770f"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1f059a4d795e646e1c37665b9d06062c62d0e8cc3c511fe01315973a6542e40"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0721931ad5fe0dda45d07f9820b90b2148ccdd8e45bb9e9b42a146cb4f695649"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:833616ddc75ad595dee848ad984d067f2f31be645d603e4d158bba656bbf516c"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:287eb7f54fc81546346207c533ad3c2c51a8d61075127d7f6d79aaf96cdee890"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:19dfb1c504781a136a80ecd1fff9f16dddf5bb43cec6871778c8a907a085bb3d"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:119af6e56dce35e8dfb5222573b50c89e5508d94d55713c75126b753f834de68"}, + {file = "regex-2024.5.15-cp311-cp311-win32.whl", hash = "sha256:1c1c174d6ec38d6c8a7504087358ce9213d4332f6293a94fbf5249992ba54efa"}, + {file = "regex-2024.5.15-cp311-cp311-win_amd64.whl", hash = "sha256:9e717956dcfd656f5055cc70996ee2cc82ac5149517fc8e1b60261b907740201"}, + {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:632b01153e5248c134007209b5c6348a544ce96c46005d8456de1d552455b014"}, + {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e64198f6b856d48192bf921421fdd8ad8eb35e179086e99e99f711957ffedd6e"}, + {file = "regex-2024.5.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68811ab14087b2f6e0fc0c2bae9ad689ea3584cad6917fc57be6a48bbd012c49"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ec0c2fea1e886a19c3bee0cd19d862b3aa75dcdfb42ebe8ed30708df64687a"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0c0c0003c10f54a591d220997dd27d953cd9ccc1a7294b40a4be5312be8797b"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2431b9e263af1953c55abbd3e2efca67ca80a3de8a0437cb58e2421f8184717a"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a605586358893b483976cffc1723fb0f83e526e8f14c6e6614e75919d9862cf"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391d7f7f1e409d192dba8bcd42d3e4cf9e598f3979cdaed6ab11288da88cb9f2"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9ff11639a8d98969c863d4617595eb5425fd12f7c5ef6621a4b74b71ed8726d5"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4eee78a04e6c67e8391edd4dad3279828dd66ac4b79570ec998e2155d2e59fd5"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8fe45aa3f4aa57faabbc9cb46a93363edd6197cbc43523daea044e9ff2fea83e"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d0a3d8d6acf0c78a1fff0e210d224b821081330b8524e3e2bc5a68ef6ab5803d"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c486b4106066d502495b3025a0a7251bf37ea9540433940a23419461ab9f2a80"}, + {file = "regex-2024.5.15-cp312-cp312-win32.whl", hash = "sha256:c49e15eac7c149f3670b3e27f1f28a2c1ddeccd3a2812cba953e01be2ab9b5fe"}, + {file = "regex-2024.5.15-cp312-cp312-win_amd64.whl", hash = "sha256:673b5a6da4557b975c6c90198588181029c60793835ce02f497ea817ff647cb2"}, + {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13cdaf31bed30a1e1c2453ef6015aa0983e1366fad2667657dbcac7b02f67133"}, + {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cac27dcaa821ca271855a32188aa61d12decb6fe45ffe3e722401fe61e323cd1"}, + {file = "regex-2024.5.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7dbe2467273b875ea2de38ded4eba86cbcbc9a1a6d0aa11dcf7bd2e67859c435"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f18a9a3513a99c4bef0e3efd4c4a5b11228b48aa80743be822b71e132ae4f5"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d347a741ea871c2e278fde6c48f85136c96b8659b632fb57a7d1ce1872547600"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1878b8301ed011704aea4c806a3cadbd76f84dece1ec09cc9e4dc934cfa5d4da"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4babf07ad476aaf7830d77000874d7611704a7fcf68c9c2ad151f5d94ae4bfc4"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35cb514e137cb3488bce23352af3e12fb0dbedd1ee6e60da053c69fb1b29cc6c"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cdd09d47c0b2efee9378679f8510ee6955d329424c659ab3c5e3a6edea696294"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:72d7a99cd6b8f958e85fc6ca5b37c4303294954eac1376535b03c2a43eb72629"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a094801d379ab20c2135529948cb84d417a2169b9bdceda2a36f5f10977ebc16"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c0c18345010870e58238790a6779a1219b4d97bd2e77e1140e8ee5d14df071aa"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:16093f563098448ff6b1fa68170e4acbef94e6b6a4e25e10eae8598bb1694b5d"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e38a7d4e8f633a33b4c7350fbd8bad3b70bf81439ac67ac38916c4a86b465456"}, + {file = "regex-2024.5.15-cp39-cp39-win32.whl", hash = "sha256:71a455a3c584a88f654b64feccc1e25876066c4f5ef26cd6dd711308aa538694"}, + {file = "regex-2024.5.15-cp39-cp39-win_amd64.whl", hash = "sha256:cab12877a9bdafde5500206d1020a584355a97884dfd388af3699e9137bf7388"}, + {file = "regex-2024.5.15.tar.gz", hash = "sha256:d3ee02d9e5f482cc8309134a91eeaacbdd2261ba111b0fef3748eeb4913e6a2c"}, ] [[package]] @@ -3790,7 +3805,7 @@ files = [ [[package]] name = "topojson" -version = "1.8" +version = "1.9" requires_python = ">=3.8" summary = "topojson - a powerful library to encode geographic data as topology in Python!🌍" dependencies = [ @@ -3799,8 +3814,8 @@ dependencies = [ "shapely", ] files = [ - {file = "topojson-1.8-py3-none-any.whl", hash = "sha256:67ac4c6b803ef12fd1f02eb9f66791ba32fbff80e60c05d18a12ad9b88ff493a"}, - {file = "topojson-1.8.tar.gz", hash = "sha256:1363933c31cd9ba3dd9cf9df96bbd3ffe56126bd0396f0295a41b48c5666de08"}, + {file = "topojson-1.9-py3-none-any.whl", hash = "sha256:122e6e91fb422549644504580eee86f8a37703dc5ccb1a8e6d8928b750706fe7"}, + {file = "topojson-1.9.tar.gz", hash = "sha256:5a8389ff576d5540660d4430dab56fcadef7c1f90b9f1aa486b1cb140033ff3b"}, ] [[package]] @@ -4020,7 +4035,7 @@ files = [ [[package]] name = "virtualenv" -version = "20.26.1" +version = "20.26.2" requires_python = ">=3.7" summary = "Virtual Python Environment builder" dependencies = [ @@ -4029,8 +4044,8 @@ dependencies = [ "platformdirs<5,>=3.9.1", ] files = [ - {file = "virtualenv-20.26.1-py3-none-any.whl", hash = "sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75"}, - {file = "virtualenv-20.26.1.tar.gz", hash = "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b"}, + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, ] [[package]] @@ -4069,15 +4084,15 @@ files = [ [[package]] name = "wcmatch" -version = "8.5.1" +version = "8.5.2" requires_python = ">=3.8" summary = "Wildcard/glob file name matcher." dependencies = [ "bracex>=2.1.1", ] files = [ - {file = "wcmatch-8.5.1-py3-none-any.whl", hash = "sha256:24c19cedc92bc9c9e27f39db4e1824d72f95bd2cea32b254a47a45b1a1b227ed"}, - {file = "wcmatch-8.5.1.tar.gz", hash = "sha256:c0088c7f6426cf6bf27e530e2b7b734031905f7e490475fd83c7c5008ab581b3"}, + {file = "wcmatch-8.5.2-py3-none-any.whl", hash = "sha256:17d3ad3758f9d0b5b4dedc770b65420d4dac62e680229c287bf24c9db856a478"}, + {file = "wcmatch-8.5.2.tar.gz", hash = "sha256:a70222b86dea82fb382dd87b73278c10756c138bd6f8f714e2183128887b9eb2"}, ] [[package]] @@ -4150,10 +4165,10 @@ files = [ [[package]] name = "zipp" -version = "3.18.1" +version = "3.18.2" requires_python = ">=3.8" summary = "Backport of pathlib-compatible object wrapper for zip files" files = [ - {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, - {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, + {file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"}, + {file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"}, ] diff --git a/pyproject.toml b/pyproject.toml index a73c7b0..37e9e41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ dependencies = [ "requests", "polars>=0.19.4", "rich>=10.11.0", + "geoarrow-rust-core>=0.2.0", ] requires-python = ">=3.9" readme = "README.md" diff --git a/quackosm/__main__.py b/quackosm/__main__.py index f1f238b..62e610d 100644 --- a/quackosm/__main__.py +++ b/quackosm/__main__.py @@ -12,8 +12,8 @@ def main() -> None: ) raise ImportError(error_msg) from exc - cli.app(prog_name=__app_name__) + cli.app(prog_name=__app_name__) # pragma: no cover -if __name__ == "__main__": +if __name__ == "__main__": # pragma: no cover main() diff --git a/quackosm/_intersection.py b/quackosm/_intersection.py new file mode 100644 index 0000000..7c3be52 --- /dev/null +++ b/quackosm/_intersection.py @@ -0,0 +1,52 @@ +from functools import partial +from pathlib import Path +from typing import Optional + +import pyarrow as pa +from geoarrow.rust.core import PointArray +from shapely import STRtree +from shapely.geometry.base import BaseGeometry + +from quackosm._parquet_multiprocessing import map_parquet_dataset +from quackosm._rich_progress import TaskProgressBar # type: ignore[attr-defined] + + +def _intersect_nodes( + table: pa.Table, + geometry_filter: BaseGeometry, +) -> pa.Table: # pragma: no cover + points_array = PointArray.from_xy( + x=table["lon"].combine_chunks(), y=table["lat"].combine_chunks() + ) + + tree = STRtree(points_array.to_shapely()) + + intersecting_ids_array = table["id"].take(tree.query(geometry_filter, predicate="intersects")) + + return pa.table({"id": intersecting_ids_array}) + + +def intersect_nodes_with_geometry( + tmp_dir_path: Path, + geometry_filter: BaseGeometry, + progress_bar: Optional[TaskProgressBar] = None, +) -> None: + """ + Intersects nodes points with geometry filter using spatial index with multiprocessing. + + Args: + tmp_dir_path (Path): Path of the working directory. + geometry_filter (BaseGeometry): Geometry used for filtering. + progress_bar (Optional[TaskProgressBar]): Progress bar to show task status. + Defaults to `None` + """ + dataset_path = tmp_dir_path / "nodes_valid_with_tags" + destination_path = tmp_dir_path / "nodes_intersecting_ids" + + map_parquet_dataset( + dataset_path=dataset_path, + destination_path=destination_path, + progress_bar=progress_bar, + function=partial(_intersect_nodes, geometry_filter=geometry_filter), + columns=["id", "lat", "lon"], + ) diff --git a/quackosm/_parquet_multiprocessing.py b/quackosm/_parquet_multiprocessing.py new file mode 100644 index 0000000..5a0ede7 --- /dev/null +++ b/quackosm/_parquet_multiprocessing.py @@ -0,0 +1,158 @@ +import multiprocessing +import traceback +from pathlib import Path +from queue import Empty, Queue +from time import sleep +from typing import Callable, Optional + +import pyarrow as pa +import pyarrow.parquet as pq + +from quackosm._rich_progress import TaskProgressBar # type: ignore[attr-defined] + + +def _job( + queue: Queue[tuple[str, int]], + save_path: Path, + function: Callable[[pa.Table], pa.Table], + columns: Optional[list[str]] = None, +) -> None: # pragma: no cover + current_pid = multiprocessing.current_process().pid + + filepath = save_path / f"{current_pid}.parquet" + writer = None + while not queue.empty(): + try: + file_name, row_group_index = None, None + file_name, row_group_index = queue.get_nowait() + + pq_file = pq.ParquetFile(file_name) + row_group_table = pq_file.read_row_group(row_group_index, columns=columns) + if len(row_group_table) == 0: + continue + + result_table = function(row_group_table) + + if not writer: + writer = pq.ParquetWriter(filepath, result_table.schema) + + writer.write_table(result_table) + except Empty: + pass + except Exception as ex: + if file_name is not None and row_group_index is not None: + queue.put((file_name, row_group_index)) + + msg = ( + f"Error in worker (PID: {current_pid}," + f" Parquet: {file_name}, Row group: {row_group_index})" + ) + raise RuntimeError(msg) from ex + + if writer: + writer.close() + + +class WorkerProcess(multiprocessing.Process): + def __init__(self, *args, **kwargs): # type: ignore[no-untyped-def] + multiprocessing.Process.__init__(self, *args, **kwargs) + self._pconn, self._cconn = multiprocessing.Pipe() + self._exception: Optional[tuple[Exception, str]] = None + + def run(self) -> None: # pragma: no cover + try: + multiprocessing.Process.run(self) + self._cconn.send(None) + except Exception as e: + tb: str = traceback.format_exc() + self._cconn.send((e, tb)) + + @property + def exception(self) -> Optional[tuple[Exception, str]]: + if self._pconn.poll(): + self._exception = self._pconn.recv() + return self._exception + + +def map_parquet_dataset( + dataset_path: Path, + destination_path: Path, + function: Callable[[pa.Table], pa.Table], + columns: Optional[list[str]] = None, + progress_bar: Optional[TaskProgressBar] = None, +) -> None: + """ + Apply a function over parquet dataset in a multiprocessing environment. + + Will save results in multiple files in a destination path. + + Args: + dataset_path (Path): Path of the parquet dataset. + destination_path (Path): Path of the destination. + function (Callable[[pa.Table], pa.Table]): Function to apply over a row group table. + Will save resulting table in a new parquet file. + columns (Optional[list[str]]): List of columns to read. Defaults to `None`. + progress_bar (Optional[TaskProgressBar]): Progress bar to show task status. + Defaults to `None`. + """ + queue: Queue[tuple[str, int]] = multiprocessing.Manager().Queue() + + dataset = pq.ParquetDataset(dataset_path) + + for pq_file in dataset.files: + for row_group in range(pq.ParquetFile(pq_file).num_row_groups): + queue.put((pq_file, row_group)) + + total = queue.qsize() + + destination_path.mkdir(parents=True, exist_ok=True) + + try: + processes = [ + WorkerProcess( + target=_job, + args=(queue, destination_path, function, columns), + ) # type: ignore[no-untyped-call] + for _ in range(multiprocessing.cpu_count()) + ] + + # Run processes + for p in processes: + p.start() + + if progress_bar: # pragma: no cover + progress_bar.create_manual_bar(total=total) + while any(process.is_alive() for process in processes): + if any(p.exception for p in processes): # pragma: no cover + break + + if progress_bar: # pragma: no cover + progress_bar.update_manual_bar(current_progress=total - queue.qsize()) + sleep(1) + + if progress_bar: # pragma: no cover + progress_bar.update_manual_bar(current_progress=total) + finally: # pragma: no cover + # In case of exception + exceptions = [] + for p in processes: + if p.is_alive(): + p.terminate() + + if p.exception: + exceptions.append(p.exception) + + if exceptions: + # use ExceptionGroup in Python3.11 + _raise_multiple(exceptions) + + +def _raise_multiple(exceptions: list[tuple[Exception, str]]) -> None: + if not exceptions: + return + try: + error, traceback = exceptions.pop() + msg = f"{error}\n\nOriginal {traceback}" + raise type(error)(msg) + finally: + _raise_multiple(exceptions) diff --git a/quackosm/_rich_progress.py b/quackosm/_rich_progress.py index ca15036..d210bea 100644 --- a/quackosm/_rich_progress.py +++ b/quackosm/_rich_progress.py @@ -147,38 +147,39 @@ def __init__( self.progress_cls = progress_cls self.live_obj = live_obj + def _create_progress(self): + columns = [ + SpinnerColumn(), + TextColumn(self.step_number), + TextColumn( + "[progress.description]{task.description}" + " [progress.percentage]{task.percentage:>3.0f}%" + ), + BarColumn(), + MofNCompleteColumn(), + TextColumn("•"), + TimeElapsedColumn(), + TextColumn("<"), + TimeRemainingColumn(), + TextColumn("•"), + SpeedColumn(), + ] + + if self.skip_step_number: + columns.pop(1) + + self.progress = self.progress_cls( + *columns, + live_obj=self.live_obj, + transient=self.transient_mode, + speed_estimate_period=1800, + ) + def __enter__(self): if self.silent_mode: self.progress = None else: - - columns = [ - SpinnerColumn(), - TextColumn(self.step_number), - TextColumn( - "[progress.description]{task.description}" - " [progress.percentage]{task.percentage:>3.0f}%" - ), - BarColumn(), - MofNCompleteColumn(), - TextColumn("•"), - TimeElapsedColumn(), - TextColumn("<"), - TimeRemainingColumn(), - TextColumn("•"), - SpeedColumn(), - ] - - if self.skip_step_number: - columns.pop(1) - - self.progress = self.progress_cls( - *columns, - live_obj=self.live_obj, - transient=self.transient_mode, - speed_estimate_period=1800, - ) - + self._create_progress() self.progress.__enter__() return self @@ -189,6 +190,12 @@ def __exit__(self, exc_type, exc_value, exc_tb): self.progress = None + def create_manual_bar(self, total: int): + self.progress.add_task(description=self.step_name, total=total) + + def update_manual_bar(self, current_progress: int): + self.progress.update(task_id=self.progress.task_ids[0], completed=current_progress) + def track(self, iterable: Iterable): if self.progress is not None: for i in self.progress.track(list(iterable), description=self.step_name): diff --git a/quackosm/osm_extracts/_poly_parser.py b/quackosm/osm_extracts/_poly_parser.py index b108a2b..550208e 100644 --- a/quackosm/osm_extracts/_poly_parser.py +++ b/quackosm/osm_extracts/_poly_parser.py @@ -8,7 +8,7 @@ __all__ = ["parse_polygon_file"] -def parse_polygon_file(polygon_url: str) -> Optional[MultiPolygon]: +def parse_polygon_file(polygon_url: str) -> Optional[MultiPolygon]: # pragma: no cover """ Parse poly file from URL to geometry. @@ -30,7 +30,7 @@ def parse_polygon_file(polygon_url: str) -> Optional[MultiPolygon]: return poly -def parse_poly(lines: list[str]) -> MultiPolygon: +def parse_poly(lines: list[str]) -> MultiPolygon: # pragma: no cover """ Parse an Osmosis polygon filter file. diff --git a/quackosm/osm_extracts/bbbike.py b/quackosm/osm_extracts/bbbike.py index a469df7..ba17dd4 100644 --- a/quackosm/osm_extracts/bbbike.py +++ b/quackosm/osm_extracts/bbbike.py @@ -43,7 +43,7 @@ def _load_bbbike_index() -> gpd.GeoDataFrame: if save_path.exists(): gdf = gpd.read_file(save_path) - else: + else: # pragma: no cover extracts = _iterate_bbbike_index() gdf = gpd.GeoDataFrame( data=[asdict(extract) for extract in extracts], geometry="geometry" @@ -57,7 +57,7 @@ def _load_bbbike_index() -> gpd.GeoDataFrame: return gdf -def _iterate_bbbike_index() -> list[OpenStreetMapExtract]: +def _iterate_bbbike_index() -> list[OpenStreetMapExtract]: # pragma: no cover """ Iterate OpenStreetMap.fr extracts service page. diff --git a/quackosm/osm_extracts/geofabrik.py b/quackosm/osm_extracts/geofabrik.py index 784d11b..ae1a1b2 100644 --- a/quackosm/osm_extracts/geofabrik.py +++ b/quackosm/osm_extracts/geofabrik.py @@ -38,7 +38,7 @@ def _load_geofabrik_index() -> gpd.GeoDataFrame: if save_path.exists(): gdf = gpd.read_file(save_path) - else: + else: # pragma: no cover result = requests.get( GEOFABRIK_INDEX_URL, headers={ diff --git a/quackosm/osm_extracts/osm_fr.py b/quackosm/osm_extracts/osm_fr.py index ec18e59..569faa7 100644 --- a/quackosm/osm_extracts/osm_fr.py +++ b/quackosm/osm_extracts/osm_fr.py @@ -45,7 +45,7 @@ def _load_openstreetmap_fr_index() -> gpd.GeoDataFrame: if save_path.exists(): gdf = gpd.read_file(save_path) - else: + else: # pragma: no cover force_terminal = os.getenv("FORCE_TERMINAL_MODE", "false").lower() == "true" extracts = [] with tqdm(disable=True if force_terminal else None) as pbar: @@ -79,7 +79,9 @@ def _load_openstreetmap_fr_index() -> gpd.GeoDataFrame: return gdf -def _gather_all_openstreetmap_fr_urls(id_prefix: str, directory_url: str, pbar: tqdm) -> list[Any]: +def _gather_all_openstreetmap_fr_urls( + id_prefix: str, directory_url: str, pbar: tqdm +) -> list[Any]: # pragma: no cover """ Iterate OpenStreetMap.fr extracts service page. diff --git a/quackosm/pbf_file_reader.py b/quackosm/pbf_file_reader.py index 75d0677..fed625f 100644 --- a/quackosm/pbf_file_reader.py +++ b/quackosm/pbf_file_reader.py @@ -35,6 +35,7 @@ from quackosm._constants import FEATURES_INDEX, GEOMETRY_COLUMN, WGS84_CRS from quackosm._exceptions import EmptyResultWarning, InvalidGeometryFilter +from quackosm._intersection import intersect_nodes_with_geometry from quackosm._osm_tags_filters import ( GroupedOsmTagsFilter, OsmTagsFilter, @@ -242,6 +243,7 @@ def convert_pbf_to_parquet( ignore_cache: bool = False, filter_osm_ids: Optional[list[str]] = None, save_as_wkt: bool = False, + pbf_extract_geometry: Optional[Union[BaseGeometry, Iterable[BaseGeometry]]] = None, ) -> Path: """ Convert PBF file to GeoParquet file. @@ -268,6 +270,9 @@ def convert_pbf_to_parquet( save_as_wkt (bool): Whether to save the file with geometry in the WKT form instead of WKB. If `True`, it will be saved as a `.parquet` file, because it won't be in the GeoParquet standard. Defaults to `False`. + pbf_extract_geometry (Optional[Union[BaseGeometry, Iterable[BaseGeometry]]], optional): + List of geometries defining PBF extract. Used internally to speed up intersections + for complex filters. Defaults to `None`. Returns: Path: Path to the generated GeoParquet file. @@ -277,6 +282,17 @@ def convert_pbf_to_parquet( else: pbf_path = list(pbf_path) + if pbf_extract_geometry is not None: + if isinstance(pbf_extract_geometry, BaseGeometry): + pbf_extract_geometry = [pbf_extract_geometry] + else: + pbf_extract_geometry = list(pbf_extract_geometry) + if len(pbf_extract_geometry) != len(pbf_path): + raise AttributeError( + "Provided pbf_extract_geometry has a different length " + "than the list of pbf paths." + ) + if filter_osm_ids is None: filter_osm_ids = [] @@ -290,9 +306,12 @@ def convert_pbf_to_parquet( self.task_progress_tracker = TaskProgressTracker( verbosity_mode=self.verbosity_mode, total_major_steps=total_files, - debug=self.debug_memory, + debug=self.debug_times, ) if total_files == 1: + single_pbf_extract_geometry = None + if pbf_extract_geometry is not None: + single_pbf_extract_geometry = pbf_extract_geometry[0] parsed_geoparquet_file = self._convert_single_pbf_to_parquet( pbf_path[0], result_file_path=result_file_path, @@ -301,6 +320,7 @@ def convert_pbf_to_parquet( ignore_cache=ignore_cache, filter_osm_ids=filter_osm_ids, save_as_wkt=save_as_wkt, + pbf_extract_geometry=single_pbf_extract_geometry, ) self.task_progress_tracker.stop() return parsed_geoparquet_file @@ -334,6 +354,11 @@ def convert_pbf_to_parquet( for file_idx, single_pbf_path in enumerate(pbf_path): self.task_progress_tracker.reset_steps(file_idx + 1) + + single_pbf_extract_geometry = None + if pbf_extract_geometry is not None: + single_pbf_extract_geometry = pbf_extract_geometry[file_idx] + parsed_geoparquet_file = self._convert_single_pbf_to_parquet( single_pbf_path, keep_all_tags=keep_all_tags, @@ -341,6 +366,7 @@ def convert_pbf_to_parquet( ignore_cache=ignore_cache, filter_osm_ids=filter_osm_ids, save_as_wkt=save_as_wkt, + pbf_extract_geometry=single_pbf_extract_geometry, ) parsed_geoparquet_files.append(parsed_geoparquet_file) @@ -404,6 +430,7 @@ def _convert_single_pbf_to_parquet( ignore_cache: bool = False, filter_osm_ids: Optional[list[str]] = None, save_as_wkt: bool = False, + pbf_extract_geometry: Optional[BaseGeometry] = None, ) -> Path: if filter_osm_ids is None: filter_osm_ids = [] @@ -422,6 +449,14 @@ def _convert_single_pbf_to_parquet( try: self.encountered_query_exception = False self.connection = _set_up_duckdb_connection(tmp_dir_path=self.tmp_dir_path) + + original_geometry_filter = self.geometry_filter + + if pbf_extract_geometry is not None: + self.geometry_filter = cast(BaseGeometry, self.geometry_filter).intersection( + cast(BaseGeometry, pbf_extract_geometry) + ) + result_file_path = result_file_path or self._generate_result_file_path( pbf_path, filter_osm_ids=filter_osm_ids, @@ -439,6 +474,8 @@ def _convert_single_pbf_to_parquet( save_as_wkt=save_as_wkt, ) + self.geometry_filter = original_geometry_filter + return parsed_geoparquet_file finally: if self.connection is not None: @@ -538,6 +575,9 @@ def convert_geometry_to_parquet( ignore_cache=ignore_cache, filter_osm_ids=filter_osm_ids, save_as_wkt=save_as_wkt, + pbf_extract_geometry=[ + matching_extract.geometry for matching_extract in matching_extracts + ], ) @deprecate_kwarg(old_arg_name="file_paths", new_arg_name="pbf_path") # type: ignore @@ -1101,16 +1141,17 @@ def _prefilter_elements_ids( # - select all from NI with tags filter filter_osm_node_ids_filter = self._generate_elements_filter(filter_osm_ids, "node") if is_intersecting: - wkt = cast(BaseGeometry, self.geometry_filter).wkt - intersection_filter = f"ST_Intersects(ST_Point(lon, lat), ST_GeomFromText('{wkt}'))" - with self.task_progress_tracker.get_spinner("Filtering nodes - intersection"): - nodes_intersecting_ids = self._sql_to_parquet_file( - sql_query=f""" - SELECT DISTINCT id FROM ({nodes_valid_with_tags.sql_query()}) n - WHERE {intersection_filter} = true - """, - file_path=self.tmp_dir_path / "nodes_intersecting_ids", + with self.task_progress_tracker.get_bar("Filtering nodes - intersection") as bar: + intersect_nodes_with_geometry( + tmp_dir_path=self.tmp_dir_path, + geometry_filter=self.geometry_filter, + progress_bar=bar, + ) + + nodes_intersecting_ids = self.connection.read_parquet( + str(self.tmp_dir_path / "nodes_intersecting_ids" / "*.parquet") ) + with self.task_progress_tracker.get_spinner("Filtering nodes - tags"): self._sql_to_parquet_file( sql_query=f""" diff --git a/tests/base/test_intersection.py b/tests/base/test_intersection.py new file mode 100644 index 0000000..58e2f04 --- /dev/null +++ b/tests/base/test_intersection.py @@ -0,0 +1,56 @@ +"""Tests for PbfFileReader nodes intersection filtering.""" + +import tempfile +from pathlib import Path + +import duckdb +import pyarrow as pa +import pyarrow.parquet as pq +from geoarrow.rust.core import PointArray + +from quackosm._intersection import intersect_nodes_with_geometry +from quackosm.cli import GeocodeGeometryParser + + +def test_nodes_intersection() -> None: + """Test if multiprocessing implementation works the same as local.""" + pbf_file = Path(__file__).parent.parent / "test_files" / "monaco.osm.pbf" + geom_filter = GeocodeGeometryParser().convert("Monaco-Ville, Monaco") # type: ignore + + with tempfile.TemporaryDirectory(dir=Path(__file__).parent.resolve()) as tmp_dir_name: + duckdb.install_extension("spatial") + duckdb.load_extension("spatial") + nodes_destination = Path(tmp_dir_name) / "nodes_valid_with_tags" + nodes_destination.mkdir(exist_ok=True, parents=True) + duckdb.sql( + f""" + COPY ( + SELECT + id, lon, lat + FROM ST_ReadOSM('{pbf_file}') + WHERE kind = 'node' + AND lat IS NOT NULL AND lon IS NOT NULL + ) TO '{nodes_destination}' ( + FORMAT 'parquet', + PER_THREAD_OUTPUT true, + ROW_GROUP_SIZE 25000 + ) + """ + ) + nodes_points = pq.ParquetDataset(nodes_destination).read() + points_array = PointArray.from_xy( + x=nodes_points["lon"].combine_chunks(), y=nodes_points["lat"].combine_chunks() + ).to_shapely() + intersecting_points_mask = geom_filter.intersects(points_array) + + intersecting_ids_array = ( + nodes_points["id"].combine_chunks().filter(pa.array(intersecting_points_mask)) + ) + + intersect_nodes_with_geometry(tmp_dir_path=Path(tmp_dir_name), geometry_filter=geom_filter) + + intersecting_points = pq.ParquetDataset( + Path(tmp_dir_name) / "nodes_intersecting_ids" + ).read() + + assert set(intersecting_points["id"]) == set(intersecting_ids_array) diff --git a/tests/base/test_parquet_multiprocessing.py b/tests/base/test_parquet_multiprocessing.py new file mode 100644 index 0000000..1457b93 --- /dev/null +++ b/tests/base/test_parquet_multiprocessing.py @@ -0,0 +1,50 @@ +"""Tests for Parquet multiprocessing wrapper.""" + +import tempfile +from pathlib import Path +from random import random +from time import sleep +from typing import Any + +import duckdb +import pytest + +from quackosm._parquet_multiprocessing import map_parquet_dataset + + +def raise_error(pa: Any) -> Any: + """Function for raising error.""" + sleep(random()) + raise Exception("Quack!") + +def test_exception_wrapping() -> None: + """Test if multiprocessing exception raising works..""" + pbf_file = Path(__file__).parent.parent / "test_files" / "monaco.osm.pbf" + + with tempfile.TemporaryDirectory(dir=Path(__file__).parent.resolve()) as tmp_dir_name: + duckdb.install_extension("spatial") + duckdb.load_extension("spatial") + nodes_destination = Path(tmp_dir_name) / "nodes_valid_with_tags" + nodes_destination.mkdir(exist_ok=True, parents=True) + duckdb.sql( + f""" + COPY ( + SELECT + id, lon, lat + FROM ST_ReadOSM('{pbf_file}') + WHERE kind = 'node' + AND lat IS NOT NULL AND lon IS NOT NULL + ) TO '{nodes_destination}' ( + FORMAT 'parquet', + PER_THREAD_OUTPUT true, + ROW_GROUP_SIZE 25000 + ) + """ + ) + + with pytest.raises(RuntimeError): + map_parquet_dataset( + dataset_path=nodes_destination, + destination_path=Path(tmp_dir_name) / "test", + function=raise_error, + ) diff --git a/tests/base/test_pbf_file_reader.py b/tests/base/test_pbf_file_reader.py index a03ca11..b56edaa 100644 --- a/tests/base/test_pbf_file_reader.py +++ b/tests/base/test_pbf_file_reader.py @@ -3,6 +3,7 @@ import json import warnings from functools import partial +from itertools import permutations from pathlib import Path from typing import Any, Callable, Optional, Union, cast from unittest import TestCase @@ -117,6 +118,31 @@ def test_geometry_hash_calculation(geometry: BaseGeometry): == PbfFileReader(geometry_filter=oriented_b)._get_oriented_geometry_filter() ) + assert ( + PbfFileReader(geometry_filter=oriented_a)._generate_geometry_hash() + == PbfFileReader(geometry_filter=oriented_b)._generate_geometry_hash() + ) + + +def test_multipart_geometry_hash_calculation() -> None: + """Test if geometry hash is orientation-agnostic.""" + geom_1 = geometry_box() + geom_2 = box(minx=0, miny=0, maxx=1, maxy=1) + geom_3 = GeocodeGeometryParser().convert("Monaco-Ville, Monaco") # type: ignore + geom_4 = H3GeometryParser().convert("8a3969a40ac7fff,893969a4037ffff") # type: ignore + + geoms = [ + GeometryCollection(combination) + for combination in permutations([geom_1, geom_2, geom_3, geom_4], 4) + ] + + hashes = [ + PbfFileReader(geometry_filter=geom_filter)._generate_geometry_hash() + for geom_filter in geoms + ] + + assert all(i == hashes[0] for i in hashes) + def test_unique_osm_ids_duplicated_file(): # type: ignore """Test if function returns results without duplicated features."""