diff --git a/.flake8 b/.flake8 deleted file mode 100644 index f77f556a..00000000 --- a/.flake8 +++ /dev/null @@ -1,20 +0,0 @@ -# https://lintlyci.github.io/Flake8Rules/ -[flake8] -max-line-length = 88 -include = - #W292 No newline at end of file - W292, -ignore = - # E251 unexpected spaces around keyword / parameter equals - E251, - # sometimes I just want to line up decimal points... - # E201 whitespace after '[' - E201, - # E241 multiple spaces after ',' - E241, - # E731 do not assign a lambda expression, use a def - E731, - # https://stackoverflow.com/questions/67942075/w504-line-break-after-binary-operator - W503,W504, - # E272 multiple spaces before keyword - E272 diff --git a/.github/workflows/coverage-lint-pr.yml b/.github/workflows/coverage-lint-pr.yml index eb689e30..1785d09d 100644 --- a/.github/workflows/coverage-lint-pr.yml +++ b/.github/workflows/coverage-lint-pr.yml @@ -23,13 +23,8 @@ jobs: pip install --upgrade pip setuptools wheel pip install .[test] - - name: Lint - run: flake8 src/h3 tests - - - name: Pylint - # As a test for visibility of API bindings, we want to ensure that pylint has no - # `import-error` warnings for h3 imports. - run: pylint --disable=all --enable=import-error tests/ + - name: Run Linting + uses: astral-sh/ruff-action@v1 - name: Coverage run: | diff --git a/.github/workflows/coverage-lint.yml b/.github/workflows/coverage-lint.yml index 72ef8ead..7dc1e3a7 100644 --- a/.github/workflows/coverage-lint.yml +++ b/.github/workflows/coverage-lint.yml @@ -23,13 +23,8 @@ jobs: pip install --upgrade pip setuptools wheel pip install .[test] - - name: Lint - run: flake8 src/h3 tests - - - name: Pylint - # As a test for visibility of API bindings, we want to ensure that pylint has no - # `import-error` warnings for h3 imports. - run: pylint --disable=all --enable=import-error tests/ + - name: Run Linting + uses: astral-sh/ruff-action@v1 - name: Coverage run: | diff --git a/docs/polygon_tutorial.ipynb b/docs/polygon_tutorial.ipynb index 7e0a1e93..ab8b3a88 100644 --- a/docs/polygon_tutorial.ipynb +++ b/docs/polygon_tutorial.ipynb @@ -34,41 +34,48 @@ "metadata": {}, "outputs": [], "source": [ - "import h3\n", - "\n", - "import geopandas\n", - "import geodatasets\n", "import contextily as cx\n", + "import geodatasets\n", + "import geopandas\n", "import matplotlib.pyplot as plt\n", "\n", + "import h3\n", + "\n", + "\n", "def plot_df(df, column=None, ax=None):\n", - " 'Plot based on the `geometry` column of a GeoPandas dataframe'\n", + " \"Plot based on the `geometry` column of a GeoPandas dataframe\"\n", " df = df.copy()\n", - " df = df.to_crs(epsg=3857) # web mercator\n", + " df = df.to_crs(epsg=3857) # web mercator\n", "\n", " if ax is None:\n", - " fig, ax = plt.subplots(figsize=(8,8))\n", + " fig, ax = plt.subplots(figsize=(8, 8))\n", " ax.get_xaxis().set_visible(False)\n", " ax.get_yaxis().set_visible(False)\n", - " \n", + "\n", " df.plot(\n", " ax=ax,\n", - " alpha=0.5, edgecolor='k',\n", - " column=column, categorical=True,\n", - " legend=True, legend_kwds={'loc': 'upper left'}, \n", + " alpha=0.5,\n", + " edgecolor='k',\n", + " column=column,\n", + " categorical=True,\n", + " legend=True,\n", + " legend_kwds={'loc': 'upper left'},\n", " )\n", " cx.add_basemap(ax, crs=df.crs, source=cx.providers.CartoDB.Positron)\n", "\n", + "\n", "def plot_shape(shape, ax=None):\n", " df = geopandas.GeoDataFrame({'geometry': [shape]}, crs='EPSG:4326')\n", " plot_df(df, ax=ax)\n", "\n", + "\n", "def plot_cells(cells, ax=None):\n", " shape = h3.cells_to_h3shape(cells)\n", " plot_shape(shape, ax=ax)\n", "\n", + "\n", "def plot_shape_and_cells(shape, res=9):\n", - " fig, axs = plt.subplots(1,2, figsize=(10,5), sharex=True, sharey=True)\n", + " fig, axs = plt.subplots(1, 2, figsize=(10, 5), sharex=True, sharey=True)\n", " plot_shape(shape, ax=axs[0])\n", " plot_cells(h3.h3shape_to_cells(shape, res), ax=axs[1])\n", " fig.tight_layout()" @@ -92,11 +99,7 @@ "metadata": {}, "outputs": [], "source": [ - "outer = [\n", - " (37.804, -122.412),\n", - " (37.778, -122.507),\n", - " (37.733, -122.501)\n", - "]\n", + "outer = [(37.804, -122.412), (37.778, -122.507), (37.733, -122.501)]\n", "\n", "poly = h3.LatLngPoly(outer)\n", "print(poly)\n", @@ -263,6 +266,7 @@ " def __geo_interface__(self):\n", " return self.d\n", "\n", + "\n", "geo = MockGeo(d)\n", "h3.geo_to_h3shape(geo)" ] @@ -429,7 +433,13 @@ "poly1 = h3.LatLngPoly([(37.804, -122.412), (37.778, -122.507), (37.733, -122.501)])\n", "poly2 = h3.LatLngPoly(\n", " [(37.803, -122.408), (37.736, -122.491), (37.738, -122.380), (37.787, -122.39)],\n", - " [(37.760, -122.441), (37.772, -122.427), (37.773, -122.404), (37.758, -122.401), (37.745, -122.428)]\n", + " [\n", + " (37.760, -122.441),\n", + " (37.772, -122.427),\n", + " (37.773, -122.404),\n", + " (37.758, -122.401),\n", + " (37.745, -122.428),\n", + " ],\n", ")\n", "mpoly = h3.LatLngMultiPoly(poly1, poly2)\n", "\n", diff --git a/makefile b/makefile index a838caa0..185536b1 100644 --- a/makefile +++ b/makefile @@ -40,8 +40,8 @@ test: ./env/bin/pytest lint: - ./env/bin/flake8 src/h3 tests - ./env/bin/pylint --disable=all --enable=import-error tests/ + ./env/bin/ruff check --fix + ./env/bin/ruff format lab: ./env/bin/pip install .[all] diff --git a/pyproject.toml b/pyproject.toml index 9e24b7d7..46e3f74e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,10 +46,10 @@ Changelog = 'https://package.readthedocs.io/en/latest/changelog.html' [project.optional-dependencies] numpy = ['numpy'] -test = ['pytest', 'pytest-cov', 'flake8', 'pylint', 'numpy'] +test = ['pytest', 'pytest-cov', 'ruff', 'numpy'] all = [ + 'h3[test]', 'jupyter-book', - 'flake8', 'sphinx>=7.3.3', # https://github.com/sphinx-doc/sphinx/issues/12290 'jupyterlab', 'jupyterlab-geojson', @@ -59,15 +59,51 @@ all = [ 'contextily', 'cartopy', 'geoviews', - 'numpy', - 'pytest', - 'pytest-cov', - 'pylint', ] [tool.pytest.ini_options] addopts = "--cov=h3 --cov=tests --cov-report=term-missing --durations=10" +[tool.ruff] +src = [ + "src", + "tests", +] + +lint.select = [ + "E", + "F", + "W", +] + +lint.extend-select = [ + "I", +] + +lint.ignore = [ + "E251", # unexpected spaces around keyword / parameter equals + "E272", # multiple spaces before keyword + # sometimes I just want to line up decimal points... + "E201", # whitespace after '[' + "E241", # multiple spaces after ',' + "E731", # do not assign a lambda expression, use a def + # Ignore when using formatter (https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules) + "E501", # Line-too-long; +] + +respect-gitignore = true + +[tool.ruff.format] +indent-style = "space" +quote-style = "single" + +[tool.ruff.lint.per-file-ignores] +# Do not enforce usage in init files +"__init__.py" = [ + "E402", + "F401", +] + [tool.coverage.run] omit = [ '*/h3/api/basic_int/__init__.py', diff --git a/src/h3/__init__.py b/src/h3/__init__.py index 4f7cb32f..fa21fae5 100644 --- a/src/h3/__init__.py +++ b/src/h3/__init__.py @@ -1,29 +1,24 @@ -# flake8: noqa - -from .api.basic_str import * -from ._version import __version__ - from ._cy import ( - UnknownH3ErrorCode, H3BaseException, - - H3GridNavigationError, - H3MemoryError, - H3ValueError, - - H3FailedError, - H3DomainError, - H3LatLngDomainError, - H3ResDomainError, H3CellInvalidError, H3DirEdgeInvalidError, - H3UndirEdgeInvalidError, - H3VertexInvalidError, - H3PentagonError, + H3DomainError, H3DuplicateInputError, - H3NotNeighborsError, - H3ResMismatchError, + H3FailedError, + H3GridNavigationError, + H3LatLngDomainError, H3MemoryAllocError, H3MemoryBoundsError, + H3MemoryError, + H3NotNeighborsError, H3OptionInvalidError, + H3PentagonError, + H3ResDomainError, + H3ResMismatchError, + H3UndirEdgeInvalidError, + H3ValueError, + H3VertexInvalidError, + UnknownH3ErrorCode, ) +from ._version import __version__ +from .api.basic_str import * # noqa diff --git a/src/h3/_cy/__init__.py b/src/h3/_cy/__init__.py index 804b6b0e..71456a96 100644 --- a/src/h3/_cy/__init__.py +++ b/src/h3/_cy/__init__.py @@ -1,5 +1,3 @@ -# flake8: noqa - """ This module should serve as the interface between the C/Cython code and the Python code. That is, it is an internal API. @@ -14,97 +12,86 @@ """ from .cells import ( - is_valid_cell, - is_pentagon, - get_base_cell_number, - get_resolution, - cell_to_parent, - grid_distance, - grid_disk, - grid_ring, - cell_to_children_size, - cell_to_children, + average_hexagon_area, + cell_area, + cell_to_center_child, cell_to_child_pos, + cell_to_children, + cell_to_children_size, + cell_to_local_ij, + cell_to_parent, child_pos_to_cell, compact_cells, - uncompact_cells, + get_base_cell_number, + get_icosahedron_faces, get_num_cells, - average_hexagon_area, - cell_area, - grid_path_cells, - is_res_class_iii, get_pentagons, get_res0_cells, - cell_to_center_child, - get_icosahedron_faces, - cell_to_local_ij, + get_resolution, + grid_disk, + grid_distance, + grid_path_cells, + grid_ring, + is_pentagon, + is_res_class_iii, + is_valid_cell, local_ij_to_cell, + uncompact_cells, ) - from .edges import ( are_neighbor_cells, + average_hexagon_edge_length, cells_to_directed_edge, - is_valid_directed_edge, - get_directed_edge_origin, - get_directed_edge_destination, directed_edge_to_cells, - origin_to_directed_edges, - average_hexagon_edge_length, edge_length, + get_directed_edge_destination, + get_directed_edge_origin, + is_valid_directed_edge, + origin_to_directed_edges, +) +from .error_system import ( + H3BaseException, + H3CellInvalidError, + H3DirEdgeInvalidError, + H3DomainError, + H3DuplicateInputError, + H3FailedError, + H3GridNavigationError, + H3LatLngDomainError, + H3MemoryAllocError, + H3MemoryBoundsError, + H3MemoryError, + H3NotNeighborsError, + H3OptionInvalidError, + H3PentagonError, + H3ResDomainError, + H3ResMismatchError, + H3UndirEdgeInvalidError, + H3ValueError, + H3VertexInvalidError, + UnknownH3ErrorCode, ) - from .latlng import ( - latlng_to_cell, - cell_to_latlng, - polygon_to_cells, - polygons_to_cells, cell_to_boundary, + cell_to_latlng, directed_edge_to_boundary, great_circle_distance, + latlng_to_cell, + polygon_to_cells, + polygons_to_cells, ) - -from .vertex import ( - cell_to_vertex, - cell_to_vertexes, - vertex_to_latlng, - is_valid_vertex, -) - -from .to_multipoly import ( - cells_to_multi_polygon +from .memory import ( + iter_to_mv, ) - +from .to_multipoly import cells_to_multi_polygon from .util import ( c_version, - str_to_int, int_to_str, + str_to_int, ) - -from .memory import ( - iter_to_mv, -) - -from .error_system import ( - UnknownH3ErrorCode, - H3BaseException, - - H3GridNavigationError, - H3MemoryError, - H3ValueError, - - H3FailedError, - H3DomainError, - H3LatLngDomainError, - H3ResDomainError, - H3CellInvalidError, - H3DirEdgeInvalidError, - H3UndirEdgeInvalidError, - H3VertexInvalidError, - H3PentagonError, - H3DuplicateInputError, - H3NotNeighborsError, - H3ResMismatchError, - H3MemoryAllocError, - H3MemoryBoundsError, - H3OptionInvalidError, +from .vertex import ( + cell_to_vertex, + cell_to_vertexes, + is_valid_vertex, + vertex_to_latlng, ) diff --git a/src/h3/_h3shape.py b/src/h3/_h3shape.py index 5c362951..80fe3585 100644 --- a/src/h3/_h3shape.py +++ b/src/h3/_h3shape.py @@ -5,10 +5,11 @@ class H3Shape(metaclass=ABCMeta): """ Abstract parent class of ``LatLngPoly`` and ``LatLngMultiPoly``. """ + @property @abstractmethod def __geo_interface__(self): - """ https://github.com/pytest-dev/pytest-cov/issues/428 """ + """https://github.com/pytest-dev/pytest-cov/issues/428""" class LatLngPoly(H3Shape): @@ -51,6 +52,7 @@ class LatLngPoly(H3Shape): ... ) """ + def __init__(self, outer, *holes): loops = [outer] + list(holes) for loop in loops: @@ -63,10 +65,7 @@ def __init__(self, outer, *holes): raise ValueError('LatLngPoly only accepts 2D points: lat/lng.') self.outer = tuple(_open_ring(outer)) - self.holes = tuple( - _open_ring(hole) - for hole in holes - ) + self.holes = tuple(_open_ring(hole) for hole in holes) def __repr__(self): return ''.format(self.loopcode) @@ -80,7 +79,7 @@ def __len__(self): @property def loopcode(self): - """ Short code for describing the length of the outer loop and each hole + """Short code for describing the length of the outer loop and each hole Example: ``[382/(18, 6, 6)]`` indicates an outer loop of 382 points, along with 3 holes with 18, 6, and 6 points, respectively. @@ -116,12 +115,13 @@ class LatLngMultiPoly(H3Shape): polys : list[LatLngPoly] List of lat/lng points describing the outer loop of the polygon """ + def __init__(self, *polys): self.polys = tuple(polys) for p in self.polys: if not isinstance(p, LatLngPoly): - raise ValueError('LatLngMultiPoly requires each input to be an LatLngPoly object, instead got: ' + str(p)) # noqa + raise ValueError('LatLngMultiPoly requires each input to be an LatLngPoly object, instead got: ' + str(p)) # fmt: skip def __repr__(self): out = [p.loopcode for p in self.polys] @@ -133,8 +133,7 @@ def __iter__(self): return iter(self.polys) def __len__(self): - """ Give the number of polygons in this multi-polygon. - """ + """Give the number of polygons in this multi-polygon.""" """ TODO: Pandas series or dataframe representation changes depending @@ -195,19 +194,13 @@ def __geo_interface__(self): def _mpoly_to_LL3(mpoly): - ll3 = tuple( - _polygon_to_LL2(poly) - for poly in mpoly - ) + ll3 = tuple(_polygon_to_LL2(poly) for poly in mpoly) return ll3 def _LL3_to_mpoly(ll3): - polys = [ - _LL2_to_polygon(ll2) - for ll2 in ll3 - ] + polys = [_LL2_to_polygon(ll2) for ll2 in ll3] mpoly = LatLngMultiPoly(*polys) @@ -216,10 +209,7 @@ def _LL3_to_mpoly(ll3): def _polygon_to_LL2(poly): ll2 = [poly.outer] + list(poly.holes) - ll2 = tuple( - _close_ring(_swap_latlng(ll1)) - for ll1 in ll2 - ) + ll2 = tuple(_close_ring(_swap_latlng(ll1)) for ll1 in ll2) return ll2 @@ -230,15 +220,9 @@ def _remove_z(ll1): def _LL2_to_polygon(ll2): - ll2 = [ - _remove_z(ll1) - for ll1 in ll2 - ] - - ll2 = [ - _swap_latlng(ll1) - for ll1 in ll2 - ] + ll2 = [_remove_z(ll1) for ll1 in ll2] + + ll2 = [_swap_latlng(ll1) for ll1 in ll2] h3poly = LatLngPoly(*ll2) return h3poly @@ -263,9 +247,7 @@ def _LL3_to_geojson_dict(ll3): def _swap_latlng(ll1): - ll1 = tuple( - (b, a) for a, b in ll1 - ) + ll1 = tuple((b, a) for a, b in ll1) return ll1 diff --git a/src/h3/api/__init__.py b/src/h3/api/__init__.py index 435b13a1..82c4d6fb 100644 --- a/src/h3/api/__init__.py +++ b/src/h3/api/__init__.py @@ -1,6 +1 @@ -# flake8: noqa - -from . import basic_int -from . import basic_str -from . import memview_int -from . import numpy_int +from . import basic_int, basic_str, memview_int, numpy_int diff --git a/src/h3/api/basic_int/__init__.py b/src/h3/api/basic_int/__init__.py index 60359662..93891bc1 100644 --- a/src/h3/api/basic_int/__init__.py +++ b/src/h3/api/basic_int/__init__.py @@ -3,17 +3,16 @@ from ... import _cy from ..._h3shape import ( H3Shape, - LatLngPoly, LatLngMultiPoly, + LatLngPoly, geo_to_h3shape, h3shape_to_geo, ) - from ._convert import ( - _in_scalar, - _out_scalar, _in_collection, + _in_scalar, _out_collection, + _out_scalar, ) @@ -1071,9 +1070,11 @@ def great_circle_distance(latlng1, latlng2, unit='km'): lat1, lng1 = latlng1 lat2, lng2 = latlng2 return _cy.great_circle_distance( - lat1, lng1, - lat2, lng2, - unit = unit + lat1, + lng1, + lat2, + lng2, + unit=unit, ) diff --git a/src/h3/api/numpy_int/_convert.py b/src/h3/api/numpy_int/_convert.py index 6b293cc9..f1be5c33 100644 --- a/src/h3/api/numpy_int/_convert.py +++ b/src/h3/api/numpy_int/_convert.py @@ -7,6 +7,7 @@ def _in_scalar(x): def _in_collection(x): import numpy as np + # array is copied only if dtype does not match # `list`s should work, but not `set`s of integers return np.asarray(x, dtype='uint64') diff --git a/tests/polyfill/test_h3.py b/tests/polyfill/test_h3.py index 8d9d9480..b9cfdce5 100644 --- a/tests/polyfill/test_h3.py +++ b/tests/polyfill/test_h3.py @@ -1,6 +1,7 @@ -import h3 import pytest +import h3 + from .. import util as u @@ -28,9 +29,7 @@ def latlng_closed(): def swap_latlng(ll1): - ll1 = tuple( - (b, a) for a, b in ll1 - ) + ll1 = tuple((b, a) for a, b in ll1) return ll1 @@ -43,10 +42,12 @@ def lnglat_closed(): def get_mocked(loop): - geo = MockGeoInterface({ - 'type': 'Polygon', - 'coordinates': [loop] - }) + geo = MockGeoInterface( + { + 'type': 'Polygon', + 'coordinates': [loop], + } + ) return geo @@ -82,8 +83,7 @@ def test_geo_interface(): assert ( poly.__geo_interface__['coordinates'] - == - mpoly.__geo_interface__['coordinates'][0] + == mpoly.__geo_interface__['coordinates'][0] ) @@ -91,11 +91,7 @@ def test_shape_repr(): poly = h3.LatLngPoly(sf_hole1) mpoly = h3.LatLngMultiPoly(poly) - assert ( - '' - == str(mpoly) - == repr(mpoly) - ) + assert '' == str(mpoly) == repr(mpoly) def test_polyfill(): @@ -125,23 +121,16 @@ def test_polyfill_with_hole(): foo = lambda x: set(h3.h3shape_to_cells(h3.LatLngPoly(x), 9)) - assert u.same_set( - out, - foo(sf_7x7) - foo(sf_hole1) - ) + assert u.same_set(out, foo(sf_7x7) - foo(sf_hole1)) def test_polyfill_with_two_holes(): - poly = h3.LatLngPoly(sf_7x7, sf_hole1, sf_hole2) out = h3.h3shape_to_cells(poly, 9) assert len(out) == 1172 foo = lambda x: set(h3.h3shape_to_cells(h3.LatLngPoly(x), 9)) - assert u.same_set( - out, - foo(sf_7x7) - (foo(sf_hole1) | foo(sf_hole2)) - ) + assert u.same_set(out, foo(sf_7x7) - (foo(sf_hole1) | foo(sf_hole2))) def test_polyfill_geo_json_compliant(): @@ -177,12 +166,14 @@ def test_geo_to_h3shape(): expected = { 'type': 'Polygon', - 'coordinates': (( - (-122.408, 37.813), - (-122.512, 37.707), - (-122.479, 37.815), - (-122.408, 37.813), - ),) + 'coordinates': ( + ( + (-122.408, 37.813), + (-122.512, 37.707), + (-122.479, 37.815), + (-122.408, 37.813), + ), + ), } for shape in shapes: @@ -192,12 +183,16 @@ def test_geo_to_h3shape(): multi_expected = { 'type': 'MultiPolygon', - 'coordinates': ((( - (-122.408, 37.813), - (-122.512, 37.707), - (-122.479, 37.815), - (-122.408, 37.813), - ),),) + 'coordinates': ( + ( + ( + (-122.408, 37.813), + (-122.512, 37.707), + (-122.479, 37.815), + (-122.408, 37.813), + ), + ), + ), } for mp in mpolys: @@ -360,8 +355,12 @@ def test_cells_to_h3shape_non_contiguous(): def test_cells_to_h3shape_hole(): # Six hexagons in a ring around a hole cells = [ - '892830828c7ffff', '892830828d7ffff', '8928308289bffff', - '89283082813ffff', '8928308288fffff', '89283082883ffff', + '892830828c7ffff', + '892830828d7ffff', + '8928308289bffff', + '89283082813ffff', + '8928308288fffff', + '89283082883ffff', ] mpoly = h3.cells_to_h3shape(cells, tight=False) @@ -386,7 +385,6 @@ def test_cells_to_h3shape_2grid_disk(): def test_multipoly_checks(): - with pytest.raises(ValueError): h3.LatLngMultiPoly('foo') @@ -400,7 +398,7 @@ def test_multipoly_checks(): def test_3d_geo(): loop = lnglat_open() - loop2d = [(lng, lat) for lng, lat in loop] + loop2d = [(lng, lat) for lng, lat in loop] loop3d = [(lng, lat, 0.0) for lng, lat in loop] geo2d = get_mocked(loop2d) @@ -418,10 +416,7 @@ def test_3d_geo(): def test_against_3d_polygons(): # LatLngPoly still expects just a lat/lng. it won't handle 3d coords - loop3d = [ - (lat, lng, 0.0) - for lat, lng in latlng_open() - ] + loop3d = [(lat, lng, 0.0) for lat, lng in latlng_open()] with pytest.raises(ValueError): h3.LatLngPoly(loop3d) diff --git a/tests/polyfill/test_polyfill.py b/tests/polyfill/test_polyfill.py index 1431b876..8c8ec855 100644 --- a/tests/polyfill/test_polyfill.py +++ b/tests/polyfill/test_polyfill.py @@ -1,42 +1,35 @@ -import h3 import pytest +import h3 from h3 import H3ResDomainError from .. import util as u def get_us_box_coords(): - # big center chunk of the US in lat/lng order outer = [ [42.68, -110.61], [32.17, -109.02], - [31.57, -94.26], - [42.94, -89.38], - [42.68, -110.61] + [31.57, -94.26], + [42.94, -89.38], + [42.68, -110.61], ] hole1 = [ [39.77, -105.07], [34.81, -104.72], - [34.77, -98.39], - [40.14, -96.72], - [39.77, -105.07] + [34.77, -98.39], + [40.14, -96.72], + [39.77, -105.07], ] - hole2 = [ - [41.37, -98.61], - [40.04, -91.80], - [42.32, -91.80], - [41.37, -98.61] - ] + hole2 = [[41.37, -98.61], [40.04, -91.80], [42.32, -91.80], [41.37, -98.61]] return outer, hole1, hole2 def test_h3shape_to_cells(): - # approximate lat/lngs for State of Maine maine = [ (45.137, -67.137), @@ -68,7 +61,7 @@ def test_h3shape_to_cells(): '832b1afffffffff', '832b1efffffffff', '832ba9fffffffff', - '832badfffffffff' + '832badfffffffff', } poly = h3.LatLngPoly(maine) @@ -93,12 +86,9 @@ def test_h3shape_to_cells2(): def test_h3shape_to_cells_holes(): - outer, hole1, hole2 = get_us_box_coords() - assert 7063 == len( - h3.h3shape_to_cells(h3.LatLngPoly(outer), 5) - ) + assert 7063 == len(h3.h3shape_to_cells(h3.LatLngPoly(outer), 5)) for res in 1, 2, 3, 4, 5: cells_all = h3.h3shape_to_cells(h3.LatLngPoly(outer), res) @@ -109,10 +99,7 @@ def test_h3shape_to_cells_holes(): cells_2 = set(h3.h3shape_to_cells(h3.LatLngPoly(hole2), res)) assert len(cells_all) == len(cells_holes) + len(cells_1) + len(cells_2) - assert u.same_set( - 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(): diff --git a/tests/polyfill/test_polyfill_ordering.py b/tests/polyfill/test_polyfill_ordering.py index e0e43d8f..501d9b0a 100644 --- a/tests/polyfill/test_polyfill_ordering.py +++ b/tests/polyfill/test_polyfill_ordering.py @@ -1,4 +1,4 @@ -""" Test that `h3shape_to_cells` can take in polygon inputs +"""Test that `h3shape_to_cells` can take in polygon inputs where the LinearRings may or may not follow the right hand rule, and they may or may not be closed loops (where the last element is equal to the first). @@ -8,9 +8,10 @@ may follow a different subset of rules. """ -import h3 import itertools +import h3 + def reverse(loop): return list(reversed(loop)) @@ -21,7 +22,7 @@ def drop_last(loop): def toggle_map(func, poly): - """ Return all permutations of `func` being applied or not + """Return all permutations of `func` being applied or not to each element of `poly` returns iterable of length 2**len(poly) @@ -50,29 +51,28 @@ def input_permutations(geo, res=5): def get_us_box_coords(): - # big center chunk of the US in lat/lng order outer = [ [42.68, -110.61], [32.17, -109.02], - [31.57, -94.26], - [42.94, -89.38], - [42.68, -110.61] + [31.57, -94.26], + [42.94, -89.38], + [42.68, -110.61], ] hole1 = [ [39.77, -105.07], [34.81, -104.72], - [34.77, -98.39], - [40.14, -96.72], - [39.77, -105.07] + [34.77, -98.39], + [40.14, -96.72], + [39.77, -105.07], ] hole2 = [ [41.37, -98.61], [40.04, -91.80], [42.32, -91.80], - [41.37, -98.61] + [41.37, -98.61], ] return outer, hole1, hole2 diff --git a/tests/polyfill/test_polygon_class.py b/tests/polyfill/test_polygon_class.py index 3996d302..cba7d3ec 100644 --- a/tests/polyfill/test_polygon_class.py +++ b/tests/polyfill/test_polygon_class.py @@ -1,6 +1,7 @@ -import h3 import pytest +import h3 + def test_repr(): a = '8928308280fffff' diff --git a/tests/polyfill/test_to_multipoly.py b/tests/polyfill/test_to_multipoly.py index 61f77f63..7c2008e7 100644 --- a/tests/polyfill/test_to_multipoly.py +++ b/tests/polyfill/test_to_multipoly.py @@ -1,6 +1,5 @@ import h3 - from .. import util as u @@ -37,13 +36,7 @@ def test_2_polys(): mpoly = h3.cells_to_h3shape(cells) - out = [ - set(h3.h3shape_to_cells(poly, 9)) - for poly in mpoly - ] + out = [set(h3.h3shape_to_cells(poly, 9)) for poly in mpoly] - assert u.same_set( - 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/test_basic_int.py b/tests/test_apis/test_basic_int.py index a567b3de..75c91b76 100644 --- a/tests/test_apis/test_basic_int.py +++ b/tests/test_apis/test_basic_int.py @@ -1,6 +1,5 @@ import h3.api.basic_int as h3 - from .. import util as u @@ -9,7 +8,7 @@ def test_int_output(): lng = -122.418307270836 assert h3.latlng_to_cell(lat, lng, 9) == 617700169958293503 - assert h3.latlng_to_cell(lat, lng, 9) == 0x8928308280fffff + assert h3.latlng_to_cell(lat, lng, 9) == 0x8928308280fffff # fmt: skip def test_grid_disk(): diff --git a/tests/test_apis/test_basic_str.py b/tests/test_apis/test_basic_str.py index fccc164f..fdc38bfa 100644 --- a/tests/test_apis/test_basic_str.py +++ b/tests/test_apis/test_basic_str.py @@ -1,6 +1,5 @@ import h3.api.basic_str as h3 - from .. import util as u @@ -17,7 +16,7 @@ def test5(): '89283082807ffff', '8928308280bffff', '8928308280fffff', - '89283082803ffff' + '89283082803ffff', ] out = h3.grid_disk('8928308280fffff', 1) @@ -25,7 +24,6 @@ def test5(): def test_string_subtypes(): - class my_str(str): pass @@ -36,7 +34,7 @@ class my_str(str): '89283082807ffff', '8928308280bffff', '8928308280fffff', - '89283082803ffff' + '89283082803ffff', ] out = h3.grid_disk(my_str('8928308280fffff'), 1) diff --git a/tests/test_apis/test_collection_inputs.py b/tests/test_apis/test_collection_inputs.py index 5f826a14..0794dd7a 100644 --- a/tests/test_apis/test_collection_inputs.py +++ b/tests/test_apis/test_collection_inputs.py @@ -1,9 +1,10 @@ import numpy as np # only run this test suite if numpy is installed import pytest + from h3.api import ( basic_int, - numpy_int, memview_int, + numpy_int, ) # todo: check when a copy is made, and when it isn't @@ -62,15 +63,18 @@ def test_list(): def test_np_array(): - ints = np.array([ - 619056821839331327, - 619056821839593471, - 619056821839855615, - 619056821840117759, - 619056821840379903, - 619056821840642047, - 619056821840904191, - ], dtype='uint64') + ints = np.array( + [ + 619056821839331327, + 619056821839593471, + 619056821839855615, + 619056821840117759, + 619056821840379903, + 619056821840642047, + 619056821840904191, + ], + dtype='uint64', + ) h = 614553222213795839 @@ -111,17 +115,18 @@ def test_list_to_array(): def test_iterator(): - def foo(): - ints = iter([ - 619056821839331327, - 619056821839593471, - 619056821839855615, - 619056821840117759, - 619056821840379903, - 619056821840642047, - 619056821840904191, - ]) + ints = iter( + [ + 619056821839331327, + 619056821839593471, + 619056821839855615, + 619056821840117759, + 619056821840379903, + 619056821840642047, + 619056821840904191, + ] + ) return ints diff --git a/tests/test_apis/test_numpy_int.py b/tests/test_apis/test_numpy_int.py index c341b555..8a02d65f 100644 --- a/tests/test_apis/test_numpy_int.py +++ b/tests/test_apis/test_numpy_int.py @@ -1,6 +1,7 @@ -import h3.api.numpy_int as h3 import numpy as np # only run this test suite if numpy is installed +import h3.api.numpy_int as h3 + from .. import util as u diff --git a/tests/test_cells_and_edges.py b/tests/test_cells_and_edges.py index d23ff4d6..30ddac2e 100644 --- a/tests/test_cells_and_edges.py +++ b/tests/test_cells_and_edges.py @@ -1,16 +1,15 @@ -import h3 import pytest +import h3 from h3 import ( + H3CellInvalidError, + H3DomainError, H3FailedError, + H3NotNeighborsError, H3ResDomainError, - H3DomainError, H3ResMismatchError, - H3CellInvalidError, - H3NotNeighborsError, ) - from . import util as u @@ -58,7 +57,7 @@ def test5(): '89283082807ffff', '8928308280bffff', '8928308280fffff', - '89283082803ffff' + '89283082803ffff', ] out = h3.grid_disk('8928308280fffff', 1) @@ -78,7 +77,7 @@ def test7(): '8928308280bffff', '8928308283bffff', '89283082873ffff', - '89283082877ffff' + '89283082877ffff', ] out = h3.grid_ring('8928308280fffff', 1) @@ -152,7 +151,7 @@ def test_children(): '8a28308280dffff', '8a28308280e7fff', '8a28308280effff', - '8a28308280f7fff' + '8a28308280f7fff', ] out = h3.cell_to_children(h, 10) assert u.same_set(out, expected) @@ -195,7 +194,7 @@ def test_distance(): def test_distance_error(): - """ Two valid cells, but they are too far apart compute the distance + """Two valid cells, but they are too far apart compute the distance todo: make sure this raises a E_TOO_FAR error (when we add it in the future) """ @@ -208,34 +207,36 @@ def test_distance_error(): def get_maine_cells(): # lat/lngs for State of Maine - poly = h3.LatLngPoly([ - (45.137451890638886, -67.13734351262877), - (44.8097, -66.96466), - (44.3252, -68.03252), - (43.98, -69.06), - (43.68405, -70.11617), - (43.090083319667144, -70.64573401557249), - (43.08003225358635, -70.75102474636725), - (43.21973948828747, -70.79761105007827), - (43.36789581966826, -70.98176001655037), - (43.46633942318431, -70.94416541205806), - (45.3052400000002, -71.08482), - (45.46022288673396, -70.6600225491012), - (45.914794623389355, -70.30495378282376), - (46.69317088478567, -70.00014034695016), - (47.44777598732787, -69.23708614772835), - (47.184794623394396, -68.90478084987546), - (47.35462921812177, -68.23430497910454), - (47.066248887716995, -67.79035274928509), - (45.702585354182816, -67.79141211614706), - (45.137451890638886, -67.13734351262877) - ]) + poly = h3.LatLngPoly( + [ + (45.137451890638886, -67.13734351262877), + (44.8097, -66.96466), + (44.3252, -68.03252), + (43.98, -69.06), + (43.68405, -70.11617), + (43.090083319667144, -70.64573401557249), + (43.08003225358635, -70.75102474636725), + (43.21973948828747, -70.79761105007827), + (43.36789581966826, -70.98176001655037), + (43.46633942318431, -70.94416541205806), + (45.3052400000002, -71.08482), + (45.46022288673396, -70.6600225491012), + (45.914794623389355, -70.30495378282376), + (46.69317088478567, -70.00014034695016), + (47.44777598732787, -69.23708614772835), + (47.184794623394396, -68.90478084987546), + (47.35462921812177, -68.23430497910454), + (47.066248887716995, -67.79035274928509), + (45.702585354182816, -67.79141211614706), + (45.137451890638886, -67.13734351262877), + ] + ) res = 5 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'] # fmt: skip return cells_uncomp, cells_comp, res @@ -262,15 +263,13 @@ def test_get_num_cells(): 15: 569707381193162, } - out = { - k: h3.get_num_cells(k) - for k in expected - } + out = {k: h3.get_num_cells(k) for k in expected} assert expected == out def test_average_hexagon_area(): + # fmt: off expected_in_km2 = { 0: 4357449.416078381, 1: 609788.441794133, @@ -278,11 +277,9 @@ def test_average_hexagon_area(): 9: 0.105332513, 15: 8.95311e-07, } + # fmt: on - out = { - k: h3.average_hexagon_area(k, unit='km^2') - for k in expected_in_km2 - } + out = {k: h3.average_hexagon_area(k, unit='km^2') for k in expected_in_km2} assert out == pytest.approx(expected_in_km2) @@ -297,8 +294,7 @@ def test_average_hexagon_edge_length(): } out = { - res: h3.average_hexagon_edge_length(res, unit='km') - for res in expected_in_km + res: h3.average_hexagon_edge_length(res, unit='km') for res in expected_in_km } assert out == pytest.approx(expected_in_km) @@ -326,10 +322,7 @@ def test_edge(): def test_origin_to_directed_edges(): h = '8928308280fffff' edges = h3.origin_to_directed_edges(h) - destinations = { - h3.get_directed_edge_destination(e) - for e in edges - } + destinations = {h3.get_directed_edge_destination(e) for e in edges} neighbors = h3.grid_ring(h, 1) assert u.same_set(neighbors, destinations) @@ -342,7 +335,7 @@ def test_edge_boundary(): expected = ( (37.77688044840226, -122.41612835779266), - (37.778385004930925, -122.41738797617619) + (37.778385004930925, -122.41738797617619), ) out = h3.directed_edge_to_boundary(e) @@ -436,7 +429,7 @@ def test_line(): expected = [ '8928308280fffff', '89283082873ffff', - '8928308287bffff' + '8928308287bffff', ] assert out == expected @@ -540,10 +533,7 @@ def test_get_res0_cells(): assert all(map(h3.is_valid_cell, out)) # resolution - assert all(map( - lambda h: h3.get_resolution(h) == 0, - out - )) + assert all(map(lambda h: h3.get_resolution(h) == 0, out)) # verify a few concrete cells sub = { @@ -584,10 +574,7 @@ def test_from_local_ij_error(): nb = h3.grid_ring(h, k=1) goodies = {h3.cell_to_local_ij(h, p) for p in nb} - out = { - h3.local_ij_to_cell(h, i, j) - for i, j in goodies - } + out = {h3.local_ij_to_cell(h, i, j) for i, j in goodies} assert u.same_set(out, nb) diff --git a/tests/test_error_codes.py b/tests/test_error_codes.py index 9961178d..2df00e5d 100644 --- a/tests/test_error_codes.py +++ b/tests/test_error_codes.py @@ -8,11 +8,9 @@ h3_exceptions = { # h3.UnknownH3ErrorCode h3.H3BaseException: None, - h3.H3GridNavigationError: None, h3.H3MemoryError: None, h3.H3ValueError: None, - h3.H3FailedError: 1, h3.H3DomainError: 2, h3.H3LatLngDomainError: 3, diff --git a/tests/test_h3.py b/tests/test_h3.py index 760c3fab..1528637b 100644 --- a/tests/test_h3.py +++ b/tests/test_h3.py @@ -148,10 +148,7 @@ def test_grid_ring(): } assert u.same_set(out, expected) - assert u.same_set( - out, - set(h3.grid_disk(h, 1)) - set(h3.grid_disk(h, 0)) - ) + assert u.same_set(out, set(h3.grid_disk(h, 1)) - set(h3.grid_disk(h, 0))) def test_grid_ring2(): @@ -174,10 +171,7 @@ def test_grid_ring2(): } assert u.same_set(out, expected) - assert u.same_set( - out, - set(h3.grid_disk(h, 2)) - set(h3.grid_disk(h, 1)) - ) + assert u.same_set(out, set(h3.grid_disk(h, 2)) - set(h3.grid_disk(h, 1))) def test_grid_ring_pentagon(): @@ -328,14 +322,10 @@ def test_directed_edge_to_cells(): def test_origin_to_directed_edges(): - h3_uni_edges = h3.origin_to_directed_edges( - '8928308280fffff' - ) + h3_uni_edges = h3.origin_to_directed_edges('8928308280fffff') assert len(h3_uni_edges) == 6 - h3_uni_edge_pentagon = h3.origin_to_directed_edges( - '821c07fffffffff' - ) + h3_uni_edge_pentagon = h3.origin_to_directed_edges('821c07fffffffff') assert len(h3_uni_edge_pentagon) == 5 @@ -481,10 +471,7 @@ def test_cell_to_children_size2(): for r in range(16): total_cells = 120 * (7**r) + 2 - assert total_cells == sum( - h3.cell_to_children_size(h, r) - for h in cells - ) + assert total_cells == sum(h3.cell_to_children_size(h, r) for h in cells) def test_child_pos3(): diff --git a/tests/test_length_area.py b/tests/test_length_area.py index 1003f564..ce1e4509 100644 --- a/tests/test_length_area.py +++ b/tests/test_length_area.py @@ -1,16 +1,14 @@ -import h3 import pytest +import h3 + from . import util as u def cell_perimiter1(h, unit='km'): edges = h3.origin_to_directed_edges(h) - dists = [ - h3.edge_length(e, unit=unit) - for e in edges - ] + dists = [h3.edge_length(e, unit=unit) for e in edges] assert all(d > 0 for d in dists) @@ -23,8 +21,7 @@ def cell_perimiter2(h, unit='km'): verts += (verts[0],) dists = [ - h3.great_circle_distance(verts[i], verts[i + 1], unit=unit) - for i in range(N) + h3.great_circle_distance(verts[i], verts[i + 1], unit=unit) for i in range(N) ] assert all(d > 0 for d in dists) @@ -33,6 +30,7 @@ def cell_perimiter2(h, unit='km'): def test_areas_at_00(): + # fmt: off areas_km2 = [ 2.562182162955495529e+06, 4.476842018179409206e+05, @@ -51,11 +49,9 @@ def test_areas_at_00(): 4.664070326136773890e-06, 6.662957615868890711e-07, ] + # fmt: on - out = [ - h3.cell_area(h3.latlng_to_cell(0, 0, r), unit='km^2') - for r in range(16) - ] + out = [h3.cell_area(h3.latlng_to_cell(0, 0, r), unit='km^2') for r in range(16)] assert u.approx2(out, areas_km2) @@ -78,10 +74,7 @@ def test_areas_at_00(): 1.641537700693487648e-14, ] - out = [ - h3.cell_area(h3.latlng_to_cell(0, 0, r), unit='rads^2') - for r in range(16) - ] + out = [h3.cell_area(h3.latlng_to_cell(0, 0, r), unit='rads^2') for r in range(16)] assert u.approx2(out, areas_rads2) diff --git a/tests/util.py b/tests/util.py index f6d31776..b82100c0 100644 --- a/tests/util.py +++ b/tests/util.py @@ -15,7 +15,4 @@ def approx2(a, b): if len(a) != len(b): return False - return all( - x == pytest.approx(y) - for x, y in zip(a, b) - ) + return all(x == pytest.approx(y) for x, y in zip(a, b))