fastquadtree 1.3.0__tar.gz → 1.3.1__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.
Potentially problematic release.
This version of fastquadtree might be problematic. Click here for more details.
- fastquadtree-1.3.1/.github/workflows/test.yml +65 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/Cargo.lock +1 -1
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/Cargo.toml +1 -1
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/PKG-INFO +1 -1
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/_base_quadtree.py +15 -3
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/point_quadtree.py +2 -2
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/rect_quadtree.py +2 -2
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_insert_many_numpy.py +42 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_point_quadtree_dtypes.py +2 -2
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_rect_quadtree.py +2 -2
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/.github/workflows/docs.yml +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/.github/workflows/release.yml +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/.gitignore +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/.pre-commit-config.yaml +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/LICENSE +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/README.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/assets/ballpit.png +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/assets/interactive_v2_rect_screenshot.png +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/assets/interactive_v2_screenshot.png +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/assets/quadtree_bench_throughput.png +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/assets/quadtree_bench_time.png +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/benchmark_native_vs_shim.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/benchmark_np_vs_list.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/benchmark_serialization_vs_rebuild.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/cross_library_bench.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/quadtree_bench/__init__.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/quadtree_bench/engines.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/quadtree_bench/main.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/quadtree_bench/plotting.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/quadtree_bench/runner.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/requirements.txt +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/runner.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/benchmarks/system_info_collector.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/api/point_item.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/api/pyqtree.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/api/quadtree.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/api/rect_item.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/api/rect_quadtree.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/benchmark.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/future_features.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/index.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/quickstart.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/runnables.md +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/docs/styles/overrides.css +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/interactive/ballpit.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/interactive/interactive.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/interactive/interactive_v2.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/interactive/interactive_v2_rect.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/interactive/requirements.txt +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/mkdocs.yml +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pyproject.toml +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/__init__.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/_item.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/_obj_store.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/py.typed +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/pysrc/fastquadtree/pyqtree.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/src/geom.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/src/lib.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/src/quadtree.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/src/rect_quadtree.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/insertions.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/nearest_neighbor.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/query.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/rect_quadtree.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/rectangle_traversal.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/serialization.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_base_quadtree.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_clear.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_delete.rs +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_delete_by_object.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_delete_python.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_obj_store.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_point_quadtree_nn_runtime.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_pyqtree_shim_compat.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_python.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_serialization.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_unconventional_bounds.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/test_wrapper_edges.py +0 -0
- {fastquadtree-1.3.0 → fastquadtree-1.3.1}/tests/unconventional_bounds.rs +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# .github/workflows/test.yml
|
|
2
|
+
name: Test
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
pages: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Test build (Python ${{ matrix.python-version }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.9", "3.14"]
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
allow-prereleases: true
|
|
29
|
+
cache: "pip"
|
|
30
|
+
|
|
31
|
+
- name: Create venv for maturin develop
|
|
32
|
+
run: python -m venv .venv
|
|
33
|
+
|
|
34
|
+
- name: Build with maturin into this Python
|
|
35
|
+
uses: PyO3/maturin-action@v1
|
|
36
|
+
with:
|
|
37
|
+
command: develop
|
|
38
|
+
args: --release
|
|
39
|
+
manylinux: manylinux2014
|
|
40
|
+
|
|
41
|
+
- name: Install Python test deps into .venv
|
|
42
|
+
run: |
|
|
43
|
+
. .venv/bin/activate
|
|
44
|
+
pip install -e '.[dev]'
|
|
45
|
+
|
|
46
|
+
- name: Run Python tests
|
|
47
|
+
run: |
|
|
48
|
+
. .venv/bin/activate
|
|
49
|
+
pytest
|
|
50
|
+
|
|
51
|
+
- name: Run Python tests
|
|
52
|
+
run: |
|
|
53
|
+
. .venv/bin/activate
|
|
54
|
+
pytest
|
|
55
|
+
|
|
56
|
+
- name: Install Rust toolchain
|
|
57
|
+
uses: dtolnay/rust-toolchain@stable
|
|
58
|
+
|
|
59
|
+
- name: Run Rust tests
|
|
60
|
+
run: cargo test
|
|
61
|
+
|
|
62
|
+
- name: Upload coverage to Codecov
|
|
63
|
+
uses: codecov/codecov-action@v5
|
|
64
|
+
with:
|
|
65
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -29,6 +29,14 @@ G = TypeVar("G") # geometry type, e.g. Point or Bounds
|
|
|
29
29
|
HitT = TypeVar("HitT") # raw native tuple, e.g. (id,x,y) or (id,x0,y0,x1,y1)
|
|
30
30
|
ItemType = TypeVar("ItemType", bound=Item) # e.g. PointItem or RectItem
|
|
31
31
|
|
|
32
|
+
# Quadtree dtype to numpy dtype mapping
|
|
33
|
+
QUADTREE_DTYPE_TO_NP_DTYPE = {
|
|
34
|
+
"f32": "float32",
|
|
35
|
+
"f64": "float64",
|
|
36
|
+
"i32": "int32",
|
|
37
|
+
"i64": "int64",
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
|
|
33
41
|
def _is_np_array(x: Any) -> bool:
|
|
34
42
|
mod = getattr(x.__class__, "__module__", "")
|
|
@@ -250,7 +258,7 @@ class _BaseQuadTree(Generic[G, HitT, ItemType], ABC):
|
|
|
250
258
|
) -> int:
|
|
251
259
|
"""
|
|
252
260
|
Bulk insert with auto-assigned contiguous ids. Faster than inserting one-by-one.<br>
|
|
253
|
-
Can accept either a Python sequence of geometries or a NumPy array of shape (N,2) or (N,4) with dtype
|
|
261
|
+
Can accept either a Python sequence of geometries or a NumPy array of shape (N,2) or (N,4) with a dtype that matches the quadtree's dtype.
|
|
254
262
|
|
|
255
263
|
If tracking is enabled, the objects will be bulk stored internally.
|
|
256
264
|
If no objects are provided, the items will have obj=None (if tracking).
|
|
@@ -289,8 +297,12 @@ class _BaseQuadTree(Generic[G, HitT, ItemType], ABC):
|
|
|
289
297
|
if geoms.size == 0:
|
|
290
298
|
return 0
|
|
291
299
|
|
|
292
|
-
if
|
|
293
|
-
|
|
300
|
+
# Check if dtype matches quadtree dtype
|
|
301
|
+
expected_np_dtype = QUADTREE_DTYPE_TO_NP_DTYPE.get(self._dtype)
|
|
302
|
+
if geoms.dtype != expected_np_dtype:
|
|
303
|
+
raise TypeError(
|
|
304
|
+
f"Numpy array dtype {geoms.dtype} does not match quadtree dtype {self._dtype}"
|
|
305
|
+
)
|
|
294
306
|
|
|
295
307
|
if self._store is None:
|
|
296
308
|
# Simple contiguous path with native bulk insert
|
|
@@ -161,7 +161,7 @@ class QuadTree(_BaseQuadTree[Point, _IdCoord, PointItem]):
|
|
|
161
161
|
"""Create the native engine instance."""
|
|
162
162
|
rust_cls = DTYPE_MAP.get(self._dtype)
|
|
163
163
|
if rust_cls is None:
|
|
164
|
-
raise
|
|
164
|
+
raise TypeError(f"Unsupported dtype: {self._dtype}")
|
|
165
165
|
return rust_cls(bounds, capacity, max_depth)
|
|
166
166
|
|
|
167
167
|
@classmethod
|
|
@@ -169,7 +169,7 @@ class QuadTree(_BaseQuadTree[Point, _IdCoord, PointItem]):
|
|
|
169
169
|
"""Create a new native engine instance from serialized bytes."""
|
|
170
170
|
rust_cls = DTYPE_MAP.get(dtype)
|
|
171
171
|
if rust_cls is None:
|
|
172
|
-
raise
|
|
172
|
+
raise TypeError(f"Unsupported dtype: {dtype}")
|
|
173
173
|
return rust_cls.from_bytes(data)
|
|
174
174
|
|
|
175
175
|
@staticmethod
|
|
@@ -101,7 +101,7 @@ class RectQuadTree(_BaseQuadTree[Bounds, _IdRect, RectItem]):
|
|
|
101
101
|
"""Create the native engine instance."""
|
|
102
102
|
rust_cls = DTYPE_MAP.get(self._dtype)
|
|
103
103
|
if rust_cls is None:
|
|
104
|
-
raise
|
|
104
|
+
raise TypeError(f"Unsupported dtype: {self._dtype}")
|
|
105
105
|
return rust_cls(bounds, capacity, max_depth)
|
|
106
106
|
|
|
107
107
|
@classmethod
|
|
@@ -109,7 +109,7 @@ class RectQuadTree(_BaseQuadTree[Bounds, _IdRect, RectItem]):
|
|
|
109
109
|
"""Create a new native engine instance from serialized bytes."""
|
|
110
110
|
rust_cls = DTYPE_MAP.get(dtype)
|
|
111
111
|
if rust_cls is None:
|
|
112
|
-
raise
|
|
112
|
+
raise TypeError(f"Unsupported dtype: {dtype}")
|
|
113
113
|
return rust_cls.from_bytes(data)
|
|
114
114
|
|
|
115
115
|
@staticmethod
|
|
@@ -52,6 +52,48 @@ def test_type_error_on_wrong_dtype():
|
|
|
52
52
|
assert len(qt) == 0
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
def test_non_default_dtype_insert_many():
|
|
56
|
+
qt = QuadTree(BOUNDS, capacity=8, track_objects=True, dtype="f64")
|
|
57
|
+
points = np.array([[10, 10], [20, 20], [30, 30]], dtype=np.float64)
|
|
58
|
+
n = qt.insert_many(points)
|
|
59
|
+
assert n == 3
|
|
60
|
+
assert len(qt) == 3
|
|
61
|
+
|
|
62
|
+
raw = qt.query((0, 0, 40, 40), as_items=False)
|
|
63
|
+
|
|
64
|
+
assert len(raw) == 3
|
|
65
|
+
# ids and positions match
|
|
66
|
+
m_raw = {t[0]: (t[1], t[2]) for t in raw}
|
|
67
|
+
for t in raw:
|
|
68
|
+
assert (t[1], t[2]) == m_raw[t[0]]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_non_default_quadtree_dtype_with_default_numpy_dtype_raises():
|
|
72
|
+
qt = QuadTree(BOUNDS, capacity=8, track_objects=True, dtype="f64")
|
|
73
|
+
points = np.array([[10, 10], [20, 20], [30, 30]], dtype=np.float32) # Wrong dtype
|
|
74
|
+
with pytest.raises(TypeError):
|
|
75
|
+
qt.insert_many(points)
|
|
76
|
+
assert len(qt) == 0
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_unspported_quadtree_dtype_insert_many_raises():
|
|
80
|
+
qt = QuadTree(BOUNDS, capacity=8, track_objects=True, dtype="i32")
|
|
81
|
+
points = np.array([[10, 10], [20, 20], [30, 30]], dtype=np.float32) # Wrong dtype
|
|
82
|
+
with pytest.raises(TypeError):
|
|
83
|
+
qt.insert_many(points)
|
|
84
|
+
assert len(qt) == 0
|
|
85
|
+
|
|
86
|
+
points = np.array(
|
|
87
|
+
[[10, 10], [20, 20], [30, 30]], dtype=np.uint32
|
|
88
|
+
) # unsupported dtype
|
|
89
|
+
with pytest.raises(TypeError):
|
|
90
|
+
qt.insert_many(points)
|
|
91
|
+
|
|
92
|
+
# QT is also unsupported
|
|
93
|
+
with pytest.raises(TypeError):
|
|
94
|
+
qt = QuadTree(BOUNDS, capacity=8, track_objects=True, dtype="u32")
|
|
95
|
+
|
|
96
|
+
|
|
55
97
|
def test_insert_empty_numpy_array():
|
|
56
98
|
qt = QuadTree(BOUNDS, capacity=8, track_objects=True)
|
|
57
99
|
points = np.empty((0, 2), dtype=np.float32)
|
|
@@ -5,13 +5,13 @@ from fastquadtree import QuadTree
|
|
|
5
5
|
|
|
6
6
|
def test_unsupported_dtype():
|
|
7
7
|
"""Test that providing an unsupported dtype raises ValueError."""
|
|
8
|
-
with pytest.raises(
|
|
8
|
+
with pytest.raises(TypeError):
|
|
9
9
|
QuadTree((0, 0, 100, 100), capacity=4, track_objects=True, dtype="f128") # type: ignore
|
|
10
10
|
|
|
11
11
|
# From bytes
|
|
12
12
|
qt = QuadTree((0, 0, 100, 100), capacity=4, track_objects=True, dtype="f32")
|
|
13
13
|
data = qt.to_bytes()
|
|
14
|
-
with pytest.raises(
|
|
14
|
+
with pytest.raises(TypeError):
|
|
15
15
|
QuadTree.from_bytes(data, dtype="f128") # type: ignore
|
|
16
16
|
|
|
17
17
|
|
|
@@ -195,7 +195,7 @@ def test_accurate_obj_output_with_tracking():
|
|
|
195
195
|
|
|
196
196
|
def test_unsupported_dtype():
|
|
197
197
|
"""Test that providing an unsupported dtype raises ValueError."""
|
|
198
|
-
with pytest.raises(
|
|
198
|
+
with pytest.raises(TypeError):
|
|
199
199
|
rq.RectQuadTree(
|
|
200
200
|
b_to_float(0, 0, 100, 100), capacity=4, track_objects=True, dtype="f128"
|
|
201
201
|
) # type: ignore
|
|
@@ -205,7 +205,7 @@ def test_unsupported_dtype():
|
|
|
205
205
|
b_to_float(0, 0, 100, 100), capacity=4, track_objects=True, dtype="f32"
|
|
206
206
|
)
|
|
207
207
|
data = qt.to_bytes()
|
|
208
|
-
with pytest.raises(
|
|
208
|
+
with pytest.raises(TypeError):
|
|
209
209
|
rq.RectQuadTree.from_bytes(data, dtype="f128") # type: ignore
|
|
210
210
|
|
|
211
211
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|