faster-geohash 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ # Version 0.1.0
2
+ Released November 2, 2025
3
+
4
+ - Initial release
@@ -0,0 +1,250 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "approx"
7
+ version = "0.5.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
10
+ dependencies = [
11
+ "num-traits",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "autocfg"
16
+ version = "1.5.0"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
19
+
20
+ [[package]]
21
+ name = "faster-geohash"
22
+ version = "0.1.0"
23
+ dependencies = [
24
+ "geohash",
25
+ "pyo3",
26
+ "pyo3-build-config",
27
+ ]
28
+
29
+ [[package]]
30
+ name = "geo-types"
31
+ version = "0.7.17"
32
+ source = "registry+https://github.com/rust-lang/crates.io-index"
33
+ checksum = "75a4dcd69d35b2c87a7c83bce9af69fd65c9d68d3833a0ded568983928f3fc99"
34
+ dependencies = [
35
+ "approx",
36
+ "num-traits",
37
+ "serde",
38
+ ]
39
+
40
+ [[package]]
41
+ name = "geohash"
42
+ version = "0.13.1"
43
+ source = "registry+https://github.com/rust-lang/crates.io-index"
44
+ checksum = "0fb94b1a65401d6cbf22958a9040aa364812c26674f841bee538b12c135db1e6"
45
+ dependencies = [
46
+ "geo-types",
47
+ "libm",
48
+ ]
49
+
50
+ [[package]]
51
+ name = "heck"
52
+ version = "0.5.0"
53
+ source = "registry+https://github.com/rust-lang/crates.io-index"
54
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
55
+
56
+ [[package]]
57
+ name = "indoc"
58
+ version = "2.0.7"
59
+ source = "registry+https://github.com/rust-lang/crates.io-index"
60
+ checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
61
+ dependencies = [
62
+ "rustversion",
63
+ ]
64
+
65
+ [[package]]
66
+ name = "libc"
67
+ version = "0.2.177"
68
+ source = "registry+https://github.com/rust-lang/crates.io-index"
69
+ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
70
+
71
+ [[package]]
72
+ name = "libm"
73
+ version = "0.2.15"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
76
+
77
+ [[package]]
78
+ name = "memoffset"
79
+ version = "0.9.1"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
82
+ dependencies = [
83
+ "autocfg",
84
+ ]
85
+
86
+ [[package]]
87
+ name = "num-traits"
88
+ version = "0.2.19"
89
+ source = "registry+https://github.com/rust-lang/crates.io-index"
90
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
91
+ dependencies = [
92
+ "autocfg",
93
+ "libm",
94
+ ]
95
+
96
+ [[package]]
97
+ name = "once_cell"
98
+ version = "1.21.3"
99
+ source = "registry+https://github.com/rust-lang/crates.io-index"
100
+ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
101
+
102
+ [[package]]
103
+ name = "portable-atomic"
104
+ version = "1.11.1"
105
+ source = "registry+https://github.com/rust-lang/crates.io-index"
106
+ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
107
+
108
+ [[package]]
109
+ name = "proc-macro2"
110
+ version = "1.0.103"
111
+ source = "registry+https://github.com/rust-lang/crates.io-index"
112
+ checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
113
+ dependencies = [
114
+ "unicode-ident",
115
+ ]
116
+
117
+ [[package]]
118
+ name = "pyo3"
119
+ version = "0.27.1"
120
+ source = "registry+https://github.com/rust-lang/crates.io-index"
121
+ checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf"
122
+ dependencies = [
123
+ "indoc",
124
+ "libc",
125
+ "memoffset",
126
+ "once_cell",
127
+ "portable-atomic",
128
+ "pyo3-build-config",
129
+ "pyo3-ffi",
130
+ "pyo3-macros",
131
+ "unindent",
132
+ ]
133
+
134
+ [[package]]
135
+ name = "pyo3-build-config"
136
+ version = "0.27.1"
137
+ source = "registry+https://github.com/rust-lang/crates.io-index"
138
+ checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb"
139
+ dependencies = [
140
+ "target-lexicon",
141
+ ]
142
+
143
+ [[package]]
144
+ name = "pyo3-ffi"
145
+ version = "0.27.1"
146
+ source = "registry+https://github.com/rust-lang/crates.io-index"
147
+ checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be"
148
+ dependencies = [
149
+ "libc",
150
+ "pyo3-build-config",
151
+ ]
152
+
153
+ [[package]]
154
+ name = "pyo3-macros"
155
+ version = "0.27.1"
156
+ source = "registry+https://github.com/rust-lang/crates.io-index"
157
+ checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71"
158
+ dependencies = [
159
+ "proc-macro2",
160
+ "pyo3-macros-backend",
161
+ "quote",
162
+ "syn",
163
+ ]
164
+
165
+ [[package]]
166
+ name = "pyo3-macros-backend"
167
+ version = "0.27.1"
168
+ source = "registry+https://github.com/rust-lang/crates.io-index"
169
+ checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b"
170
+ dependencies = [
171
+ "heck",
172
+ "proc-macro2",
173
+ "pyo3-build-config",
174
+ "quote",
175
+ "syn",
176
+ ]
177
+
178
+ [[package]]
179
+ name = "quote"
180
+ version = "1.0.41"
181
+ source = "registry+https://github.com/rust-lang/crates.io-index"
182
+ checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
183
+ dependencies = [
184
+ "proc-macro2",
185
+ ]
186
+
187
+ [[package]]
188
+ name = "rustversion"
189
+ version = "1.0.22"
190
+ source = "registry+https://github.com/rust-lang/crates.io-index"
191
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
192
+
193
+ [[package]]
194
+ name = "serde"
195
+ version = "1.0.228"
196
+ source = "registry+https://github.com/rust-lang/crates.io-index"
197
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
198
+ dependencies = [
199
+ "serde_core",
200
+ "serde_derive",
201
+ ]
202
+
203
+ [[package]]
204
+ name = "serde_core"
205
+ version = "1.0.228"
206
+ source = "registry+https://github.com/rust-lang/crates.io-index"
207
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
208
+ dependencies = [
209
+ "serde_derive",
210
+ ]
211
+
212
+ [[package]]
213
+ name = "serde_derive"
214
+ version = "1.0.228"
215
+ source = "registry+https://github.com/rust-lang/crates.io-index"
216
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
217
+ dependencies = [
218
+ "proc-macro2",
219
+ "quote",
220
+ "syn",
221
+ ]
222
+
223
+ [[package]]
224
+ name = "syn"
225
+ version = "2.0.108"
226
+ source = "registry+https://github.com/rust-lang/crates.io-index"
227
+ checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
228
+ dependencies = [
229
+ "proc-macro2",
230
+ "quote",
231
+ "unicode-ident",
232
+ ]
233
+
234
+ [[package]]
235
+ name = "target-lexicon"
236
+ version = "0.13.3"
237
+ source = "registry+https://github.com/rust-lang/crates.io-index"
238
+ checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c"
239
+
240
+ [[package]]
241
+ name = "unicode-ident"
242
+ version = "1.0.22"
243
+ source = "registry+https://github.com/rust-lang/crates.io-index"
244
+ checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
245
+
246
+ [[package]]
247
+ name = "unindent"
248
+ version = "0.2.4"
249
+ source = "registry+https://github.com/rust-lang/crates.io-index"
250
+ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
@@ -0,0 +1,42 @@
1
+ [package]
2
+ name = "faster-geohash"
3
+ version = "0.1.0"
4
+ authors = ["Eashwar Ranganathan <eashwar@eashwar.com>"]
5
+ edition = "2024"
6
+ rust-version = "1.85"
7
+
8
+ description = "A fast geohashing library"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ keywords = ["geohash", "gis"]
12
+
13
+ # This rust code only exists to bind with python
14
+ # It should not be published as a crate
15
+ publish = false
16
+
17
+ [dependencies]
18
+ geohash = "0.13.1"
19
+ pyo3 = "0.27"
20
+
21
+ [features]
22
+ # The extension-modules feature is required to build wheels, but is terrible for
23
+ # local dev, so make it an optional feature that we enable only when building with maturin.
24
+ wheel = ["pyo3/extension-module"]
25
+
26
+ # This feature allows for building abi3 compatible wheels, but is not enabled by default
27
+ # here or in the maturin config. Enable it explicitly when building the wheel, e.g.
28
+ # `uv build -C maturin.build-args=--features=abi3 --wheel .`
29
+ # Keep the `pyo3/abi3-{lower_bound}` feature here in sync with project.requires-python in the pyproject.toml
30
+ abi3 = [
31
+ "wheel",
32
+ "pyo3/abi3",
33
+ "pyo3/abi3-py39",
34
+ ]
35
+
36
+ [build-dependencies]
37
+ pyo3-build-config = { version = "0.27.1", features = ["resolve-config"] }
38
+
39
+ [lib]
40
+ name = "faster_geohash"
41
+ crate-type = ["cdylib"]
42
+ path = "src/lib.rs"
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Eashwar Ranganathan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: faster-geohash
3
+ Version: 0.1.0
4
+ Classifier: Intended Audience :: Developers
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: Python :: 3 :: Only
7
+ Classifier: Programming Language :: Python :: 3.9
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
14
+ Classifier: Programming Language :: Rust
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Operating System :: MacOS
18
+ License-File: LICENSE
19
+ Summary: A fast geohashing library
20
+ Keywords: geohash,gis
21
+ Author-email: Eashwar Ranganathan <eashwar@eashwar.com>
22
+ License-Expression: MIT
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
25
+ Project-URL: homepage, https://github.com/e-nomem/faster-geohash
26
+ Project-URL: changelog, https://github.com/e-nomem/faster-geohash/blob/main/CHANGELOG.md
27
+
28
+ # faster-geohash
29
+ [![PyPI version](https://img.shields.io/pypi/v/faster-geohash.svg)](https://pypi.org/projects/faster-geohash) [![License](https://img.shields.io/github/license/e-nomem/faster-geohash.svg)](https://github.com/e-nomem/faster-geohash/blob/main/LICENSE)
30
+
31
+ A fast geohash library for python implemented using the [rust geohash crate](https://github.com/georust/geohash).
32
+
33
+ This library supports python 3.9-3.14 and has experimental support for the 'free-threaded' mode in python 3.14.
34
+
35
+ ## Usage
36
+ ```python
37
+ import faster_geohash
38
+
39
+ faster_geohash.encode((37.8324, 112.5584), precision=9) # 'ww8p1r4t8'
40
+
41
+ faster_geohash.decode('ww8p1r4t8') # ('37.8324', '112.5584')
42
+ ```
43
+
44
+ ## Building
45
+ This library uses `maturin` to compile the rust code into a python extension module. An existing rust toolchain does not have to be installed because `maturin` will bootstrap a rust toolchain in an isolated environment as necessary. Use any standard build frontend, e.g. using `uv`:
46
+ ```bash
47
+ # Build from source checkout
48
+ uv build --wheel .
49
+
50
+ # Build directly from sdist
51
+ uv build --wheel path/to/faster_geohash-0.0.1.tar.gz
52
+ ```
53
+
54
+ ### ABI3 Support
55
+ This library supports building against the python 'limited' API/ABI3. By default it will not do so, but the option can be enabled by passing the config flag to maturin. E.g. using `uv`:
56
+ ```bash
57
+ uv build --config-setting maturin.build-args=--features=abi3 --wheel <source_dir or sdist>
58
+ ```
59
+
@@ -0,0 +1,31 @@
1
+ # faster-geohash
2
+ [![PyPI version](https://img.shields.io/pypi/v/faster-geohash.svg)](https://pypi.org/projects/faster-geohash) [![License](https://img.shields.io/github/license/e-nomem/faster-geohash.svg)](https://github.com/e-nomem/faster-geohash/blob/main/LICENSE)
3
+
4
+ A fast geohash library for python implemented using the [rust geohash crate](https://github.com/georust/geohash).
5
+
6
+ This library supports python 3.9-3.14 and has experimental support for the 'free-threaded' mode in python 3.14.
7
+
8
+ ## Usage
9
+ ```python
10
+ import faster_geohash
11
+
12
+ faster_geohash.encode((37.8324, 112.5584), precision=9) # 'ww8p1r4t8'
13
+
14
+ faster_geohash.decode('ww8p1r4t8') # ('37.8324', '112.5584')
15
+ ```
16
+
17
+ ## Building
18
+ This library uses `maturin` to compile the rust code into a python extension module. An existing rust toolchain does not have to be installed because `maturin` will bootstrap a rust toolchain in an isolated environment as necessary. Use any standard build frontend, e.g. using `uv`:
19
+ ```bash
20
+ # Build from source checkout
21
+ uv build --wheel .
22
+
23
+ # Build directly from sdist
24
+ uv build --wheel path/to/faster_geohash-0.0.1.tar.gz
25
+ ```
26
+
27
+ ### ABI3 Support
28
+ This library supports building against the python 'limited' API/ABI3. By default it will not do so, but the option can be enabled by passing the config flag to maturin. E.g. using `uv`:
29
+ ```bash
30
+ uv build --config-setting maturin.build-args=--features=abi3 --wheel <source_dir or sdist>
31
+ ```
@@ -0,0 +1,4 @@
1
+ // SPDX-License-Identifier: MIT
2
+ fn main() {
3
+ pyo3_build_config::use_pyo3_cfgs();
4
+ }
@@ -0,0 +1,48 @@
1
+ # SPDX-License-Identifier: MIT
2
+ def encode(coords: tuple[float, float], /, precision: int = 12) -> str:
3
+ """Encodes a coordinate point into a geohash
4
+
5
+ :param coords: A coordinate tuple of (latitude, longitude)
6
+ :type coords: tuple[float, float]
7
+ :param precision: The precisions/length of the output geohash from
8
+ 1 to 12 inclusive (defaults to 12)
9
+ :type precision: int
10
+ :returns: The coordinate encoded as a geohash string
11
+ :rtype: str
12
+ """
13
+ ...
14
+
15
+ def decode_bbox(hash_str: str) -> tuple[tuple[float, float], tuple[float, float]]:
16
+ """Decode a geohash returning the bounding box that contains it
17
+
18
+ :param hash_str: The geohash string
19
+ :type hash_str: str
20
+ :returns: The bounding box as a (min_coord, max_coord) tuple where
21
+ each coord is a tuple of (latitude, longitude)
22
+ :rtype: tuple[tuple[float, float], tuple[float, float]]
23
+ """
24
+ ...
25
+
26
+ def decode_exact(hash_str: str) -> tuple[tuple[float, float], float, float]:
27
+ """Decode a geohash returning a coordinate and error margins
28
+
29
+ :param hash_str: The geohash string
30
+ :type hash_str: str
31
+ :returns: A tuple of (coordinate, latitude_error, longitude_error) where
32
+ the coordinate is a tuple of (latitude, longitude) and each error value
33
+ is a float
34
+ :rtype: tuple[tuple[float, float], float, float]
35
+ """
36
+ ...
37
+
38
+ def decode(hash_str: str) -> tuple[str, str]:
39
+ """Decode a geohash returning a coordinate with truncated precision
40
+
41
+ :param hash_str: The geohash string
42
+ :type hash_str: str
43
+ :returns: The coordinate as a tuple of strings (latitude, longitude)
44
+ with each string represnentation truncated to a precision matching
45
+ the error margins and trailing zeroes removed
46
+ :rtype: tuple[str, str]
47
+ """
48
+ ...
@@ -0,0 +1,141 @@
1
+ [build-system]
2
+ requires = [
3
+ # Keep this in sync with dependency-groups.dev below
4
+ "maturin~=1.9",
5
+ ]
6
+ build-backend = "maturin"
7
+
8
+
9
+ [project]
10
+ name = "faster-geohash"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ requires-python = ">=3.9" # Keep the lower bound here in sync with the abi3 feature in the Cargo.toml
14
+ authors = [
15
+ {name = "Eashwar Ranganathan", email = "eashwar@eashwar.com"},
16
+ ]
17
+ classifiers = [
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: 3.14",
27
+ "Programming Language :: Python :: Free Threading :: 2 - Beta",
28
+ "Programming Language :: Rust",
29
+ "Development Status :: 4 - Beta",
30
+ "Operating System :: POSIX :: Linux",
31
+ "Operating System :: MacOS",
32
+ ]
33
+
34
+ dynamic = [
35
+ "description",
36
+ "keywords",
37
+ "readme",
38
+ "version",
39
+ ]
40
+
41
+ [project.urls]
42
+ homepage = "https://github.com/e-nomem/faster-geohash"
43
+ changelog = "https://github.com/e-nomem/faster-geohash/blob/main/CHANGELOG.md"
44
+
45
+ [dependency-groups]
46
+ dev = [
47
+ # Keep this in sync with build-system.requires above
48
+ "maturin~=1.9",
49
+ # See the docs on how to install this into your venv
50
+ "maturin-import-hook~=0.3.0",
51
+ {include-group = "lint"},
52
+ {include-group = "test"},
53
+ ]
54
+ lint = [
55
+ "ruff~=0.14.2",
56
+ "ty==0.0.1a25",
57
+ ]
58
+ test = [
59
+ "pytest>=8.4.2",
60
+ ]
61
+
62
+
63
+ [tool.maturin]
64
+ features = ["wheel"]
65
+ locked = true
66
+ exclude = [
67
+ ".github/**/*",
68
+ ".gitignore",
69
+ ]
70
+
71
+ [tool.maturin.target.x86_64-apple-darwin]
72
+ # 10.12 is the minimum target for the rust compiler
73
+ # Note that cibuildwheel has a lower target that is overridden in the publish workflow
74
+ # See https://cibuildwheel.pypa.io/en/stable/platforms/#macos-version-compatibility
75
+ macos-deployment-target = "10.12"
76
+
77
+ [tool.maturin.target.aarch64-apple-darwin]
78
+ # 11.0 is the minimum target used by cibuildwheel for aarch64 macOS
79
+ macos-deployment-target = "11.0"
80
+
81
+
82
+ [tool.cibuildwheel]
83
+ build-frontend = "build[uv]"
84
+
85
+ test-groups = ["test"]
86
+ test-sources = ["tests"]
87
+ test-command = "pytest ./tests"
88
+
89
+ [[tool.cibuildwheel.overrides]]
90
+ # For all builds, use this opportunity to run twine check to verify the metadata
91
+ select = "*"
92
+ inherit.repair-wheel-command = "append"
93
+ repair-wheel-command = [
94
+ "uv tool run twine check --strict {wheel}",
95
+ ]
96
+
97
+ [[tool.cibuildwheel.overrides]]
98
+ # Free-threaded python is not currently ABI3 compatible (See PEP 803)
99
+ # So we only add these options for non-free-threaded python to build api3
100
+ select = "cp39-*"
101
+ config-settings."maturin.build-args" = "--features=abi3"
102
+ inherit.repair-wheel-command = "append"
103
+ repair-wheel-command = [
104
+ "uv tool run abi3audit --strict --report {wheel}",
105
+ ]
106
+
107
+
108
+ [tool.ruff]
109
+ line-length = 120
110
+ target-version = "py39"
111
+
112
+ [tool.ruff.lint]
113
+ select = [
114
+ "A", # flake8-builtins
115
+ "B", # flake8-bugbear
116
+ "C4", # flake8-comprehensions
117
+ "E", # pycodestyle
118
+ "F", # Pyflakes
119
+ "I", # isort
120
+ "S", # flake8-bandit
121
+ "SIM", # flake8-simplify
122
+ "UP", # pyupgrade
123
+ ]
124
+ future-annotations = true
125
+
126
+ [tool.ruff.lint.per-file-ignores]
127
+ # Disable S101 (usage of assert) in tests
128
+ "tests/**.py" = ["S101"]
129
+
130
+ [tool.ruff.lint.isort]
131
+ case-sensitive = true
132
+ force-single-line = true
133
+
134
+ [tool.ruff.format]
135
+ quote-style = "single"
136
+ indent-style = "tab"
137
+ docstring-code-format = true
138
+
139
+ [tool.ty.terminal]
140
+ # Error if ty emits any warning-level diagnostics.
141
+ error-on-warning = true
@@ -0,0 +1,135 @@
1
+ // SPDX-License-Identifier: MIT
2
+ use std::cmp;
3
+ use std::error::Error;
4
+ use std::fmt::Display;
5
+ use std::fmt::Error as FmtError;
6
+ use std::fmt::Formatter;
7
+
8
+ use geohash::GeohashError;
9
+ use pyo3::exceptions::PyValueError;
10
+ use pyo3::prelude::*;
11
+
12
+ #[pymodule(gil_used = false)]
13
+ mod faster_geohash {
14
+ use geohash::Coord;
15
+ use pyo3::prelude::*;
16
+
17
+ use super::FastGeohashError;
18
+ use super::error_to_precision;
19
+ use super::format_to_precision;
20
+
21
+ type CoordTuple = (f64, f64);
22
+
23
+ #[pyfunction]
24
+ #[pyo3(signature = (coords, /, precision = 12))]
25
+ fn encode(
26
+ py: Python<'_>,
27
+ coords: CoordTuple,
28
+ precision: usize,
29
+ ) -> Result<String, FastGeohashError> {
30
+ py.detach(move || {
31
+ let c = Coord {
32
+ x: coords.1,
33
+ y: coords.0,
34
+ };
35
+ let result = geohash::encode(c, precision)?;
36
+ Ok(result)
37
+ })
38
+ }
39
+
40
+ #[pyfunction]
41
+ fn decode_bbox(
42
+ py: Python<'_>,
43
+ hash_str: &str,
44
+ ) -> Result<(CoordTuple, CoordTuple), FastGeohashError> {
45
+ py.detach(move || {
46
+ let bbox = geohash::decode_bbox(hash_str)?;
47
+ let min = (bbox.min().y, bbox.min().x);
48
+ let max = (bbox.max().y, bbox.max().x);
49
+ Ok((min, max))
50
+ })
51
+ }
52
+
53
+ #[pyfunction]
54
+ fn decode_exact(
55
+ py: Python<'_>,
56
+ hash_str: &str,
57
+ ) -> Result<(CoordTuple, f64, f64), FastGeohashError> {
58
+ py.detach(move || {
59
+ let (Coord { x, y }, lng_err, lat_err) = geohash::decode(hash_str)?;
60
+ Ok(((y, x), lat_err, lng_err))
61
+ })
62
+ }
63
+
64
+ #[pyfunction]
65
+ fn decode(py: Python<'_>, hash_str: &str) -> Result<(String, String), FastGeohashError> {
66
+ py.detach(move || {
67
+ let (coord, lng_err, lat_err) = geohash::decode(hash_str)?;
68
+
69
+ let lng_precision = error_to_precision(lng_err);
70
+ let lat_precision = error_to_precision(lat_err);
71
+
72
+ let lng = format_to_precision(coord.x, lng_precision as usize);
73
+ let lat = format_to_precision(coord.y, lat_precision as usize);
74
+
75
+ Ok((lat, lng))
76
+ })
77
+ }
78
+ }
79
+
80
+ fn error_to_precision(error: f64) -> i64 {
81
+ let v = error.log10();
82
+ let v = (-v).round();
83
+ cmp::max(v as i64, 1) - 1
84
+ }
85
+
86
+ fn format_to_precision(value: f64, precision: usize) -> String {
87
+ let v = format!("{:.*}", precision, value);
88
+ v.trim_end_matches("0").trim_end_matches(".").into()
89
+ }
90
+
91
+ #[derive(Debug)]
92
+ enum FastGeohashError {
93
+ InternalGeohashError(GeohashError),
94
+ }
95
+
96
+ impl Display for FastGeohashError {
97
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
98
+ match self {
99
+ Self::InternalGeohashError(e) => write!(f, "internal geohash error: {e}"),
100
+ }
101
+ }
102
+ }
103
+
104
+ impl Error for FastGeohashError {
105
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
106
+ match self {
107
+ Self::InternalGeohashError(e) => Some(e),
108
+ }
109
+ }
110
+ }
111
+
112
+ impl From<FastGeohashError> for PyErr {
113
+ fn from(value: FastGeohashError) -> Self {
114
+ match value {
115
+ FastGeohashError::InternalGeohashError(e) => match e {
116
+ GeohashError::InvalidCoordinateRange(c) => {
117
+ // Special case for this error because we expect everything in
118
+ // lat, lng order, but the coords are in the opposite x, y order
119
+ // So we reformat the error here to avoid confusion
120
+ PyValueError::new_err(format!(
121
+ "invalid coordinate range: COORD(lat={}, lng={})",
122
+ c.y, c.x
123
+ ))
124
+ }
125
+ e => PyValueError::new_err(format!("{e}")),
126
+ },
127
+ }
128
+ }
129
+ }
130
+
131
+ impl From<GeohashError> for FastGeohashError {
132
+ fn from(value: GeohashError) -> Self {
133
+ Self::InternalGeohashError(value)
134
+ }
135
+ }
@@ -0,0 +1 @@
1
+ # SPDX-License-Identifier: MIT
@@ -0,0 +1,57 @@
1
+ # SPDX-License-Identifier: MIT
2
+ import pytest
3
+
4
+ import faster_geohash
5
+
6
+
7
+ def test_encode_explicit_len() -> None:
8
+ result = faster_geohash.encode((37.8324, 112.5584), precision=9)
9
+
10
+ assert result == 'ww8p1r4t8'
11
+
12
+
13
+ def test_encode_default_len() -> None:
14
+ result = faster_geohash.encode((37.8324, 112.5584))
15
+
16
+ assert result == 'ww8p1r4t8yd0'
17
+
18
+
19
+ def test_encode__invalid_coordinates() -> None:
20
+ with pytest.raises(ValueError) as e:
21
+ faster_geohash.encode((float('nan'), 112.5584), 9)
22
+
23
+ assert str(e.value) == 'invalid coordinate range: COORD(lat=NaN, lng=112.5584)'
24
+
25
+
26
+ def test_encode__invalid_length() -> None:
27
+ with pytest.raises(ValueError) as e:
28
+ faster_geohash.encode((37.8324, 112.5584), 14)
29
+
30
+ assert str(e.value) == 'Invalid length specified: 14. Accepted values are between 1 and 12, inclusive'
31
+
32
+
33
+ def test_decode_bbox() -> None:
34
+ assert faster_geohash.decode_bbox('ww8p1r4t8') == (
35
+ (37.83236503601074, 112.55836486816406),
36
+ (37.83240795135498, 112.5584077835083),
37
+ )
38
+
39
+
40
+ def test_decode_exact() -> None:
41
+ assert faster_geohash.decode_exact('ww8p1r4t8') == (
42
+ (37.83238649368286, 112.55838632583618),
43
+ 2.1457672119140625e-05,
44
+ 2.1457672119140625e-05,
45
+ )
46
+
47
+
48
+ def test_decode() -> None:
49
+ assert faster_geohash.decode('ww8p1r4t8') == ('37.8324', '112.5584')
50
+
51
+
52
+ def test_round_trip() -> None:
53
+ coord = (37, 112)
54
+ geohash = faster_geohash.encode(coord, precision=12)
55
+ decoded = faster_geohash.decode(geohash)
56
+
57
+ assert decoded == tuple(str(v) for v in coord)
@@ -0,0 +1,305 @@
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.9"
4
+ resolution-markers = [
5
+ "python_full_version >= '3.10'",
6
+ "python_full_version < '3.10'",
7
+ ]
8
+
9
+ [[package]]
10
+ name = "colorama"
11
+ version = "0.4.6"
12
+ source = { registry = "https://pypi.org/simple" }
13
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
14
+ wheels = [
15
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
16
+ ]
17
+
18
+ [[package]]
19
+ name = "exceptiongroup"
20
+ version = "1.3.0"
21
+ source = { registry = "https://pypi.org/simple" }
22
+ dependencies = [
23
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
24
+ ]
25
+ sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" }
26
+ wheels = [
27
+ { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" },
28
+ ]
29
+
30
+ [[package]]
31
+ name = "faster-geohash"
32
+ source = { editable = "." }
33
+
34
+ [package.dev-dependencies]
35
+ dev = [
36
+ { name = "maturin" },
37
+ { name = "maturin-import-hook" },
38
+ { name = "pytest" },
39
+ { name = "ruff" },
40
+ { name = "ty" },
41
+ ]
42
+ lint = [
43
+ { name = "ruff" },
44
+ { name = "ty" },
45
+ ]
46
+ test = [
47
+ { name = "pytest" },
48
+ ]
49
+
50
+ [package.metadata]
51
+
52
+ [package.metadata.requires-dev]
53
+ dev = [
54
+ { name = "maturin", specifier = "~=1.9" },
55
+ { name = "maturin-import-hook", specifier = "~=0.3.0" },
56
+ { name = "pytest", specifier = ">=8.4.2" },
57
+ { name = "ruff", specifier = "~=0.14.2" },
58
+ { name = "ty", specifier = "==0.0.1a25" },
59
+ ]
60
+ lint = [
61
+ { name = "ruff", specifier = "~=0.14.2" },
62
+ { name = "ty", specifier = "==0.0.1a25" },
63
+ ]
64
+ test = [{ name = "pytest", specifier = ">=8.4.2" }]
65
+
66
+ [[package]]
67
+ name = "filelock"
68
+ version = "3.19.1"
69
+ source = { registry = "https://pypi.org/simple" }
70
+ resolution-markers = [
71
+ "python_full_version < '3.10'",
72
+ ]
73
+ sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" }
74
+ wheels = [
75
+ { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" },
76
+ ]
77
+
78
+ [[package]]
79
+ name = "filelock"
80
+ version = "3.20.0"
81
+ source = { registry = "https://pypi.org/simple" }
82
+ resolution-markers = [
83
+ "python_full_version >= '3.10'",
84
+ ]
85
+ sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" }
86
+ wheels = [
87
+ { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" },
88
+ ]
89
+
90
+ [[package]]
91
+ name = "iniconfig"
92
+ version = "2.1.0"
93
+ source = { registry = "https://pypi.org/simple" }
94
+ resolution-markers = [
95
+ "python_full_version < '3.10'",
96
+ ]
97
+ sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" }
98
+ wheels = [
99
+ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
100
+ ]
101
+
102
+ [[package]]
103
+ name = "iniconfig"
104
+ version = "2.3.0"
105
+ source = { registry = "https://pypi.org/simple" }
106
+ resolution-markers = [
107
+ "python_full_version >= '3.10'",
108
+ ]
109
+ sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
110
+ wheels = [
111
+ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
112
+ ]
113
+
114
+ [[package]]
115
+ name = "maturin"
116
+ version = "1.9.6"
117
+ source = { registry = "https://pypi.org/simple" }
118
+ dependencies = [
119
+ { name = "tomli", marker = "python_full_version < '3.11'" },
120
+ ]
121
+ sdist = { url = "https://files.pythonhosted.org/packages/9a/35/c3370188492f4c139c7a318f438d01b8185c216303c49c4bc885c98b6afb/maturin-1.9.6.tar.gz", hash = "sha256:2c2ae37144811d365509889ed7220b0598487f1278c2441829c3abf56cc6324a", size = 214846, upload-time = "2025-10-07T12:45:08.408Z" }
122
+ wheels = [
123
+ { url = "https://files.pythonhosted.org/packages/55/5c/b435418ba4ba2647a1f7a95d53314991b1e556e656ae276dea993c3bce1d/maturin-1.9.6-py3-none-linux_armv6l.whl", hash = "sha256:26e3ab1a42a7145824210e9d763f6958f2c46afb1245ddd0bab7d78b1f59bb3f", size = 8134483, upload-time = "2025-10-07T12:44:44.274Z" },
124
+ { url = "https://files.pythonhosted.org/packages/4d/1c/8e58eda6601f328b412cdeeaa88a9b6a10e591e2a73f313e8c0154d68385/maturin-1.9.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5263dda3f71feef2e4122baf5c4620e4b3710dbb7f2121f85a337182de214369", size = 15776470, upload-time = "2025-10-07T12:44:47.476Z" },
125
+ { url = "https://files.pythonhosted.org/packages/6c/33/8c967cce6848cdd87a2e442c86120ac644b80c5ed4c32e3291bde6a17df8/maturin-1.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fe78262c2800c92f67d1ce3c0f6463f958a692cc67bfb572e5dbf5b4b696a8ba", size = 8226557, upload-time = "2025-10-07T12:44:49.844Z" },
126
+ { url = "https://files.pythonhosted.org/packages/58/bd/3e2675cdc8b7270700ba30c663c852a35694441732a107ac30ebd6878bd8/maturin-1.9.6-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:7ab827c6e8c022eb2e1e7fb6deede54549c8460b20ccc2e9268cc6e8cde957a8", size = 8166544, upload-time = "2025-10-07T12:44:51.396Z" },
127
+ { url = "https://files.pythonhosted.org/packages/58/1f/a2047ddf2230e700d5f8a13dd4b9af5ce806ad380c32e58105888205926e/maturin-1.9.6-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:0246202377c49449315305209f45c8ecef6e2d6bd27a04b5b6f1ab3e4ea47238", size = 8641010, upload-time = "2025-10-07T12:44:53.658Z" },
128
+ { url = "https://files.pythonhosted.org/packages/be/1f/265d63c7aa6faf363d4a3f23396f51bc6b4d5c7680a4190ae68dba25dea2/maturin-1.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:f5bac167700fbb6f8c8ed1a97b494522554b4432d7578e11403b894b6a91d99f", size = 7965945, upload-time = "2025-10-07T12:44:55.248Z" },
129
+ { url = "https://files.pythonhosted.org/packages/4c/ca/a8e61979ccfe080948bcc1bddd79356157aee687134df7fb013050cec783/maturin-1.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:7f53d3b1d8396d3fea3e1ee5fd37558bca5719090f3d194ba1c02b0b56327ae3", size = 7978820, upload-time = "2025-10-07T12:44:56.919Z" },
130
+ { url = "https://files.pythonhosted.org/packages/bf/4a/81b412f8ad02a99801ef19ec059fba0822d1d28fb44cb6a92e722f05f278/maturin-1.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:7f506eb358386d94d6ec3208c003130cf4b69cab26034fc0cbbf8bf83afa4c2e", size = 10452064, upload-time = "2025-10-07T12:44:58.232Z" },
131
+ { url = "https://files.pythonhosted.org/packages/5b/12/cc96c7a8cb51d8dcc9badd886c361caa1526fba7fa69d1e7892e613b71d4/maturin-1.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2d6984ab690af509f525dbd2b130714207c06ebb14a5814edbe1e42b17ae0de", size = 8852401, upload-time = "2025-10-07T12:44:59.8Z" },
132
+ { url = "https://files.pythonhosted.org/packages/51/8e/653ac3c9f2c25cdd81aefb0a2d17ff140ca5a14504f5e3c7f94dcfe4dbb7/maturin-1.9.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5c2252b0956bb331460ac750c805ddf0d9b44442449fc1f16e3b66941689d0bc", size = 8425057, upload-time = "2025-10-07T12:45:01.711Z" },
133
+ { url = "https://files.pythonhosted.org/packages/db/29/f13490328764ae9bfc1da55afc5b707cebe4fa75ad7a1573bfa82cfae0c6/maturin-1.9.6-py3-none-win32.whl", hash = "sha256:f2c58d29ebdd4346fd004e6be213d071fdd94a77a16aa91474a21a4f9dbf6309", size = 7165956, upload-time = "2025-10-07T12:45:03.766Z" },
134
+ { url = "https://files.pythonhosted.org/packages/db/9f/dd51e5ac1fce47581b8efa03d77a03f928c0ef85b6e48a61dfa37b6b85a2/maturin-1.9.6-py3-none-win_amd64.whl", hash = "sha256:1b39a5d82572c240d20d9e8be024d722dfb311d330c5e28ddeb615211755941a", size = 8145722, upload-time = "2025-10-07T12:45:05.487Z" },
135
+ { url = "https://files.pythonhosted.org/packages/65/f2/e97aaba6d0d78c5871771bf9dd71d4eb8dac15df9109cf452748d2207412/maturin-1.9.6-py3-none-win_arm64.whl", hash = "sha256:ac02a30083553d2a781c10cd6f5480119bf6692fd177e743267406cad2ad198c", size = 6857006, upload-time = "2025-10-07T12:45:06.813Z" },
136
+ ]
137
+
138
+ [[package]]
139
+ name = "maturin-import-hook"
140
+ version = "0.3.0"
141
+ source = { registry = "https://pypi.org/simple" }
142
+ dependencies = [
143
+ { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
144
+ { name = "filelock", version = "3.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
145
+ { name = "tomli", marker = "python_full_version < '3.11'" },
146
+ ]
147
+ sdist = { url = "https://files.pythonhosted.org/packages/75/a1/3b007a4132265d5da19096d6835cd4c7e9908afb9156afb96d19ff190f39/maturin_import_hook-0.3.0.tar.gz", hash = "sha256:cdd51ce267663c437c4aea1bfd5f7ee5884b54a9d866ea924227d68d758bbba2", size = 30785, upload-time = "2025-06-08T15:43:57.801Z" }
148
+ wheels = [
149
+ { url = "https://files.pythonhosted.org/packages/9f/55/0c17a1fccec90dffbb1d904d7ddb7971e4e95f994c6264637e8fe66a5b86/maturin_import_hook-0.3.0-py3-none-any.whl", hash = "sha256:f5d20b4bc3056d84170dc08fe655160421b28d2b5128b48f55312315cdbb2cfe", size = 30848, upload-time = "2025-06-08T15:43:56.298Z" },
150
+ ]
151
+
152
+ [[package]]
153
+ name = "packaging"
154
+ version = "25.0"
155
+ source = { registry = "https://pypi.org/simple" }
156
+ sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
157
+ wheels = [
158
+ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
159
+ ]
160
+
161
+ [[package]]
162
+ name = "pluggy"
163
+ version = "1.6.0"
164
+ source = { registry = "https://pypi.org/simple" }
165
+ sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
166
+ wheels = [
167
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
168
+ ]
169
+
170
+ [[package]]
171
+ name = "pygments"
172
+ version = "2.19.2"
173
+ source = { registry = "https://pypi.org/simple" }
174
+ sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
175
+ wheels = [
176
+ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
177
+ ]
178
+
179
+ [[package]]
180
+ name = "pytest"
181
+ version = "8.4.2"
182
+ source = { registry = "https://pypi.org/simple" }
183
+ dependencies = [
184
+ { name = "colorama", marker = "sys_platform == 'win32'" },
185
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
186
+ { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
187
+ { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
188
+ { name = "packaging" },
189
+ { name = "pluggy" },
190
+ { name = "pygments" },
191
+ { name = "tomli", marker = "python_full_version < '3.11'" },
192
+ ]
193
+ sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
194
+ wheels = [
195
+ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
196
+ ]
197
+
198
+ [[package]]
199
+ name = "ruff"
200
+ version = "0.14.3"
201
+ source = { registry = "https://pypi.org/simple" }
202
+ sdist = { url = "https://files.pythonhosted.org/packages/75/62/50b7727004dfe361104dfbf898c45a9a2fdfad8c72c04ae62900224d6ecf/ruff-0.14.3.tar.gz", hash = "sha256:4ff876d2ab2b161b6de0aa1f5bd714e8e9b4033dc122ee006925fbacc4f62153", size = 5558687, upload-time = "2025-10-31T00:26:26.878Z" }
203
+ wheels = [
204
+ { url = "https://files.pythonhosted.org/packages/ce/8e/0c10ff1ea5d4360ab8bfca4cb2c9d979101a391f3e79d2616c9bf348cd26/ruff-0.14.3-py3-none-linux_armv6l.whl", hash = "sha256:876b21e6c824f519446715c1342b8e60f97f93264012de9d8d10314f8a79c371", size = 12535613, upload-time = "2025-10-31T00:25:44.302Z" },
205
+ { url = "https://files.pythonhosted.org/packages/d3/c8/6724f4634c1daf52409fbf13fefda64aa9c8f81e44727a378b7b73dc590b/ruff-0.14.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6fd8c79b457bedd2abf2702b9b472147cd860ed7855c73a5247fa55c9117654", size = 12855812, upload-time = "2025-10-31T00:25:47.793Z" },
206
+ { url = "https://files.pythonhosted.org/packages/de/03/db1bce591d55fd5f8a08bb02517fa0b5097b2ccabd4ea1ee29aa72b67d96/ruff-0.14.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:71ff6edca490c308f083156938c0c1a66907151263c4abdcb588602c6e696a14", size = 11944026, upload-time = "2025-10-31T00:25:49.657Z" },
207
+ { url = "https://files.pythonhosted.org/packages/0b/75/4f8dbd48e03272715d12c87dc4fcaaf21b913f0affa5f12a4e9c6f8a0582/ruff-0.14.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:786ee3ce6139772ff9272aaf43296d975c0217ee1b97538a98171bf0d21f87ed", size = 12356818, upload-time = "2025-10-31T00:25:51.949Z" },
208
+ { url = "https://files.pythonhosted.org/packages/ec/9b/506ec5b140c11d44a9a4f284ea7c14ebf6f8b01e6e8917734a3325bff787/ruff-0.14.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cd6291d0061811c52b8e392f946889916757610d45d004e41140d81fb6cd5ddc", size = 12336745, upload-time = "2025-10-31T00:25:54.248Z" },
209
+ { url = "https://files.pythonhosted.org/packages/c7/e1/c560d254048c147f35e7f8131d30bc1f63a008ac61595cf3078a3e93533d/ruff-0.14.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a497ec0c3d2c88561b6d90f9c29f5ae68221ac00d471f306fa21fa4264ce5fcd", size = 13101684, upload-time = "2025-10-31T00:25:56.253Z" },
210
+ { url = "https://files.pythonhosted.org/packages/a5/32/e310133f8af5cd11f8cc30f52522a3ebccc5ea5bff4b492f94faceaca7a8/ruff-0.14.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e231e1be58fc568950a04fbe6887c8e4b85310e7889727e2b81db205c45059eb", size = 14535000, upload-time = "2025-10-31T00:25:58.397Z" },
211
+ { url = "https://files.pythonhosted.org/packages/a2/a1/7b0470a22158c6d8501eabc5e9b6043c99bede40fa1994cadf6b5c2a61c7/ruff-0.14.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:469e35872a09c0e45fecf48dd960bfbce056b5db2d5e6b50eca329b4f853ae20", size = 14156450, upload-time = "2025-10-31T00:26:00.889Z" },
212
+ { url = "https://files.pythonhosted.org/packages/0a/96/24bfd9d1a7f532b560dcee1a87096332e461354d3882124219bcaff65c09/ruff-0.14.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d6bc90307c469cb9d28b7cfad90aaa600b10d67c6e22026869f585e1e8a2db0", size = 13568414, upload-time = "2025-10-31T00:26:03.291Z" },
213
+ { url = "https://files.pythonhosted.org/packages/a7/e7/138b883f0dfe4ad5b76b58bf4ae675f4d2176ac2b24bdd81b4d966b28c61/ruff-0.14.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2f8a0bbcffcfd895df39c9a4ecd59bb80dca03dc43f7fb63e647ed176b741e", size = 13315293, upload-time = "2025-10-31T00:26:05.708Z" },
214
+ { url = "https://files.pythonhosted.org/packages/33/f4/c09bb898be97b2eb18476b7c950df8815ef14cf956074177e9fbd40b7719/ruff-0.14.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:678fdd7c7d2d94851597c23ee6336d25f9930b460b55f8598e011b57c74fd8c5", size = 13539444, upload-time = "2025-10-31T00:26:08.09Z" },
215
+ { url = "https://files.pythonhosted.org/packages/9c/aa/b30a1db25fc6128b1dd6ff0741fa4abf969ded161599d07ca7edd0739cc0/ruff-0.14.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1ec1ac071e7e37e0221d2f2dbaf90897a988c531a8592a6a5959f0603a1ecf5e", size = 12252581, upload-time = "2025-10-31T00:26:10.297Z" },
216
+ { url = "https://files.pythonhosted.org/packages/da/13/21096308f384d796ffe3f2960b17054110a9c3828d223ca540c2b7cc670b/ruff-0.14.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:afcdc4b5335ef440d19e7df9e8ae2ad9f749352190e96d481dc501b753f0733e", size = 12307503, upload-time = "2025-10-31T00:26:12.646Z" },
217
+ { url = "https://files.pythonhosted.org/packages/cb/cc/a350bac23f03b7dbcde3c81b154706e80c6f16b06ff1ce28ed07dc7b07b0/ruff-0.14.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:7bfc42f81862749a7136267a343990f865e71fe2f99cf8d2958f684d23ce3dfa", size = 12675457, upload-time = "2025-10-31T00:26:15.044Z" },
218
+ { url = "https://files.pythonhosted.org/packages/cb/76/46346029fa2f2078826bc88ef7167e8c198e58fe3126636e52f77488cbba/ruff-0.14.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a65e448cfd7e9c59fae8cf37f9221585d3354febaad9a07f29158af1528e165f", size = 13403980, upload-time = "2025-10-31T00:26:17.81Z" },
219
+ { url = "https://files.pythonhosted.org/packages/9f/a4/35f1ef68c4e7b236d4a5204e3669efdeefaef21f0ff6a456792b3d8be438/ruff-0.14.3-py3-none-win32.whl", hash = "sha256:f3d91857d023ba93e14ed2d462ab62c3428f9bbf2b4fbac50a03ca66d31991f7", size = 12500045, upload-time = "2025-10-31T00:26:20.503Z" },
220
+ { url = "https://files.pythonhosted.org/packages/03/15/51960ae340823c9859fb60c63301d977308735403e2134e17d1d2858c7fb/ruff-0.14.3-py3-none-win_amd64.whl", hash = "sha256:d7b7006ac0756306db212fd37116cce2bd307e1e109375e1c6c106002df0ae5f", size = 13594005, upload-time = "2025-10-31T00:26:22.533Z" },
221
+ { url = "https://files.pythonhosted.org/packages/b7/73/4de6579bac8e979fca0a77e54dec1f1e011a0d268165eb8a9bc0982a6564/ruff-0.14.3-py3-none-win_arm64.whl", hash = "sha256:26eb477ede6d399d898791d01961e16b86f02bc2486d0d1a7a9bb2379d055dc1", size = 12590017, upload-time = "2025-10-31T00:26:24.52Z" },
222
+ ]
223
+
224
+ [[package]]
225
+ name = "tomli"
226
+ version = "2.3.0"
227
+ source = { registry = "https://pypi.org/simple" }
228
+ sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" }
229
+ wheels = [
230
+ { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" },
231
+ { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" },
232
+ { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" },
233
+ { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" },
234
+ { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" },
235
+ { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" },
236
+ { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" },
237
+ { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" },
238
+ { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" },
239
+ { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" },
240
+ { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" },
241
+ { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" },
242
+ { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" },
243
+ { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" },
244
+ { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" },
245
+ { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" },
246
+ { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" },
247
+ { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" },
248
+ { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" },
249
+ { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" },
250
+ { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" },
251
+ { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" },
252
+ { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" },
253
+ { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" },
254
+ { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" },
255
+ { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" },
256
+ { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" },
257
+ { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" },
258
+ { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" },
259
+ { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" },
260
+ { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" },
261
+ { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" },
262
+ { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" },
263
+ { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" },
264
+ { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" },
265
+ { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" },
266
+ { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" },
267
+ { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" },
268
+ { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" },
269
+ { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" },
270
+ { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" },
271
+ ]
272
+
273
+ [[package]]
274
+ name = "ty"
275
+ version = "0.0.1a25"
276
+ source = { registry = "https://pypi.org/simple" }
277
+ sdist = { url = "https://files.pythonhosted.org/packages/f6/6b/e73bc3c1039ea72936158a08313155a49e5aa5e7db5205a149fe516a4660/ty-0.0.1a25.tar.gz", hash = "sha256:5550b24b9dd0e0f8b4b2c1f0fcc608a55d0421dd67b6c364bc7bf25762334511", size = 4403670, upload-time = "2025-10-29T19:40:23.647Z" }
278
+ wheels = [
279
+ { url = "https://files.pythonhosted.org/packages/8f/3b/4457231238a2eeb04cba4ba7cc33d735be68ee46ca40a98ae30e187de864/ty-0.0.1a25-py3-none-linux_armv6l.whl", hash = "sha256:d35b2c1f94a014a22875d2745aa0432761d2a9a8eb7212630d5caf547daeef6d", size = 8878803, upload-time = "2025-10-29T19:39:42.243Z" },
280
+ { url = "https://files.pythonhosted.org/packages/8a/fa/a328713dd310018fc7a381693d8588185baa2fdae913e01a6839187215df/ty-0.0.1a25-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:192edac94675a468bac7f6e04687a77a64698e4e1fe01f6a048bf9b6dde5b703", size = 8695667, upload-time = "2025-10-29T19:39:45.179Z" },
281
+ { url = "https://files.pythonhosted.org/packages/22/e8/5707939118992ced2bf5385adc3ede7723c1b717b07ad14c495eea1e47b4/ty-0.0.1a25-py3-none-macosx_11_0_arm64.whl", hash = "sha256:949523621f336e01bc7d687b7bd08fe838edadbdb6563c2c057ed1d264e820cf", size = 8159012, upload-time = "2025-10-29T19:39:47.011Z" },
282
+ { url = "https://files.pythonhosted.org/packages/eb/fb/ff313aa71602225cd78f1bce3017713d6d1b1c1e0fa8101ead4594a60d95/ty-0.0.1a25-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f78f621458c05e59e890061021198197f29a7b51a33eda82bbb036e7ed73d7", size = 8433675, upload-time = "2025-10-29T19:39:48.443Z" },
283
+ { url = "https://files.pythonhosted.org/packages/c0/8d/cc7e7fb57215a15b575a43ed042bdd92971871e0decec1b26d2e7d969465/ty-0.0.1a25-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9656fca8062a2c6709c30d76d662c96d2e7dbfee8f70e55ec6b6afd67b5d447", size = 8668456, upload-time = "2025-10-29T19:39:50.412Z" },
284
+ { url = "https://files.pythonhosted.org/packages/b8/6d/d7bf5909ed2dcdcbc1e2ca7eea80929893e2d188d9c36b3fcb2b36532ff6/ty-0.0.1a25-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9f3bbf523b49935bbd76e230408d858dce0d614f44f5807bbbd0954f64e0f01", size = 9023543, upload-time = "2025-10-29T19:39:52.292Z" },
285
+ { url = "https://files.pythonhosted.org/packages/b4/b8/72bcefb4be32e5a84f0b21de2552f16cdb4cae3eb271ac891c8199c26b1a/ty-0.0.1a25-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f13ea9815f4a54a0a303ca7bf411b0650e3c2a24fc6c7889ffba2c94f5e97a6a", size = 9700013, upload-time = "2025-10-29T19:39:57.283Z" },
286
+ { url = "https://files.pythonhosted.org/packages/90/0d/cf7e794b840cf6b0bbecb022e593c543f85abad27a582241cf2095048cb1/ty-0.0.1a25-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eab6e33ebe202a71a50c3d5a5580e3bc1a85cda3ffcdc48cec3f1c693b7a873b", size = 9372574, upload-time = "2025-10-29T19:40:04.532Z" },
287
+ { url = "https://files.pythonhosted.org/packages/1e/71/2d35e7d51b48eabd330e2f7b7e0bce541cbd95950c4d2f780e85f3366af1/ty-0.0.1a25-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6b9a31da43424cdab483703a54a561b93aabba84630788505329fc5294a9c62", size = 9535726, upload-time = "2025-10-29T19:40:06.548Z" },
288
+ { url = "https://files.pythonhosted.org/packages/57/d3/01ecc23bbd8f3e0dfbcf9172d06d84e88155c5f416f1491137e8066fd859/ty-0.0.1a25-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a90d897a7c1a5ae9b41a4c7b0a42262a06361476ad88d783dbedd7913edadbc", size = 9003380, upload-time = "2025-10-29T19:40:08.683Z" },
289
+ { url = "https://files.pythonhosted.org/packages/de/f9/cde9380d8a1a6ca61baeb9aecb12cbec90d489aa929be55cd78ad5c2ccd9/ty-0.0.1a25-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:93c7e7ab2859af0f866d34d27f4ae70dd4fb95b847387f082de1197f9f34e068", size = 8401833, upload-time = "2025-10-29T19:40:10.627Z" },
290
+ { url = "https://files.pythonhosted.org/packages/0b/39/0acf3625b0c495011795a391016b572f97a812aca1d67f7a76621fdb9ebf/ty-0.0.1a25-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4a247061bd32bae3865a236d7f8b6c9916c80995db30ae1600999010f90623a9", size = 8706761, upload-time = "2025-10-29T19:40:12.575Z" },
291
+ { url = "https://files.pythonhosted.org/packages/25/73/7de1648f3563dd9d416d36ab5f1649bfd7b47a179135027f31d44b89a246/ty-0.0.1a25-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1711dd587eccf04fd50c494dc39babe38f4cb345bc3901bf1d8149cac570e979", size = 8792426, upload-time = "2025-10-29T19:40:14.553Z" },
292
+ { url = "https://files.pythonhosted.org/packages/7d/8a/b6e761a65eac7acd10b2e452f49b2d8ae0ea163ca36bb6b18b2dadae251b/ty-0.0.1a25-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f4c9b0cf7995e2e3de9bab4d066063dea92019f2f62673b7574e3612643dd35", size = 9103991, upload-time = "2025-10-29T19:40:16.332Z" },
293
+ { url = "https://files.pythonhosted.org/packages/e4/25/9324ae947fcc4322470326cf8276a3fc2f08dc82adec1de79d963fdf7af5/ty-0.0.1a25-py3-none-win32.whl", hash = "sha256:168fc8aee396d617451acc44cd28baffa47359777342836060c27aa6f37e2445", size = 8387095, upload-time = "2025-10-29T19:40:18.368Z" },
294
+ { url = "https://files.pythonhosted.org/packages/3b/2b/cb12cbc7db1ba310aa7b1de9b4e018576f653105993736c086ee67d2ec02/ty-0.0.1a25-py3-none-win_amd64.whl", hash = "sha256:a2fad3d8e92bb4d57a8872a6f56b1aef54539d36f23ebb01abe88ac4338efafb", size = 9059225, upload-time = "2025-10-29T19:40:20.278Z" },
295
+ { url = "https://files.pythonhosted.org/packages/2f/c1/f6be8cdd0bf387c1d8ee9d14bb299b7b5d2c0532f550a6693216a32ec0c5/ty-0.0.1a25-py3-none-win_arm64.whl", hash = "sha256:dde2962d448ed87c48736e9a4bb13715a4cced705525e732b1c0dac1d4c66e3d", size = 8536832, upload-time = "2025-10-29T19:40:22.014Z" },
296
+ ]
297
+
298
+ [[package]]
299
+ name = "typing-extensions"
300
+ version = "4.15.0"
301
+ source = { registry = "https://pypi.org/simple" }
302
+ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
303
+ wheels = [
304
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
305
+ ]