From e64ff6731b83054d9e67b7d94ef23e186dca89ef Mon Sep 17 00:00:00 2001 From: AJ Friend Date: Sat, 9 Mar 2024 16:26:03 -0800 Subject: [PATCH] Replace _out_unordered and _out_ordered with _out_collection (#339) * Replace _out_unordered and _out_ordered with _out_collection * update batch of tests * lint * few more tests * group tests around APIs * few more tests * few more tests * couple few * final tests * test_icosahedron_faces * lint * remove redundant tests * consolidate same_set * same_set * update makefile * remove the .so files * Add note indicating that there is no guaranteed ordering of cells for many functions * bump to pypa/cibuildwheel@v2.16.5 --- .github/workflows/wheels.yml | 2 +- makefile | 4 +- src/h3/_cy/cells.pyx | 2 +- src/h3/api/basic_int/__init__.py | 61 +++++++++++---- src/h3/api/basic_int/_convert.py | 3 +- src/h3/api/basic_str/_convert.py | 8 +- src/h3/api/memview_int/_convert.py | 3 +- src/h3/api/numpy_int/_convert.py | 3 +- tests/polyfill/__init__.py | 0 tests/polyfill/test_h3.py | 18 +++-- tests/polyfill/test_polyfill.py | 21 +++-- tests/polyfill/test_polygon_class.py | 4 +- tests/polyfill/test_to_multipoly.py | 16 ++-- tests/test_apis/__init__.py | 0 .../test_api_bindings_match.py | 0 tests/{ => test_apis}/test_basic_int.py | 28 ++----- tests/{ => test_apis}/test_basic_str.py | 9 ++- .../{ => test_apis}/test_collection_inputs.py | 10 +-- tests/test_apis/test_ico_faces.py | 30 +++++++ tests/{ => test_apis}/test_memview_int.py | 17 ---- tests/{ => test_apis}/test_numpy_int.py | 23 +----- tests/test_cells_and_edges.py | 78 +++++++------------ tests/test_h3.py | 30 ++++--- tests/test_length_area.py | 14 +--- tests/util.py | 21 +++++ 25 files changed, 216 insertions(+), 189 deletions(-) create mode 100644 tests/polyfill/__init__.py create mode 100644 tests/test_apis/__init__.py rename tests/{ => test_apis}/test_api_bindings_match.py (100%) rename tests/{ => test_apis}/test_basic_int.py (55%) rename tests/{ => test_apis}/test_basic_str.py (82%) rename tests/{ => test_apis}/test_collection_inputs.py (93%) create mode 100644 tests/test_apis/test_ico_faces.py rename tests/{ => test_apis}/test_memview_int.py (60%) rename tests/{ => test_apis}/test_numpy_int.py (59%) create mode 100644 tests/util.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 5d4bc60c..e6f9d749 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -119,7 +119,7 @@ jobs: ## Build - - uses: pypa/cibuildwheel@v2.16.2 + - uses: pypa/cibuildwheel@v2.16.5 env: CIBW_TEST_REQUIRES: pytest numpy CIBW_TEST_COMMAND: pytest {project}/tests diff --git a/makefile b/makefile index a2f59da8..31b47cb5 100644 --- a/makefile +++ b/makefile @@ -20,9 +20,11 @@ clear: -./env/bin/pip uninstall -y h3 -@rm -rf MANIFEST -@rm -rf annotations - -@rm -rf .pytest_cache tests/__pycache__ __pycache__ _skbuild dist .coverage + -@rm -rf .pytest_cache _skbuild dist .coverage build + -@find . -type d -name '__pycache__' | xargs rm -r -@find . -type d -name '*.egg-info' | xargs rm -r -@find . -type f -name '*.pyc' | xargs rm -r + -@find . -type f -name '*.so' | xargs rm -r -@find . -type d -name '*.ipynb_checkpoints' | xargs rm -r -@find ./tests -type f -name '*.c' | xargs rm -r diff --git a/src/h3/_cy/cells.pyx b/src/h3/_cy/cells.pyx index 6a215769..64be807e 100644 --- a/src/h3/_cy/cells.pyx +++ b/src/h3/_cy/cells.pyx @@ -386,7 +386,7 @@ cpdef get_icosahedron_faces(H3int h): # todo: wait? do faces start from 0 or 1? # we could do this check/processing in the int_mv object - out = {f for f in faces if f >= 0} + out = [f for f in faces if f >= 0] return out diff --git a/src/h3/api/basic_int/__init__.py b/src/h3/api/basic_int/__init__.py index a9858cb8..b0c7e9b8 100644 --- a/src/h3/api/basic_int/__init__.py +++ b/src/h3/api/basic_int/__init__.py @@ -13,8 +13,7 @@ _in_scalar, _out_scalar, _in_collection, - _out_unordered, - _out_ordered, + _out_collection, ) @@ -258,7 +257,7 @@ def cell_to_boundary(h): def grid_disk(h, k=1): """ - Return unordered set of cells with H3 distance ``<= k`` from ``h``. + Return unordered collection of cells with H3 distance ``<= k`` from ``h``. That is, the 'filled-in' disk. Parameters @@ -270,15 +269,19 @@ def grid_disk(h, k=1): Returns ------- unordered collection of H3Cell + + Notes + ----- + There is currently no guaranteed order of the output cells. """ mv = _cy.grid_disk(_in_scalar(h), k) - return _out_unordered(mv) + return _out_collection(mv) def grid_ring(h, k=1): """ - Return unordered set of cells with H3 distance ``== k`` from ``h``. + Return unordered collection of cells with H3 distance ``== k`` from ``h``. That is, the "hollow" ring. Parameters @@ -290,15 +293,19 @@ def grid_ring(h, k=1): Returns ------- unordered collection of H3Cell + + Notes + ----- + There is currently no guaranteed order of the output cells. """ mv = _cy.grid_ring(_in_scalar(h), k) - return _out_unordered(mv) + return _out_collection(mv) def cell_to_children(h, res=None): """ - Children of a cell. + Children of a cell as an unordered collection. Parameters ---------- @@ -310,10 +317,14 @@ def cell_to_children(h, res=None): Returns ------- unordered collection of H3Cell + + Notes + ----- + There is currently no guaranteed order of the output cells. """ mv = _cy.cell_to_children(_in_scalar(h), res) - return _out_unordered(mv) + return _out_collection(mv) # todo: nogil for expensive C operation? @@ -330,12 +341,16 @@ def compact_cells(cells): Returns ------- unordered collection of H3Cell + + Notes + ----- + There is currently no guaranteed order of the output cells. """ # todo: does compact_cells work on mixed-resolution collections? hu = _in_collection(cells) hc = _cy.compact_cells(hu) - return _out_unordered(hc) + return _out_collection(hc) def uncompact_cells(cells, res): @@ -359,11 +374,15 @@ def uncompact_cells(cells, res): todo: add test to make sure an error is returned when input contains cell smaller than output res. https://github.com/uber/h3/blob/master/src/h3lib/lib/h3Index.c#L425 + + Notes + ----- + There is currently no guaranteed order of the output cells. """ hc = _in_collection(cells) hu = _cy.uncompact_cells(hc, res) - return _out_unordered(hu) + return _out_collection(hu) def h3shape_to_cells(h3shape, res): @@ -396,6 +415,10 @@ def h3shape_to_cells(h3shape, res): '862830947ffffff', '862830957ffffff', '86283095fffffff'} + + Notes + ----- + There is currently no guaranteed order of the output cells. """ # todo: not sure if i want this dispatch logic here. maybe in the objects? @@ -410,7 +433,7 @@ def h3shape_to_cells(h3shape, res): else: raise ValueError('Unrecognized type: ' + str(type(h3shape))) - return _out_unordered(mv) + return _out_collection(mv) def cells_to_h3shape(cells, tight=True): @@ -457,6 +480,10 @@ def geo_to_cells(geo, res): Both H3Poly and H3MultiPoly implement the interface. res : int Resolution of desired output cells. + + Notes + ----- + There is currently no guaranteed order of the output cells. """ h3shape = geo_to_h3shape(geo) return h3shape_to_cells(h3shape, res) @@ -643,7 +670,7 @@ def origin_to_directed_edges(origin): """ mv = _cy.origin_to_directed_edges(_in_scalar(origin)) - return _out_unordered(mv) + return _out_collection(mv) def directed_edge_to_boundary(edge): @@ -667,7 +694,7 @@ def grid_path_cells(start, end): """ mv = _cy.grid_path_cells(_in_scalar(start), _in_scalar(end)) - return _out_ordered(mv) + return _out_collection(mv) def is_res_class_III(h): @@ -715,7 +742,7 @@ def get_pentagons(res): """ mv = _cy.get_pentagons(res) - return _out_unordered(mv) + return _out_collection(mv) def get_res0_cells(): @@ -729,10 +756,14 @@ def get_res0_cells(): Returns ------- unordered collection of H3Cell + + Notes + ----- + There is currently no guaranteed order of the output cells. """ mv = _cy.get_res0_cells() - return _out_unordered(mv) + return _out_collection(mv) def cell_to_center_child(h, res=None): diff --git a/src/h3/api/basic_int/_convert.py b/src/h3/api/basic_int/_convert.py index 48cfcb94..51f47283 100644 --- a/src/h3/api/basic_int/_convert.py +++ b/src/h3/api/basic_int/_convert.py @@ -14,5 +14,4 @@ def _in_collection(cells): return _cy.iter_to_mv(it) -_out_unordered = set -_out_ordered = list +_out_collection = list diff --git a/src/h3/api/basic_str/_convert.py b/src/h3/api/basic_str/_convert.py index bad3a955..a6c0ba0d 100644 --- a/src/h3/api/basic_str/_convert.py +++ b/src/h3/api/basic_str/_convert.py @@ -10,11 +10,5 @@ def _in_collection(cells): return _cy.iter_to_mv(it) -def _out_unordered(mv): - # todo: should this be an (immutable) frozenset? - return set(_cy.int_to_str(h) for h in mv) - - -def _out_ordered(mv): - # todo: should this be an (immutable) tuple? +def _out_collection(mv): return list(_cy.int_to_str(h) for h in mv) diff --git a/src/h3/api/memview_int/_convert.py b/src/h3/api/memview_int/_convert.py index 9145baf0..2f054fd2 100644 --- a/src/h3/api/memview_int/_convert.py +++ b/src/h3/api/memview_int/_convert.py @@ -5,5 +5,4 @@ def _id(x): _in_scalar = _id _out_scalar = _id _in_collection = _id -_out_unordered = _id -_out_ordered = _id +_out_collection = _id diff --git a/src/h3/api/numpy_int/_convert.py b/src/h3/api/numpy_int/_convert.py index 2db5b14d..6b293cc9 100644 --- a/src/h3/api/numpy_int/_convert.py +++ b/src/h3/api/numpy_int/_convert.py @@ -12,5 +12,4 @@ def _in_collection(x): return np.asarray(x, dtype='uint64') -_out_unordered = _in_collection -_out_ordered = _in_collection +_out_collection = _in_collection diff --git a/tests/polyfill/__init__.py b/tests/polyfill/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/polyfill/test_h3.py b/tests/polyfill/test_h3.py index c38ff5f8..78d32238 100644 --- a/tests/polyfill/test_h3.py +++ b/tests/polyfill/test_h3.py @@ -1,6 +1,8 @@ import h3 import pytest +from .. import util as u + class MockGeoInterface: def __init__(self, dictionary): @@ -111,9 +113,12 @@ def test_polyfill_with_hole(): out = h3.h3shape_to_cells(poly, res=9) assert len(out) == 1214 - foo = lambda x: h3.h3shape_to_cells(h3.H3Poly(x), 9) - # todo: foo = lambda x: h3.H3Poly(x).to_cells(9) - assert out == foo(sf_7x7) - foo(sf_hole1) + foo = lambda x: set(h3.h3shape_to_cells(h3.H3Poly(x), 9)) + + assert u.same_set( + out, + foo(sf_7x7) - foo(sf_hole1) + ) def test_polyfill_with_two_holes(): @@ -122,8 +127,11 @@ def test_polyfill_with_two_holes(): out = h3.h3shape_to_cells(poly, 9) assert len(out) == 1172 - foo = lambda x: h3.h3shape_to_cells(h3.H3Poly(x), 9) - assert out == foo(sf_7x7) - (foo(sf_hole1) | foo(sf_hole2)) + foo = lambda x: set(h3.h3shape_to_cells(h3.H3Poly(x), 9)) + assert u.same_set( + out, + foo(sf_7x7) - (foo(sf_hole1) | foo(sf_hole2)) + ) def test_polyfill_geo_json_compliant(): diff --git a/tests/polyfill/test_polyfill.py b/tests/polyfill/test_polyfill.py index 7b059eb7..541c453b 100644 --- a/tests/polyfill/test_polyfill.py +++ b/tests/polyfill/test_polyfill.py @@ -3,6 +3,8 @@ from h3 import H3ResDomainError +from .. import util as u + def get_us_box_coords(): @@ -72,7 +74,7 @@ def test_h3shape_to_cells(): poly = h3.H3Poly(maine) out = h3.h3shape_to_cells(poly, 3) - assert out == expected + assert u.same_set(out, expected) def test_h3shape_to_cells2(): @@ -100,20 +102,23 @@ def test_h3shape_to_cells_holes(): for res in 1, 2, 3, 4, 5: cells_all = h3.h3shape_to_cells(h3.H3Poly(outer), res) - cells_holes = h3.h3shape_to_cells(h3.H3Poly(outer, hole1, hole2), res=res) + cells_holes = set(h3.h3shape_to_cells(h3.H3Poly(outer, hole1, hole2), res=res)) - cells_1 = h3.h3shape_to_cells(h3.H3Poly(hole1), res) - cells_2 = h3.h3shape_to_cells(h3.H3Poly(hole2), res) + cells_1 = set(h3.h3shape_to_cells(h3.H3Poly(hole1), res)) + cells_2 = set(h3.h3shape_to_cells(h3.H3Poly(hole2), res)) assert len(cells_all) == len(cells_holes) + len(cells_1) + len(cells_2) - assert cells_all == set.union(cells_holes, cells_1, cells_2) + assert u.same_set( + cells_all, + set.union(cells_holes, cells_1, cells_2) + ) def test_resolution(): poly = h3.H3Poly([]) - assert h3.h3shape_to_cells(poly, 0) == set() - assert h3.h3shape_to_cells(poly, 15) == set() + assert h3.h3shape_to_cells(poly, 0) == [] + assert h3.h3shape_to_cells(poly, 15) == [] with pytest.raises(H3ResDomainError): h3.h3shape_to_cells(poly, -1) @@ -158,4 +163,4 @@ def test_cells_to_geo(): assert len(coord[0]) == 7 assert coord[0][0] == coord[0][-1] - assert h3.geo_to_cells(geo, res) == {h} + assert h3.geo_to_cells(geo, res) == [h] diff --git a/tests/polyfill/test_polygon_class.py b/tests/polyfill/test_polygon_class.py index ec450f56..4ed7faa3 100644 --- a/tests/polyfill/test_polygon_class.py +++ b/tests/polyfill/test_polygon_class.py @@ -6,8 +6,8 @@ def test_repr(): a = '8928308280fffff' b = h3.grid_ring(a, 5).pop() - cells1 = h3.grid_ring(b, 2) | {a} - cells2 = cells1 | {b} + cells1 = h3.grid_ring(b, 2) + [a] + cells2 = cells1 + [b] mpoly1 = h3.cells_to_h3shape(cells1) mpoly2 = h3.cells_to_h3shape(cells2) diff --git a/tests/polyfill/test_to_multipoly.py b/tests/polyfill/test_to_multipoly.py index e613d4df..1207da2a 100644 --- a/tests/polyfill/test_to_multipoly.py +++ b/tests/polyfill/test_to_multipoly.py @@ -1,6 +1,9 @@ import h3 +from .. import util as u + + def test_cells_to_h3shape(): h = '8928308280fffff' cells = h3.grid_disk(h, 1) @@ -11,7 +14,7 @@ def test_cells_to_h3shape(): poly2 = h3.H3Poly(poly.outer, *poly.holes) out = h3.h3shape_to_cells(poly2, 9) - assert out == cells + assert u.same_set(out, cells) def test_cells_to_h3shape_tight(): @@ -22,22 +25,25 @@ def test_cells_to_h3shape_tight(): poly2 = h3.H3Poly(poly.outer, *poly.holes) out = h3.h3shape_to_cells(poly2, 9) - assert out == cells + assert u.same_set(out, cells) def test_2_polys(): h = '8928308280fffff' cells = h3.grid_ring(h, 2) - cells = cells | {h} + cells = cells + [h] # cells should be a center hex, and the 2-ring around it # (with the 1-ring being absent) mpoly = h3.cells_to_h3shape(cells) out = [ - h3.h3shape_to_cells(poly, 9) + set(h3.h3shape_to_cells(poly, 9)) for poly in mpoly ] - assert set.union(*out) == cells + assert u.same_set( + set.union(*out), + cells + ) assert set(map(len, out)) == {1, 12} diff --git a/tests/test_apis/__init__.py b/tests/test_apis/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_api_bindings_match.py b/tests/test_apis/test_api_bindings_match.py similarity index 100% rename from tests/test_api_bindings_match.py rename to tests/test_apis/test_api_bindings_match.py diff --git a/tests/test_basic_int.py b/tests/test_apis/test_basic_int.py similarity index 55% rename from tests/test_basic_int.py rename to tests/test_apis/test_basic_int.py index 99452feb..a567b3de 100644 --- a/tests/test_basic_int.py +++ b/tests/test_apis/test_basic_int.py @@ -1,6 +1,9 @@ import h3.api.basic_int as h3 +from .. import util as u + + def test_int_output(): lat = 37.7752702151959 lng = -122.418307270836 @@ -10,7 +13,7 @@ def test_int_output(): def test_grid_disk(): - expected = { + expected = [ 617700169957507071, 617700169957769215, 617700169958031359, @@ -18,31 +21,14 @@ def test_grid_disk(): 617700169961177087, 617700169964847103, 617700169965109247, - } + ] out = h3.grid_disk(617700169958293503, 1) - assert out == expected + assert u.same_set(out, expected) def test_compact_cells(): h = 617700169958293503 cells = h3.cell_to_children(h) - assert h3.compact_cells(cells) == {h} - - -def test_get_icosahedron_faces(): - h = 577832942814887935 - expected = {2, 3, 7, 8, 12} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = 579873636396040191 - expected = {13} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = 579768083279773695 - expected = {16, 15} - out = h3.get_icosahedron_faces(h) - assert out == expected + assert h3.compact_cells(cells) == [h] diff --git a/tests/test_basic_str.py b/tests/test_apis/test_basic_str.py similarity index 82% rename from tests/test_basic_str.py rename to tests/test_apis/test_basic_str.py index eaae35bb..0c65a827 100644 --- a/tests/test_basic_str.py +++ b/tests/test_apis/test_basic_str.py @@ -1,13 +1,16 @@ import h3.api.basic_str as h3 +from .. import util as u + + def test1(): lat, lng = 37.7752702151959, -122.418307270836 assert h3.latlng_to_cell(lat, lng, 9) == '8928308280fffff' def test5(): - expected = { + expected = [ '89283082873ffff', '89283082877ffff', '8928308283bffff', @@ -15,7 +18,7 @@ def test5(): '8928308280bffff', '8928308280fffff', '89283082803ffff' - } + ] out = h3.grid_disk('8928308280fffff', 1) - assert out == expected + assert u.same_set(out, expected) diff --git a/tests/test_collection_inputs.py b/tests/test_apis/test_collection_inputs.py similarity index 93% rename from tests/test_collection_inputs.py rename to tests/test_apis/test_collection_inputs.py index 92a8ba54..5f826a14 100644 --- a/tests/test_collection_inputs.py +++ b/tests/test_apis/test_collection_inputs.py @@ -22,7 +22,7 @@ def test_set(): h = 614553222213795839 - assert basic_int.compact_cells(ints) == {h} + assert basic_int.compact_cells(ints) == [h] with pytest.raises(TypeError): # numpy can't convert from a set @@ -46,7 +46,7 @@ def test_list(): h = 614553222213795839 - assert basic_int.compact_cells(ints) == {h} + assert basic_int.compact_cells(ints) == [h] # numpy can convert from a list OK # (numpy knows to convert it to uint64) @@ -74,7 +74,7 @@ def test_np_array(): h = 614553222213795839 - assert basic_int.compact_cells(ints) == {h} + assert basic_int.compact_cells(ints) == [h] assert numpy_int.compact_cells(ints) == np.array([h], dtype='uint64') assert numpy_int.compact_cells(ints).dtype == np.dtype('uint64') @@ -99,7 +99,7 @@ def test_list_to_array(): h = 614553222213795839 - assert basic_int.compact_cells(ints) == {h} + assert basic_int.compact_cells(ints) == [h] assert numpy_int.compact_cells(ints) == np.array([h], dtype='uint64') with pytest.raises(ValueError): @@ -128,7 +128,7 @@ def foo(): h = 614553222213795839 ints = foo() - assert basic_int.compact_cells(ints) == {h} + assert basic_int.compact_cells(ints) == [h] ints = foo() with pytest.raises(TypeError): diff --git a/tests/test_apis/test_ico_faces.py b/tests/test_apis/test_ico_faces.py new file mode 100644 index 00000000..6466ab0a --- /dev/null +++ b/tests/test_apis/test_ico_faces.py @@ -0,0 +1,30 @@ +import h3 + + +def test_icosahedron_faces(): + """ + get_icosahedron_faces is kind of a special case, because it always returns + a list of integers no matter the API + """ + answers = { + '804dfffffffffff': [2, 3, 7, 8, 12], + '80c1fffffffffff': [13], + '80bbfffffffffff': [15, 16], + } + + interfaces = [ + (h3.api.basic_str, lambda x: x), + (h3.api.basic_int, h3.str_to_int), + (h3.api.memview_int, h3.str_to_int), + (h3.api.numpy_int, h3.str_to_int), + ] + + for api, conv in interfaces: + for h in answers: + expected = answers[h] + + h = conv(h) # convert to int or str, depending on API + out = api.get_icosahedron_faces(h) + + assert isinstance(out, list) + assert set(out) == set(expected) diff --git a/tests/test_memview_int.py b/tests/test_apis/test_memview_int.py similarity index 60% rename from tests/test_memview_int.py rename to tests/test_apis/test_memview_int.py index 0e7e56e4..05237942 100644 --- a/tests/test_memview_int.py +++ b/tests/test_apis/test_memview_int.py @@ -23,20 +23,3 @@ def test_line(): ] assert list(out) == expected - - -def test_get_icosahedron_faces(): - h = 577832942814887935 - expected = {2, 3, 7, 8, 12} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = 579873636396040191 - expected = {13} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = 579768083279773695 - expected = {16, 15} - out = h3.get_icosahedron_faces(h) - assert out == expected diff --git a/tests/test_numpy_int.py b/tests/test_apis/test_numpy_int.py similarity index 59% rename from tests/test_numpy_int.py rename to tests/test_apis/test_numpy_int.py index c565518d..2ffa43f0 100644 --- a/tests/test_numpy_int.py +++ b/tests/test_apis/test_numpy_int.py @@ -1,6 +1,8 @@ import h3.api.numpy_int as h3 import numpy as np # only run this test suite if numpy is installed +from .. import util as u + def test1(): lat, lng = 37.7752702151959, -122.418307270836, @@ -20,7 +22,7 @@ def test5(): out = h3.grid_disk(617700169958293503, 1) assert isinstance(out, np.ndarray) - assert set(out) == expected + assert u.same_set(out, expected) def test_compact_cells(): @@ -28,21 +30,4 @@ def test_compact_cells(): cells = h3.cell_to_children(h) assert isinstance(cells, np.ndarray) - assert set(h3.compact_cells(cells)) == {h} - - -def test_get_icosahedron_faces(): - h = 577832942814887935 - expected = {2, 3, 7, 8, 12} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = 579873636396040191 - expected = {13} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = 579768083279773695 - expected = {16, 15} - out = h3.get_icosahedron_faces(h) - assert out == expected + assert h3.compact_cells(cells) == [h] diff --git a/tests/test_cells_and_edges.py b/tests/test_cells_and_edges.py index c82c6ab2..1e4c5d75 100644 --- a/tests/test_cells_and_edges.py +++ b/tests/test_cells_and_edges.py @@ -11,14 +11,7 @@ ) -def approx2(a, b): - if len(a) != len(b): - return False - - return all( - x == pytest.approx(y) - for x, y in zip(a, b) - ) +from . import util as u def test1(): @@ -44,7 +37,7 @@ def test3(): ) out = h3.cell_to_boundary('8928308280fffff') - assert approx2(out, expected) + assert u.approx2(out, expected) def test_grid_disk_distance(): @@ -58,7 +51,7 @@ def test_grid_ring_distance(): def test5(): - expected = { + expected = [ '89283082873ffff', '89283082877ffff', '8928308283bffff', @@ -66,30 +59,30 @@ def test5(): '8928308280bffff', '8928308280fffff', '89283082803ffff' - } + ] out = h3.grid_disk('8928308280fffff', 1) - assert out == expected + assert u.same_set(out, expected) def test6(): - expected = {'8928308280fffff'} + expected = ['8928308280fffff'] out = h3.grid_ring('8928308280fffff', 0) - assert out == expected + assert u.same_set(out, expected) def test7(): - expected = { + expected = [ '89283082803ffff', '89283082807ffff', '8928308280bffff', '8928308283bffff', '89283082873ffff', '89283082877ffff' - } + ] out = h3.grid_ring('8928308280fffff', 1) - assert out == expected + assert u.same_set(out, expected) def test8(): @@ -149,10 +142,10 @@ def test_children(): # same resolution is set of just cell itself out = h3.cell_to_children(h, 9) - assert out == {h} + assert out == [h] # one below should give children - expected = { + expected = [ '8a28308280c7fff', '8a28308280cffff', '8a28308280d7fff', @@ -160,9 +153,9 @@ def test_children(): '8a28308280e7fff', '8a28308280effff', '8a28308280f7fff' - } + ] out = h3.cell_to_children(h, 10) - assert out == expected + assert u.same_set(out, expected) # finest resolution cell should return error for children h = '8f04ccb2c45e225' @@ -242,7 +235,7 @@ def get_maine_cells(): cells_uncomp = h3.h3shape_to_cells(poly, res=res) # the expected result from h3.compact_cells(cells_uncomp) - cells_comp = {'852b114ffffffff', '852b189bfffffff', '852b1163fffffff', '842ba9bffffffff', '842bad3ffffffff', '852ba9cffffffff', '842badbffffffff', '852b1e8bfffffff', '852a346ffffffff', '842b1e3ffffffff', '852b116ffffffff', '842b185ffffffff', '852b1bdbfffffff', '852bad47fffffff', '852ba9c3fffffff', '852b106bfffffff', '852a30d3fffffff', '842b1edffffffff', '852b12a7fffffff', '852b1027fffffff', '842baddffffffff', '852a349bfffffff', '852b1227fffffff', '852a3473fffffff', '852b117bfffffff', '842ba99ffffffff', '852a341bfffffff', '852ba9d3fffffff', '852b1067fffffff', '852a3463fffffff', '852baca7fffffff', '852b116bfffffff', '852b1c6bfffffff', '852a3493fffffff', '852ba9dbfffffff', '852b180bfffffff', '842bad7ffffffff', '852b1063fffffff', '842ba93ffffffff', '852a3693fffffff', '852ba977fffffff', '852b1e9bfffffff', '852bad53fffffff', '852b100ffffffff', '852b102bfffffff', '852a3413fffffff', '852ba8b7fffffff', '852bad43fffffff', '852b1c6ffffffff', '852a340bfffffff', '852b103bfffffff', '852b1813fffffff', '852b12affffffff', '842a34dffffffff', '852b1873fffffff', '852b106ffffffff', '852b115bfffffff', '852baca3fffffff', '852b114bfffffff', '852b1143fffffff', '852a348bfffffff', '852a30d7fffffff', '852b181bfffffff', '842a345ffffffff', '852b1e8ffffffff', '852b1883fffffff', '852b1147fffffff', '852a3483fffffff', '852b12a3fffffff', '852a346bfffffff', '852ba9d7fffffff', '842b18dffffffff', '852b188bfffffff', '852a36a7fffffff', '852bacb3fffffff', '852b187bfffffff', '852bacb7fffffff', '842b1ebffffffff', '842b1e5ffffffff', '852ba8a7fffffff', '842bad9ffffffff', '852a36b7fffffff', '852a347bfffffff', '832b13fffffffff', '852ba9c7fffffff', '832b1afffffffff', '842ba91ffffffff', '852bad57fffffff', '852ba8affffffff', '852b1803fffffff', '842b1e7ffffffff', '852bad4ffffffff', '852b102ffffffff', '852b1077fffffff', '852b1237fffffff', '852b1153fffffff', '852a3697fffffff', '852a36b3fffffff', '842bad1ffffffff', '842b1e1ffffffff', '852b186bfffffff', '852b1023fffffff'} # noqa + cells_comp = ['852b114ffffffff', '852b189bfffffff', '852b1163fffffff', '842ba9bffffffff', '842bad3ffffffff', '852ba9cffffffff', '842badbffffffff', '852b1e8bfffffff', '852a346ffffffff', '842b1e3ffffffff', '852b116ffffffff', '842b185ffffffff', '852b1bdbfffffff', '852bad47fffffff', '852ba9c3fffffff', '852b106bfffffff', '852a30d3fffffff', '842b1edffffffff', '852b12a7fffffff', '852b1027fffffff', '842baddffffffff', '852a349bfffffff', '852b1227fffffff', '852a3473fffffff', '852b117bfffffff', '842ba99ffffffff', '852a341bfffffff', '852ba9d3fffffff', '852b1067fffffff', '852a3463fffffff', '852baca7fffffff', '852b116bfffffff', '852b1c6bfffffff', '852a3493fffffff', '852ba9dbfffffff', '852b180bfffffff', '842bad7ffffffff', '852b1063fffffff', '842ba93ffffffff', '852a3693fffffff', '852ba977fffffff', '852b1e9bfffffff', '852bad53fffffff', '852b100ffffffff', '852b102bfffffff', '852a3413fffffff', '852ba8b7fffffff', '852bad43fffffff', '852b1c6ffffffff', '852a340bfffffff', '852b103bfffffff', '852b1813fffffff', '852b12affffffff', '842a34dffffffff', '852b1873fffffff', '852b106ffffffff', '852b115bfffffff', '852baca3fffffff', '852b114bfffffff', '852b1143fffffff', '852a348bfffffff', '852a30d7fffffff', '852b181bfffffff', '842a345ffffffff', '852b1e8ffffffff', '852b1883fffffff', '852b1147fffffff', '852a3483fffffff', '852b12a3fffffff', '852a346bfffffff', '852ba9d7fffffff', '842b18dffffffff', '852b188bfffffff', '852a36a7fffffff', '852bacb3fffffff', '852b187bfffffff', '852bacb7fffffff', '842b1ebffffffff', '842b1e5ffffffff', '852ba8a7fffffff', '842bad9ffffffff', '852a36b7fffffff', '852a347bfffffff', '832b13fffffffff', '852ba9c7fffffff', '832b1afffffffff', '842ba91ffffffff', '852bad57fffffff', '852ba8affffffff', '852b1803fffffff', '842b1e7ffffffff', '852bad4ffffffff', '852b102ffffffff', '852b1077fffffff', '852b1237fffffff', '852b1153fffffff', '852a3697fffffff', '852a36b3fffffff', '842bad1ffffffff', '842b1e1ffffffff', '852b186bfffffff', '852b1023fffffff'] # noqa return cells_uncomp, cells_comp, res @@ -251,13 +244,13 @@ def test_compact_cells(): cells_uncomp, cells_comp, _ = get_maine_cells() out = h3.compact_cells(cells_uncomp) - assert out == cells_comp + assert u.same_set(out, cells_comp) def test_uncompact_cells(): cells_uncomp, cells_comp, res = get_maine_cells() out = h3.uncompact_cells(cells_comp, res) - assert out == cells_uncomp + assert u.same_set(out, cells_uncomp) def test_get_num_cells(): @@ -339,7 +332,7 @@ def test_origin_to_directed_edges(): } neighbors = h3.grid_ring(h, 1) - assert neighbors == destinations + assert u.same_set(neighbors, destinations) def test_edge_boundary(): @@ -484,7 +477,7 @@ def test_edge_is_valid_fail(): def test_get_pentagons(): out = h3.get_pentagons(0) - expected = { + expected = [ '8009fffffffffff', '801dfffffffffff', '8031fffffffffff', @@ -497,13 +490,13 @@ def test_get_pentagons(): '80c3fffffffffff', '80d7fffffffffff', '80ebfffffffffff', - } + ] - assert out == expected + assert u.same_set(out, expected) out = h3.get_pentagons(5) - expected = { + expected = [ '85080003fffffff', '851c0003fffffff', '85300003fffffff', @@ -516,9 +509,9 @@ def test_get_pentagons(): '85c20003fffffff', '85d60003fffffff', '85ea0003fffffff', - } + ] - assert out == expected + assert u.same_set(out, expected) for i in range(16): assert len(h3.get_pentagons(i)) == 12 @@ -541,7 +534,7 @@ def test_get_res0_cells(): # subset pentagons = h3.get_pentagons(0) - assert pentagons < out + assert set(pentagons) < set(out) # all valid assert all(map(h3.is_valid_cell, out)) @@ -558,24 +551,7 @@ def test_get_res0_cells(): '8003fffffffffff', '8005fffffffffff', } - assert sub < out - - -def test_get_icosahedron_faces(): - h = '804dfffffffffff' - expected = {2, 3, 7, 8, 12} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = '80c1fffffffffff' - expected = {13} - out = h3.get_icosahedron_faces(h) - assert out == expected - - h = '80bbfffffffffff' - expected = {16, 15} - out = h3.get_icosahedron_faces(h) - assert out == expected + assert sub < set(out) def test_to_local_ij_error(): @@ -613,7 +589,7 @@ def test_from_local_ij_error(): for i, j in goodies } - assert out == nb + assert u.same_set(out, nb) def test_to_local_ij_self(): diff --git a/tests/test_h3.py b/tests/test_h3.py index 94a9a949..a7fc4150 100644 --- a/tests/test_h3.py +++ b/tests/test_h3.py @@ -3,6 +3,8 @@ import h3 +from . import util as u + def test_is_valid_cell(): assert h3.is_valid_cell('85283473fffffff') @@ -77,7 +79,7 @@ def test_grid_disk(): '8928308283bffff', } - assert out == expected + assert u.same_set(out, expected) def test_grid_disk2(): @@ -108,7 +110,7 @@ def test_grid_disk2(): '8928308280bffff', } - assert out == expected + assert u.same_set(out, expected) def test_grid_disk_pentagon(): @@ -126,7 +128,7 @@ def test_grid_disk_pentagon(): '821c37fffffffff', } - assert out == expected + assert u.same_set(out, expected) def test_grid_ring(): @@ -141,8 +143,11 @@ def test_grid_ring(): '8928308283bffff', } - assert out == expected - assert out == h3.grid_disk(h, 1) - h3.grid_disk(h, 0) + assert u.same_set(out, expected) + assert u.same_set( + out, + set(h3.grid_disk(h, 1)) - set(h3.grid_disk(h, 0)) + ) def test_grid_ring2(): @@ -164,8 +169,11 @@ def test_grid_ring2(): '89283082867ffff', } - assert out == expected - assert out == h3.grid_disk(h, 2) - h3.grid_disk(h, 1) + assert u.same_set(out, expected) + assert u.same_set( + out, + set(h3.grid_disk(h, 2)) - set(h3.grid_disk(h, 1)) + ) def test_grid_ring_pentagon(): @@ -180,7 +188,7 @@ def test_grid_ring_pentagon(): '821c37fffffffff', } - assert out == expected + assert u.same_set(out, expected) def test_compact_and_uncompact_cells(): @@ -202,12 +210,12 @@ def test_compact_and_uncompact_cells(): uncompact_cells = h3.uncompact_cells(compact_cells, 9) assert len(uncompact_cells) == 1253 - assert uncompact_cells == cells + assert u.same_set(uncompact_cells, cells) def test_compact_cells_and_uncompact_cells_nothing(): - assert h3.compact_cells([]) == set() - assert h3.uncompact_cells([], 9) == set() + assert h3.compact_cells([]) == [] + assert h3.uncompact_cells([], 9) == [] def test_uncompact_cells_error(): diff --git a/tests/test_length_area.py b/tests/test_length_area.py index 8851a4b4..1003f564 100644 --- a/tests/test_length_area.py +++ b/tests/test_length_area.py @@ -1,15 +1,7 @@ import h3 import pytest - -def approx2(a, b): - if len(a) != len(b): - return False - - return all( - x == pytest.approx(y) - for x, y in zip(a, b) - ) +from . import util as u def cell_perimiter1(h, unit='km'): @@ -65,7 +57,7 @@ def test_areas_at_00(): for r in range(16) ] - assert approx2(out, areas_km2) + assert u.approx2(out, areas_km2) areas_rads2 = [ 6.312389871006786335e-02, @@ -91,7 +83,7 @@ def test_areas_at_00(): for r in range(16) ] - assert approx2(out, areas_rads2) + assert u.approx2(out, areas_rads2) def test_bad_units(): diff --git a/tests/util.py b/tests/util.py new file mode 100644 index 00000000..f6d31776 --- /dev/null +++ b/tests/util.py @@ -0,0 +1,21 @@ +import pytest + + +def same_set(a, b): + """Test if two collections are the same if taken as sets""" + set_a = set(a) + set_b = set(b) + + assert len(a) == len(b) == len(set_a) == len(set_b) + + return set_a == set_b + + +def approx2(a, b): + if len(a) != len(b): + return False + + return all( + x == pytest.approx(y) + for x, y in zip(a, b) + )