From 322fe2e4cc8be8d967c1a1a4c98a352d49f99cf8 Mon Sep 17 00:00:00 2001 From: Jeroen Craps Date: Sun, 1 Aug 2021 13:22:25 +0200 Subject: [PATCH 01/59] Added inver haversine functionality to the module --- README.md | 24 +++++++++++++ haversine/__init__.py | 2 +- haversine/haversine.py | 62 ++++++++++++++++++++++++++------- tests/test_inverse_haversine.py | 47 +++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 13 deletions(-) create mode 100755 tests/test_inverse_haversine.py diff --git a/README.md b/README.md index 1fe86f9..62cc59e 100755 --- a/README.md +++ b/README.md @@ -47,6 +47,30 @@ outputs , , ) ``` +### Inverse Haversine Formula +Calculates a point from a given vector (distance and direction) and start point. +Currently explicitly supports both cardinal (north, east, south, west) and intercardinal (northeast, southeast, southwest, northwest) directions. +But also allows for explicit angles expressed in Radians. + +## Example: Finding arbitary point from Paris +```python +from haversine import inverse_haversine, Direction +from math import pi +paris = (48.8567, 2.3508) # (lat, lon) +# Finding 32 km west of Paris +inverse_haversine(paris, 32, Direction.WEST) +# returns tuple (49.1444, 2.3508) +# Finding 32 km southwest of Paris +inverse_haversine(paris, 32, pi * 1.25) +# returns tuple (48.5377, 1.8705) +# Finding 50 miles north of Paris +inverse_haversine(paris, 50, Direction.NORTH, unit=Unit.MILES) +# returns tuple (49.5803, 2.3508) +# Finding 10 nautical miles south of Paris +inverse_haversine(paris, 10, Direction.SOUTH, unit=Unit.NAUTICAL_MILES) +# returns tuple (48.6901, 2.3508) +``` + ### Performance optimisation for distances between all points in two vectors You will need to add [numpy](https://pypi.org/project/numpy/) in order to gain performance with vectors. diff --git a/haversine/__init__.py b/haversine/__init__.py index 3cf1d36..806fe82 100755 --- a/haversine/__init__.py +++ b/haversine/__init__.py @@ -1 +1 @@ -from .haversine import Unit, haversine, haversine_vector +from .haversine import Unit, haversine, haversine_vector, Direction, inverse_haversine diff --git a/haversine/haversine.py b/haversine/haversine.py index 2be6562..3407ee7 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -1,5 +1,6 @@ -from math import radians, cos, sin, asin, sqrt +from math import radians, cos, sin, asin, sqrt, degrees, pi, atan2 from enum import Enum +from typing import Union # mean earth radius - https://en.wikipedia.org/wiki/Earth_radius#Mean_radius @@ -21,18 +22,40 @@ class Unit(Enum): INCHES = 'in' +class Direction(Enum): + """ + Enumeration of supported directions. + The full list can be checked by iterating over the class; e.g. + the expression `tuple(Direction)`. + Angles expressed in radians. + """ + + NORTH = 0 + NORTHEAST = pi * 0.25 + EAST = pi * 0.5 + SOUTHEAST = pi * 0.75 + SOUTH = pi + SOUTHWEST = pi * 1.25 + WEST = pi * 1.5 + NORTHWEST = pi * 1.75 + + # Unit values taken from http://www.unitconversion.org/unit_converter/length.html -_CONVERSIONS = {Unit.KILOMETERS: 1.0, - Unit.METERS: 1000.0, - Unit.MILES: 0.621371192, - Unit.NAUTICAL_MILES: 0.539956803, - Unit.FEET: 3280.839895013, - Unit.INCHES: 39370.078740158} +_CONVERSIONS = { + Unit.KILOMETERS: 1.0, + Unit.METERS: 1000.0, + Unit.MILES: 0.621371192, + Unit.NAUTICAL_MILES: 0.539956803, + Unit.FEET: 3280.839895013, + Unit.INCHES: 39370.078740158 +} + def get_avg_earth_radius(unit): unit = Unit(unit) return _AVG_EARTH_RADIUS_KM * _CONVERSIONS[unit] + def haversine(point1, point2, unit=Unit.KILOMETERS): """ Calculate the great-circle distance between two points on the Earth surface. @@ -118,11 +141,11 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): # If in combination mode, turn coordinates of array1 into column vectors for broadcasting if comb: - lat1 = numpy.expand_dims(lat1,axis=0) - lng1 = numpy.expand_dims(lng1,axis=0) - lat2 = numpy.expand_dims(lat2,axis=1) - lng2 = numpy.expand_dims(lng2,axis=1) - + lat1 = numpy.expand_dims(lat1, axis=0) + lng1 = numpy.expand_dims(lng1, axis=0) + lat2 = numpy.expand_dims(lat2, axis=1) + lng2 = numpy.expand_dims(lng2, axis=1) + # calculate haversine lat = lat2 - lat1 lng = lng2 - lng1 @@ -130,3 +153,18 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): + numpy.cos(lat1) * numpy.cos(lat2) * numpy.sin(lng * 0.5) ** 2) return 2 * get_avg_earth_radius(unit) * numpy.arcsin(numpy.sqrt(d)) + + +def inverse_haversine(point, distance, direction: Union[Direction, float], unit=Unit.KILOMETERS): + + lat, lng = point + lat, lng = map(radians, (lat, lng)) + d = distance + r = get_avg_earth_radius(unit) + brng = direction.value if isinstance(direction, Direction) else direction + + return_lat = asin(sin(lat) * cos(d / r) + cos(lat) * sin(d / r) * cos(brng)) + return_lng = lng + atan2(sin(brng) * sin(d / r) * cos(lat), cos(d / r) - sin(lat) * sin(return_lat)) + + return_lat, return_lng = map(degrees, (return_lat, return_lng)) + return return_lat, return_lng diff --git a/tests/test_inverse_haversine.py b/tests/test_inverse_haversine.py new file mode 100755 index 0000000..905a0bc --- /dev/null +++ b/tests/test_inverse_haversine.py @@ -0,0 +1,47 @@ +from haversine import inverse_haversine, haversine, Unit, Direction +from numpy import isclose +from math import pi +import pytest + +LYON = (45.7597, 4.8422) +PARIS = (48.8567, 2.3508) +LONDON = (51.509865, -0.118092) +NEW_YORK = (40.7033962, -74.2351462) + + +@pytest.mark.parametrize( + "point, dir, dist, result", + [ + (PARIS, Direction.NORTH, 32, (49.144444, 2.3508)), + (PARIS, 0, 32, (49.144444, 2.3508)), + (LONDON, Direction.WEST, 50, (51.507778, -0.840556)), + (LONDON, pi * 1.5, 50, (51.507778, -0.840556)), + (NEW_YORK, Direction.SOUTH, 15, (40.568611, -74.235278)), + (NEW_YORK, Direction.NORTHWEST, 50, (41.020556, -74.656667)), + (NEW_YORK, pi * 1.25, 50, (40.384722, -74.6525)), + ], +) +def test_inverse_kilometers(point, dir, dist, result): + assert isclose(inverse_haversine(point, dist, dir), result, rtol=1e-5).all() + + +@pytest.mark.parametrize( + "point, direction, distance, unit", + [ + (PARIS, Direction.NORTH, 10, Unit.KILOMETERS), + (LONDON, Direction.WEST, 32, Unit.MILES), + (LYON, Direction.NORTHEAST, 45_000, Unit.METERS), + (NEW_YORK, Direction.SOUTH, 15, Unit.NAUTICAL_MILES), + ], +) +def test_back_and_forth(point, direction, distance, unit): + new_point = inverse_haversine(point, distance, direction, unit) + assert isclose(haversine(new_point, point, unit), distance, rtol=1e-10) + + +def test_inverse_miles(): + assert isclose(inverse_haversine(PARIS, 50, Direction.NORTH, unit=Unit.MILES), (49.5803579218996, 2.3508), rtol=1e-5).all() + + +def test_nautical_inverse_miles(): + assert isclose(inverse_haversine(PARIS, 10, Direction.SOUTH, unit=Unit.NAUTICAL_MILES), (48.69014586638915, 2.3508), rtol=1e-5).all() From 54377a94785c0f5f098c1f98eaaa917f984bcafb Mon Sep 17 00:00:00 2001 From: Jeroen Craps Date: Sun, 1 Aug 2021 13:22:25 +0200 Subject: [PATCH 02/59] Added inver haversine functionality to the module --- README.md | 24 +++++++++++++ haversine/__init__.py | 2 +- haversine/haversine.py | 62 ++++++++++++++++++++++++++------- tests/test_inverse_haversine.py | 47 +++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 13 deletions(-) create mode 100755 tests/test_inverse_haversine.py diff --git a/README.md b/README.md index 1fe86f9..62cc59e 100755 --- a/README.md +++ b/README.md @@ -47,6 +47,30 @@ outputs , , ) ``` +### Inverse Haversine Formula +Calculates a point from a given vector (distance and direction) and start point. +Currently explicitly supports both cardinal (north, east, south, west) and intercardinal (northeast, southeast, southwest, northwest) directions. +But also allows for explicit angles expressed in Radians. + +## Example: Finding arbitary point from Paris +```python +from haversine import inverse_haversine, Direction +from math import pi +paris = (48.8567, 2.3508) # (lat, lon) +# Finding 32 km west of Paris +inverse_haversine(paris, 32, Direction.WEST) +# returns tuple (49.1444, 2.3508) +# Finding 32 km southwest of Paris +inverse_haversine(paris, 32, pi * 1.25) +# returns tuple (48.5377, 1.8705) +# Finding 50 miles north of Paris +inverse_haversine(paris, 50, Direction.NORTH, unit=Unit.MILES) +# returns tuple (49.5803, 2.3508) +# Finding 10 nautical miles south of Paris +inverse_haversine(paris, 10, Direction.SOUTH, unit=Unit.NAUTICAL_MILES) +# returns tuple (48.6901, 2.3508) +``` + ### Performance optimisation for distances between all points in two vectors You will need to add [numpy](https://pypi.org/project/numpy/) in order to gain performance with vectors. diff --git a/haversine/__init__.py b/haversine/__init__.py index 3cf1d36..806fe82 100755 --- a/haversine/__init__.py +++ b/haversine/__init__.py @@ -1 +1 @@ -from .haversine import Unit, haversine, haversine_vector +from .haversine import Unit, haversine, haversine_vector, Direction, inverse_haversine diff --git a/haversine/haversine.py b/haversine/haversine.py index 2be6562..3407ee7 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -1,5 +1,6 @@ -from math import radians, cos, sin, asin, sqrt +from math import radians, cos, sin, asin, sqrt, degrees, pi, atan2 from enum import Enum +from typing import Union # mean earth radius - https://en.wikipedia.org/wiki/Earth_radius#Mean_radius @@ -21,18 +22,40 @@ class Unit(Enum): INCHES = 'in' +class Direction(Enum): + """ + Enumeration of supported directions. + The full list can be checked by iterating over the class; e.g. + the expression `tuple(Direction)`. + Angles expressed in radians. + """ + + NORTH = 0 + NORTHEAST = pi * 0.25 + EAST = pi * 0.5 + SOUTHEAST = pi * 0.75 + SOUTH = pi + SOUTHWEST = pi * 1.25 + WEST = pi * 1.5 + NORTHWEST = pi * 1.75 + + # Unit values taken from http://www.unitconversion.org/unit_converter/length.html -_CONVERSIONS = {Unit.KILOMETERS: 1.0, - Unit.METERS: 1000.0, - Unit.MILES: 0.621371192, - Unit.NAUTICAL_MILES: 0.539956803, - Unit.FEET: 3280.839895013, - Unit.INCHES: 39370.078740158} +_CONVERSIONS = { + Unit.KILOMETERS: 1.0, + Unit.METERS: 1000.0, + Unit.MILES: 0.621371192, + Unit.NAUTICAL_MILES: 0.539956803, + Unit.FEET: 3280.839895013, + Unit.INCHES: 39370.078740158 +} + def get_avg_earth_radius(unit): unit = Unit(unit) return _AVG_EARTH_RADIUS_KM * _CONVERSIONS[unit] + def haversine(point1, point2, unit=Unit.KILOMETERS): """ Calculate the great-circle distance between two points on the Earth surface. @@ -118,11 +141,11 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): # If in combination mode, turn coordinates of array1 into column vectors for broadcasting if comb: - lat1 = numpy.expand_dims(lat1,axis=0) - lng1 = numpy.expand_dims(lng1,axis=0) - lat2 = numpy.expand_dims(lat2,axis=1) - lng2 = numpy.expand_dims(lng2,axis=1) - + lat1 = numpy.expand_dims(lat1, axis=0) + lng1 = numpy.expand_dims(lng1, axis=0) + lat2 = numpy.expand_dims(lat2, axis=1) + lng2 = numpy.expand_dims(lng2, axis=1) + # calculate haversine lat = lat2 - lat1 lng = lng2 - lng1 @@ -130,3 +153,18 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): + numpy.cos(lat1) * numpy.cos(lat2) * numpy.sin(lng * 0.5) ** 2) return 2 * get_avg_earth_radius(unit) * numpy.arcsin(numpy.sqrt(d)) + + +def inverse_haversine(point, distance, direction: Union[Direction, float], unit=Unit.KILOMETERS): + + lat, lng = point + lat, lng = map(radians, (lat, lng)) + d = distance + r = get_avg_earth_radius(unit) + brng = direction.value if isinstance(direction, Direction) else direction + + return_lat = asin(sin(lat) * cos(d / r) + cos(lat) * sin(d / r) * cos(brng)) + return_lng = lng + atan2(sin(brng) * sin(d / r) * cos(lat), cos(d / r) - sin(lat) * sin(return_lat)) + + return_lat, return_lng = map(degrees, (return_lat, return_lng)) + return return_lat, return_lng diff --git a/tests/test_inverse_haversine.py b/tests/test_inverse_haversine.py new file mode 100755 index 0000000..905a0bc --- /dev/null +++ b/tests/test_inverse_haversine.py @@ -0,0 +1,47 @@ +from haversine import inverse_haversine, haversine, Unit, Direction +from numpy import isclose +from math import pi +import pytest + +LYON = (45.7597, 4.8422) +PARIS = (48.8567, 2.3508) +LONDON = (51.509865, -0.118092) +NEW_YORK = (40.7033962, -74.2351462) + + +@pytest.mark.parametrize( + "point, dir, dist, result", + [ + (PARIS, Direction.NORTH, 32, (49.144444, 2.3508)), + (PARIS, 0, 32, (49.144444, 2.3508)), + (LONDON, Direction.WEST, 50, (51.507778, -0.840556)), + (LONDON, pi * 1.5, 50, (51.507778, -0.840556)), + (NEW_YORK, Direction.SOUTH, 15, (40.568611, -74.235278)), + (NEW_YORK, Direction.NORTHWEST, 50, (41.020556, -74.656667)), + (NEW_YORK, pi * 1.25, 50, (40.384722, -74.6525)), + ], +) +def test_inverse_kilometers(point, dir, dist, result): + assert isclose(inverse_haversine(point, dist, dir), result, rtol=1e-5).all() + + +@pytest.mark.parametrize( + "point, direction, distance, unit", + [ + (PARIS, Direction.NORTH, 10, Unit.KILOMETERS), + (LONDON, Direction.WEST, 32, Unit.MILES), + (LYON, Direction.NORTHEAST, 45_000, Unit.METERS), + (NEW_YORK, Direction.SOUTH, 15, Unit.NAUTICAL_MILES), + ], +) +def test_back_and_forth(point, direction, distance, unit): + new_point = inverse_haversine(point, distance, direction, unit) + assert isclose(haversine(new_point, point, unit), distance, rtol=1e-10) + + +def test_inverse_miles(): + assert isclose(inverse_haversine(PARIS, 50, Direction.NORTH, unit=Unit.MILES), (49.5803579218996, 2.3508), rtol=1e-5).all() + + +def test_nautical_inverse_miles(): + assert isclose(inverse_haversine(PARIS, 10, Direction.SOUTH, unit=Unit.NAUTICAL_MILES), (48.69014586638915, 2.3508), rtol=1e-5).all() From 1ed4cca8e9731e5e394f8a6637a10dca1474df37 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Wed, 11 Aug 2021 00:31:49 +0200 Subject: [PATCH 03/59] Adding radian and degree units --- haversine/haversine.py | 8 ++++++-- tests/test_haversine.py | 17 +++++++++++++++-- tests/test_haversine_vector.py | 4 +++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/haversine/haversine.py b/haversine/haversine.py index 2be6562..076dd35 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -1,4 +1,4 @@ -from math import radians, cos, sin, asin, sqrt +from math import radians, cos, sin, asin, sqrt, pi from enum import Enum @@ -19,6 +19,8 @@ class Unit(Enum): NAUTICAL_MILES = 'nmi' FEET = 'ft' INCHES = 'in' + RADIANS = 'rad' + DEGREES = 'deg' # Unit values taken from http://www.unitconversion.org/unit_converter/length.html @@ -27,7 +29,9 @@ class Unit(Enum): Unit.MILES: 0.621371192, Unit.NAUTICAL_MILES: 0.539956803, Unit.FEET: 3280.839895013, - Unit.INCHES: 39370.078740158} + Unit.INCHES: 39370.078740158, + Unit.RADIANS: 1/_AVG_EARTH_RADIUS_KM, + Unit.DEGREES: (1/_AVG_EARTH_RADIUS_KM)*(180.0/pi)} def get_avg_earth_radius(unit): unit = Unit(unit) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index 070b053..a9d01e1 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -1,4 +1,5 @@ from haversine import haversine, haversine_vector, Unit +from math import pi from numpy.testing import assert_allclose LYON = (45.7597, 4.8422) @@ -11,7 +12,9 @@ Unit.MILES: 243.71250609539814, Unit.NAUTICAL_MILES: 211.78037755311516, Unit.FEET: 1286802.0326751503, - Unit.INCHES: 15441624.392102592} + Unit.INCHES: 15441624.392102592, + Unit.RADIANS: 0.061562818679421795, + Unit.DEGREES: 3.5272896852600164} def haversine_test_factory(unit): @@ -30,6 +33,8 @@ def test(): test_nautical_miles = haversine_test_factory(Unit.NAUTICAL_MILES) test_feet = haversine_test_factory(Unit.FEET) test_inches = haversine_test_factory(Unit.INCHES) +test_radians = haversine_test_factory(Unit.RADIANS) +test_degrees = haversine_test_factory(Unit.DEGREES) def test_units_enum(): @@ -43,4 +48,12 @@ def test_haversine_vector_comb(): assert_allclose( # See https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_allclose.html#numpy.testing.assert_allclose haversine_vector([LYON, LONDON], [PARIS, NEW_YORK], Unit.KILOMETERS, comb=True), expected - ) \ No newline at end of file + ) + +def test_haversine_deg_rad(): + """ + Test makes sure that one time around earth matches sphere circumference in degrees / radians. + """ + p1, p2 = (45, 0), (-45, 180) + assert haversine(p1, p2, unit=Unit.RADIANS) == pi + assert round(haversine(p1, p2, unit=Unit.DEGREES), 13) == 180.0 diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index 72ed006..f2330fc 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -9,7 +9,9 @@ Unit.MILES: 243.71250609539814, Unit.NAUTICAL_MILES: 211.78037755311516, Unit.FEET: 1286802.0326751503, - Unit.INCHES: 15441624.392102592} + Unit.INCHES: 15441624.392102592, + Unit.RADIANS: 0.386810597795104, + Unit.DEGREES: 22.162614724591847} EXPECTED_LYON_NEW_YORK = {Unit.KILOMETERS: 6163.43638211, Unit.METERS: 61634363.8211 } EXPECTED_PARIS_NEW_YORK = {Unit.KILOMETERS: 5853.32898662, From d36ed4e43ef07f7bf0238b7bc8942f9a67ed7001 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Mon, 23 Aug 2021 20:37:21 +0200 Subject: [PATCH 04/59] Adding deg/rad to readme --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 62cc59e..4577a89 100755 --- a/README.md +++ b/README.md @@ -43,8 +43,9 @@ print(tuple(haversine.Unit)) outputs ```text -(, , , - , , ) +(, , , + , , , + , ) ``` ### Inverse Haversine Formula From cb6faec9a491cc962b41e5b0bc767195860d8871 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Tue, 24 Aug 2021 10:08:28 +0200 Subject: [PATCH 05/59] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4577a89..20c14b4 100755 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Calculate the distance (in various units) between two points on Earth using thei ## Installation -```bash -$ pip install haversine +```sh +pip install haversine ``` ## Usage From 78786b00e94c9fb752d0f83a3e72477b65df9161 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Tue, 24 Aug 2021 10:12:45 +0200 Subject: [PATCH 06/59] update changelog for 2.4.0 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03814ea..ac68b6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # CHANGELOG +## 2.4.0 + +- Added inver haversine functionality [#39](https://github.com/mapado/haversine/pull/39) by [@CrapsJeroen](https://github.com/CrapsJeroen) +- Adds radians and degrees units [#40](https://github.com/mapado/haversine/pull/40) by [@https://github.com/merschformann](https://github.com/merschformann) + + +## 2.3.1 + +- Fix license in setup.py [#38](https://github.com/mapado/haversine/pull/38) by [@kraj](https://github.com/kraj) + ## 2.3.0 ### Added From 487d53d6fd7bf02d016322c5c98fc5c6821fc8da Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Tue, 24 Aug 2021 10:12:52 +0200 Subject: [PATCH 07/59] =?UTF-8?q?Bump=20version:=202.3.1=20=E2=86=92=202.4?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7e786d1..f70fe65 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -2,5 +2,5 @@ files = ./setup.py commit = True tag = True -current_version = 2.3.1 +current_version = 2.4.0 diff --git a/setup.py b/setup.py index 2cdeb22..66f580b 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='haversine', - version='2.3.1', + version='2.4.0', description='Calculate the distance between 2 points on Earth.', long_description=open('README.md').read(), long_description_content_type="text/markdown", From a3c080538f7c4e016253eaf622b876bac5baf1c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 08:16:42 +0000 Subject: [PATCH 08/59] Bump py from 1.9.0 to 1.10.0 Bumps [py](https://github.com/pytest-dev/py) from 1.9.0 to 1.10.0. - [Release notes](https://github.com/pytest-dev/py/releases) - [Changelog](https://github.com/pytest-dev/py/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/py/compare/1.9.0...1.10.0) Signed-off-by: dependabot[bot] --- Pipfile.lock | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 809a8a5..bdca409 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -20,29 +20,24 @@ "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197", "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.4.0" }, "attrs": { "hashes": [ - "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a", - "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff" + "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", + "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" ], - "version": "==20.1.0" - }, - "importlib-metadata": { - "hashes": [ - "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83", - "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070" - ], - "markers": "python_version < '3.8'", - "version": "==1.7.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==21.2.0" }, "more-itertools": { "hashes": [ - "sha256:6f83822ae94818eae2612063a5101a7311e68ae8002005b5e05f03fd74a86a20", - "sha256:9b30f12df9393f0d28af9210ff8efe48d10c94f73e5daf886f10c4b0b0b4f03c" + "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d", + "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a" ], - "version": "==8.5.0" + "markers": "python_version >= '3.5'", + "version": "==8.8.0" }, "numpy": { "hashes": [ @@ -81,14 +76,16 @@ "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.13.1" }, "py": { "hashes": [ - "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", - "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" + "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", + "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" ], - "version": "==1.9.0" + "index": "pypi", + "version": "==1.10.0" }, "pytest": { "hashes": [ @@ -100,17 +97,11 @@ }, "six": { "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "version": "==1.15.0" - }, - "zipp": { - "hashes": [ - "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", - "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "version": "==3.1.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" } } } From c308fb80575b0f6a9318efa378e56c832f3f1102 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:24:23 +0200 Subject: [PATCH 09/59] Create python-app.yml --- .github/workflows/python-app.yml | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/python-app.yml diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 0000000..89e21c0 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,49 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python application + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + python-version: + - 2.7 + - 3.5 + - 3.6 + - 3.7 + - 3.8 + - 3.9 + + name: Python ${{ matrix.python-version }} sample + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Reset pipfile on python 2.7 + if: ${{ matrix.python-version == '2.7' }} + run: rm Pipfile.lock + + - name: Install pipenv + run: | + python -m pip install --upgrade pip + pip install pipenv + + - name: Install dependencies + run: pipenv install --dev + + - name: Test with pytest + run: | + pipenv run py.test From daf680e6daee951d0d2da15797526f6c18bdef34 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:38:59 +0200 Subject: [PATCH 10/59] Migrate from travis to github actions --- .github/workflows/python-app.yml | 2 +- .travis.yml | 25 ------------------------- README.md | 2 +- 3 files changed, 2 insertions(+), 27 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 89e21c0..0f08f14 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -24,7 +24,7 @@ jobs: - 3.8 - 3.9 - name: Python ${{ matrix.python-version }} sample + name: Python ${{ matrix.python-version }} steps: - uses: actions/checkout@v2 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 66cff25..0000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -dist: xenial # required for Python >= 3.7 -language: python -matrix: - include: - - name: 'Python 2.7' - python: '2.7' - env: RESET_PIPENV=yes - - name: 'Python 3.6' - python: '3.6' - - name: 'Python 3.7' - python: '3.7' - -# command to install dependencies -before_install: - - if [[ $RESET_PIPENV = 'yes' ]]; then - rm Pipfile.lock; - fi - - pip install pipenv - -install: - - pipenv install --dev - -# command to run tests -script: pipenv run py.test diff --git a/README.md b/README.md index 20c14b4..d350811 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Haversine [![Build Status](https://travis-ci.org/mapado/haversine.svg?branch=master)](https://travis-ci.org/mapado/haversine) +# Haversine Calculate the distance (in various units) between two points on Earth using their latitude and longitude. From dc081115649f652aaa1df1ba7ebabf27c8db890f Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:42:00 +0200 Subject: [PATCH 11/59] python 2.7 compatibility --- haversine/haversine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haversine/haversine.py b/haversine/haversine.py index d66da50..40e11c5 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -159,7 +159,7 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): return 2 * get_avg_earth_radius(unit) * numpy.arcsin(numpy.sqrt(d)) -def inverse_haversine(point, distance, direction: Union[Direction, float], unit=Unit.KILOMETERS): +def inverse_haversine(point, distance, direction, unit=Unit.KILOMETERS): lat, lng = point lat, lng = map(radians, (lat, lng)) From d377a92c046477458820d5df9e7f2721df1230d2 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:43:01 +0200 Subject: [PATCH 12/59] changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac68b6c..1f122bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGELOG +## 2.4.1 + +- Fix issue with python 2.7 compatibily. See [#41](https://github.com/mapado/haversine/issues/41) ## 2.4.0 - Added inver haversine functionality [#39](https://github.com/mapado/haversine/pull/39) by [@CrapsJeroen](https://github.com/CrapsJeroen) From a6316f6dd7deb4087a0b2d0f26666738128bee46 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:43:03 +0200 Subject: [PATCH 13/59] =?UTF-8?q?Bump=20version:=202.4.0=20=E2=86=92=202.4?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f70fe65..c2f1eba 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -2,5 +2,5 @@ files = ./setup.py commit = True tag = True -current_version = 2.4.0 +current_version = 2.4.1 diff --git a/setup.py b/setup.py index 66f580b..19134cf 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='haversine', - version='2.4.0', + version='2.4.1', description='Calculate the distance between 2 points on Earth.', long_description=open('README.md').read(), long_description_content_type="text/markdown", From 61799501f55246f766860ed0cbfdedaac2b6a684 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:55:38 +0200 Subject: [PATCH 14/59] Drop support for python 2.7 --- .github/workflows/python-app.yml | 4 -- CHANGELOG.md | 4 ++ Pipfile.lock | 94 ++++++++++++++++++++------------ setup.py | 16 ++---- 4 files changed, 68 insertions(+), 50 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 0f08f14..3ba24c0 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -17,7 +17,6 @@ jobs: strategy: matrix: python-version: - - 2.7 - 3.5 - 3.6 - 3.7 @@ -32,9 +31,6 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - name: Reset pipfile on python 2.7 - if: ${{ matrix.python-version == '2.7' }} - run: rm Pipfile.lock - name: Install pipenv run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f122bf..b020c28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 2.5.0 + +- [Minor break] Drop support for python 2.7 + ## 2.4.1 - Fix issue with python 2.7 compatibily. See [#41](https://github.com/mapado/haversine/issues/41) diff --git a/Pipfile.lock b/Pipfile.lock index bdca409..9031af8 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -20,7 +20,6 @@ "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197", "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.4.0" }, "attrs": { @@ -28,63 +27,71 @@ "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==21.2.0" }, + "importlib-metadata": { + "hashes": [ + "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15", + "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1" + ], + "markers": "python_version < '3.8'", + "version": "==4.8.1" + }, "more-itertools": { "hashes": [ "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d", "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a" ], - "markers": "python_version >= '3.5'", "version": "==8.8.0" }, "numpy": { "hashes": [ - "sha256:082f8d4dd69b6b688f64f509b91d482362124986d98dc7dc5f5e9f9b9c3bb983", - "sha256:1bc0145999e8cb8aed9d4e65dd8b139adf1919e521177f198529687dbf613065", - "sha256:309cbcfaa103fc9a33ec16d2d62569d541b79f828c382556ff072442226d1968", - "sha256:3673c8b2b29077f1b7b3a848794f8e11f401ba0b71c49fbd26fb40b71788b132", - "sha256:480fdd4dbda4dd6b638d3863da3be82873bba6d32d1fc12ea1b8486ac7b8d129", - "sha256:56ef7f56470c24bb67fb43dae442e946a6ce172f97c69f8d067ff8550cf782ff", - "sha256:5a936fd51049541d86ccdeef2833cc89a18e4d3808fe58a8abeb802665c5af93", - "sha256:5b6885c12784a27e957294b60f97e8b5b4174c7504665333c5e94fbf41ae5d6a", - "sha256:667c07063940e934287993366ad5f56766bc009017b4a0fe91dbd07960d0aba7", - "sha256:7ed448ff4eaffeb01094959b19cbaf998ecdee9ef9932381420d514e446601cd", - "sha256:8343bf67c72e09cfabfab55ad4a43ce3f6bf6e6ced7acf70f45ded9ebb425055", - "sha256:92feb989b47f83ebef246adabc7ff3b9a59ac30601c3f6819f8913458610bdcc", - "sha256:935c27ae2760c21cd7354402546f6be21d3d0c806fffe967f745d5f2de5005a7", - "sha256:aaf42a04b472d12515debc621c31cf16c215e332242e7a9f56403d814c744624", - "sha256:b12e639378c741add21fbffd16ba5ad25c0a1a17cf2b6fe4288feeb65144f35b", - "sha256:b1cca51512299841bf69add3b75361779962f9cee7d9ee3bb446d5982e925b69", - "sha256:b8456987b637232602ceb4d663cb34106f7eb780e247d51a260b84760fd8f491", - "sha256:b9792b0ac0130b277536ab8944e7b754c69560dac0415dd4b2dbd16b902c8954", - "sha256:c9591886fc9cbe5532d5df85cb8e0cc3b44ba8ce4367bd4cf1b93dc19713da72", - "sha256:cf1347450c0b7644ea142712619533553f02ef23f92f781312f6a3553d031fc7", - "sha256:de8b4a9b56255797cbddb93281ed92acbc510fb7b15df3f01bd28f46ebc4edae", - "sha256:e1b1dc0372f530f26a03578ac75d5e51b3868b9b76cd2facba4c9ee0eb252ab1", - "sha256:e45f8e981a0ab47103181773cc0a54e650b2aef8c7b6cd07405d0fa8d869444a", - "sha256:e4f6d3c53911a9d103d8ec9518190e52a8b945bab021745af4939cfc7c0d4a9e", - "sha256:ed8a311493cf5480a2ebc597d1e177231984c818a86875126cfd004241a73c3e", - "sha256:ef71a1d4fd4858596ae80ad1ec76404ad29701f8ca7cdcebc50300178db14dfc" + "sha256:09858463db6dd9f78b2a1a05c93f3b33d4f65975771e90d2cf7aadb7c2f66edf", + "sha256:209666ce9d4a817e8a4597cd475b71b4878a85fa4b8db41d79fdb4fdee01dde2", + "sha256:298156f4d3d46815eaf0fcf0a03f9625fc7631692bd1ad851517ab93c3168fc6", + "sha256:30fc68307c0155d2a75ad19844224be0f2c6f06572d958db4e2053f816b859ad", + "sha256:423216d8afc5923b15df86037c6053bf030d15cc9e3224206ef868c2d63dd6dc", + "sha256:426a00b68b0d21f2deb2ace3c6d677e611ad5a612d2c76494e24a562a930c254", + "sha256:466e682264b14982012887e90346d33435c984b7fead7b85e634903795c8fdb0", + "sha256:51a7b9db0a2941434cd930dacaafe0fc9da8f3d6157f9d12f761bbde93f46218", + "sha256:52a664323273c08f3b473548bf87c8145b7513afd63e4ebba8496ecd3853df13", + "sha256:550564024dc5ceee9421a86fc0fb378aa9d222d4d0f858f6669eff7410c89bef", + "sha256:5de64950137f3a50b76ce93556db392e8f1f954c2d8207f78a92d1f79aa9f737", + "sha256:640c1ccfd56724f2955c237b6ccce2e5b8607c3bc1cc51d3933b8c48d1da3723", + "sha256:7fdc7689daf3b845934d67cb221ba8d250fdca20ac0334fea32f7091b93f00d3", + "sha256:805459ad8baaf815883d0d6f86e45b3b0b67d823a8f3fa39b1ed9c45eaf5edf1", + "sha256:92a0ab128b07799dd5b9077a9af075a63467d03ebac6f8a93e6440abfea4120d", + "sha256:9f2dc79c093f6c5113718d3d90c283f11463d77daa4e83aeeac088ec6a0bda52", + "sha256:a5109345f5ce7ddb3840f5970de71c34a0ff7fceb133c9441283bb8250f532a3", + "sha256:a55e4d81c4260386f71d22294795c87609164e22b28ba0d435850fbdf82fc0c5", + "sha256:a9da45b748caad72ea4a4ed57e9cd382089f33c5ec330a804eb420a496fa760f", + "sha256:b160b9a99ecc6559d9e6d461b95c8eec21461b332f80267ad2c10394b9503496", + "sha256:b342064e647d099ca765f19672696ad50c953cac95b566af1492fd142283580f", + "sha256:b5e8590b9245803c849e09bae070a8e1ff444f45e3f0bed558dd722119eea724", + "sha256:bf75d5825ef47aa51d669b03ce635ecb84d69311e05eccea083f31c7570c9931", + "sha256:c01b59b33c7c3ba90744f2c695be571a3bd40ab2ba7f3d169ffa6db3cfba614f", + "sha256:d96a6a7d74af56feb11e9a443150216578ea07b7450f7c05df40eec90af7f4a7", + "sha256:dd0e3651d210068d13e18503d75aaa45656eef51ef0b261f891788589db2cc38", + "sha256:e167b9805de54367dcb2043519382be541117503ce99e3291cc9b41ca0a83557", + "sha256:e42029e184008a5fd3d819323345e25e2337b0ac7f5c135b7623308530209d57", + "sha256:f545c082eeb09ae678dd451a1b1dbf17babd8a0d7adea02897a76e639afca310", + "sha256:fde50062d67d805bc96f1a9ecc0d37bfc2a8f02b937d2c50824d186aa91f2419" ], "index": "pypi", - "version": "==1.19.1" + "version": "==1.21.2" }, "pluggy": { "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", + "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.1" + "version": "==1.0.0" }, "py": { "hashes": [ "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" ], - "index": "pypi", "version": "==1.10.0" }, "pytest": { @@ -100,8 +107,23 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e", + "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7", + "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34" + ], + "markers": "python_version < '3.8'", + "version": "==3.10.0.2" + }, + "zipp": { + "hashes": [ + "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3", + "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4" + ], + "version": "==3.5.0" } } } diff --git a/setup.py b/setup.py index 19134cf..af040e3 100755 --- a/setup.py +++ b/setup.py @@ -7,10 +7,8 @@ long_description=open('README.md').read(), long_description_content_type="text/markdown", include_package_data=True, - install_requires=['enum34;python_version<"3.4"'], - + python_requires='>=3.5', author='Balthazar Rouberol', - author_email='balthazar@mapado.com', maintainer='Julien Deniau', maintainer_email='julien.deniau@mapado.com', url='https://github.com/mapado/haversine', @@ -21,13 +19,11 @@ 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.1', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Scientific/Engineering :: Mathematics' ], ) From 7016702de5d76741f08acd7fbdbbf6ab74d41a59 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:58:22 +0200 Subject: [PATCH 15/59] upgrade changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b020c28..1835f56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.5.0 -- [Minor break] Drop support for python 2.7 +- [Minor break] Drop support for python 2.7 [#42](https://github.com/mapado/haversine/pull/42) ## 2.4.1 From fb1732ff15099d09bea029534b26b426c43f47b0 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 14:59:30 +0200 Subject: [PATCH 16/59] =?UTF-8?q?Bump=20version:=202.4.1=20=E2=86=92=202.5?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c2f1eba..6edd7fa 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -2,5 +2,5 @@ files = ./setup.py commit = True tag = True -current_version = 2.4.1 +current_version = 2.5.0 diff --git a/setup.py b/setup.py index af040e3..877f430 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='haversine', - version='2.4.1', + version='2.5.0', description='Calculate the distance between 2 points on Earth.', long_description=open('README.md').read(), long_description_content_type="text/markdown", From efc35499b4f9618117a2033a23106f5a46d5a1f7 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 15:02:06 +0200 Subject: [PATCH 17/59] Reset type hinting for `inverse_haversine` --- CHANGELOG.md | 4 ++++ haversine/haversine.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1835f56..b40171a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 2.5.1 + +- Reset type hinting for `inverse_haversine` + ## 2.5.0 - [Minor break] Drop support for python 2.7 [#42](https://github.com/mapado/haversine/pull/42) diff --git a/haversine/haversine.py b/haversine/haversine.py index 40e11c5..d66da50 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -159,7 +159,7 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): return 2 * get_avg_earth_radius(unit) * numpy.arcsin(numpy.sqrt(d)) -def inverse_haversine(point, distance, direction, unit=Unit.KILOMETERS): +def inverse_haversine(point, distance, direction: Union[Direction, float], unit=Unit.KILOMETERS): lat, lng = point lat, lng = map(radians, (lat, lng)) From 3e61c151aeddd0520fa26eab695da0ccc3b42c45 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 2 Sep 2021 15:02:09 +0200 Subject: [PATCH 18/59] =?UTF-8?q?Bump=20version:=202.5.0=20=E2=86=92=202.5?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6edd7fa..a387d0a 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -2,5 +2,5 @@ files = ./setup.py commit = True tag = True -current_version = 2.5.0 +current_version = 2.5.1 diff --git a/setup.py b/setup.py index 877f430..bb6792d 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='haversine', - version='2.5.0', + version='2.5.1', description='Calculate the distance between 2 points on Earth.', long_description=open('README.md').read(), long_description_content_type="text/markdown", From a447237c8e6a681c5655b5e80fd917bd31e7e862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9?= Date: Sun, 20 Feb 2022 17:52:05 +0100 Subject: [PATCH 19/59] Move ressources to new file --- tests/geo_ressources.py | 21 ++++++++++++++ tests/test_haversine.py | 26 ++--------------- tests/test_haversine_vector.py | 49 +++++++++++++++------------------ tests/test_inverse_haversine.py | 6 +--- 4 files changed, 46 insertions(+), 56 deletions(-) create mode 100644 tests/geo_ressources.py diff --git a/tests/geo_ressources.py b/tests/geo_ressources.py new file mode 100644 index 0000000..efc0371 --- /dev/null +++ b/tests/geo_ressources.py @@ -0,0 +1,21 @@ +from haversine import Unit + +LYON = (45.7597, 4.8422) +PARIS = (48.8567, 2.3508) +NEW_YORK = (40.7033962, -74.2351462) +LONDON = (51.509865, -0.118092) + +EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595594006, + Unit.METERS: 392217.2595594006, + Unit.MILES: 243.71250609539814, + Unit.NAUTICAL_MILES: 211.78037755311516, + Unit.FEET: 1286802.0326751503, + Unit.INCHES: 15441624.392102592, + Unit.RADIANS: 0.386810597795104, + Unit.DEGREES: 22.162614724591847} +EXPECTED_LYON_NEW_YORK = {Unit.KILOMETERS: 6163.43638211, + Unit.METERS: 61634363.8211 } +EXPECTED_PARIS_NEW_YORK = {Unit.KILOMETERS: 5853.32898662, + Unit.METERS: 58533289.8662 } +EXPECTED_LONDON_PARIS = {Unit.KILOMETERS: 343.37455271} +EXPECTED_LONDON_NEW_YORK = {Unit.KILOMETERS: 5586.48447423} diff --git a/tests/test_haversine.py b/tests/test_haversine.py index a9d01e1..e2a145c 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -1,21 +1,7 @@ -from haversine import haversine, haversine_vector, Unit +from haversine import haversine, Unit from math import pi -from numpy.testing import assert_allclose - -LYON = (45.7597, 4.8422) -PARIS = (48.8567, 2.3508) -LONDON = (51.509865, -0.118092) -NEW_YORK = (40.7033962, -74.2351462) - -EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595594006, - Unit.METERS: 392217.2595594006, - Unit.MILES: 243.71250609539814, - Unit.NAUTICAL_MILES: 211.78037755311516, - Unit.FEET: 1286802.0326751503, - Unit.INCHES: 15441624.392102592, - Unit.RADIANS: 0.061562818679421795, - Unit.DEGREES: 3.5272896852600164} +from tests.geo_ressources import LYON, PARIS, NEW_YORK, LONDON, EXPECTED_LYON_PARIS def haversine_test_factory(unit): def test(): @@ -42,14 +28,6 @@ def test_units_enum(): assert all(unit in _CONVERSIONS for unit in Unit) -def test_haversine_vector_comb(): - expected = [[ 392.21725956, 343.37455271], [6163.43638211, 5586.48447423]] - - assert_allclose( # See https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_allclose.html#numpy.testing.assert_allclose - haversine_vector([LYON, LONDON], [PARIS, NEW_YORK], Unit.KILOMETERS, comb=True), - expected - ) - def test_haversine_deg_rad(): """ Test makes sure that one time around earth matches sphere circumference in degrees / radians. diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index f2330fc..7d804b5 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -1,42 +1,37 @@ from haversine import haversine_vector, Unit +from numpy.testing import assert_allclose -LYON = (45.7597, 4.8422) -PARIS = (48.8567, 2.3508) -NEW_YORK = (40.7033962, -74.2351462) - -EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595594006, - Unit.METERS: 392217.2595594006, - Unit.MILES: 243.71250609539814, - Unit.NAUTICAL_MILES: 211.78037755311516, - Unit.FEET: 1286802.0326751503, - Unit.INCHES: 15441624.392102592, - Unit.RADIANS: 0.386810597795104, - Unit.DEGREES: 22.162614724591847} -EXPECTED_LYON_NEW_YORK = {Unit.KILOMETERS: 6163.43638211, - Unit.METERS: 61634363.8211 } -EXPECTED_PARIS_NEW_YORK = {Unit.KILOMETERS: 5853.32898662, - Unit.METERS: 58533289.8662 } - - -def haversine_test_factory(unit): - def test(): - expected_lyon_paris = EXPECTED_LYON_PARIS[unit] - expected_lyon_new_york = EXPECTED_LYON_NEW_YORK[unit] - expected_paris_new_york = EXPECTED_PARIS_NEW_YORK[unit] +from tests.geo_ressources import EXPECTED_LONDON_PARIS, EXPECTED_LYON_NEW_YORK, EXPECTED_LYON_PARIS, EXPECTED_LONDON_NEW_YORK, LYON, PARIS, NEW_YORK, LONDON +def test_pair(unit): + def test_lyon_paris(unit): + expected_lyon_paris = EXPECTED_LYON_PARIS[unit] assert haversine_vector(LYON, PARIS, unit=unit) == expected_lyon_paris assert isinstance(unit.value, str) assert haversine_vector(LYON, PARIS, unit=unit.value) == expected_lyon_paris - return test + return test_lyon_paris(unit) -test_kilometers = haversine_test_factory(Unit.KILOMETERS) -test_meters = haversine_test_factory(Unit.METERS) +def test_haversine_vector_comb(): + unit = Unit.KILOMETERS + expected = [ + [EXPECTED_LYON_PARIS[unit], EXPECTED_LONDON_PARIS[unit]], + [EXPECTED_LYON_NEW_YORK[unit], EXPECTED_LONDON_NEW_YORK[unit]] + ] + assert_allclose( # See https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_allclose.html#numpy.testing.assert_allclose + haversine_vector([LYON, LONDON], [PARIS, NEW_YORK], unit, comb=True), + expected + ) + +test_pair(Unit.KILOMETERS) +test_pair(Unit.METERS) +test_pair(Unit.INCHES) +test_haversine_vector_comb() def test_units_enum(): from haversine.haversine import _CONVERSIONS assert all(unit in _CONVERSIONS for unit in Unit) - +test_units_enum() \ No newline at end of file diff --git a/tests/test_inverse_haversine.py b/tests/test_inverse_haversine.py index 905a0bc..34cb6fb 100755 --- a/tests/test_inverse_haversine.py +++ b/tests/test_inverse_haversine.py @@ -3,11 +3,7 @@ from math import pi import pytest -LYON = (45.7597, 4.8422) -PARIS = (48.8567, 2.3508) -LONDON = (51.509865, -0.118092) -NEW_YORK = (40.7033962, -74.2351462) - +from tests.geo_ressources import LYON, PARIS, NEW_YORK, LONDON @pytest.mark.parametrize( "point, dir, dist, result", From 1da16a3ee0ba24dcde4f52f74a84d3cf58e1f422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9?= Date: Sun, 20 Feb 2022 18:10:34 +0100 Subject: [PATCH 20/59] correct constant values --- tests/geo_ressources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/geo_ressources.py b/tests/geo_ressources.py index efc0371..7069642 100644 --- a/tests/geo_ressources.py +++ b/tests/geo_ressources.py @@ -11,8 +11,8 @@ Unit.NAUTICAL_MILES: 211.78037755311516, Unit.FEET: 1286802.0326751503, Unit.INCHES: 15441624.392102592, - Unit.RADIANS: 0.386810597795104, - Unit.DEGREES: 22.162614724591847} + Unit.RADIANS: 0.061562818679421795, + Unit.DEGREES: 3.5272896852600164} EXPECTED_LYON_NEW_YORK = {Unit.KILOMETERS: 6163.43638211, Unit.METERS: 61634363.8211 } EXPECTED_PARIS_NEW_YORK = {Unit.KILOMETERS: 5853.32898662, From 0b47ac417d82c4ae15ba49c7856453bf81afa1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9?= Date: Sun, 20 Feb 2022 18:10:42 +0100 Subject: [PATCH 21/59] use parametrized test --- tests/test_haversine_vector.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index 7d804b5..f1cd9b1 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -1,8 +1,12 @@ from haversine import haversine_vector, Unit from numpy.testing import assert_allclose +import pytest from tests.geo_ressources import EXPECTED_LONDON_PARIS, EXPECTED_LYON_NEW_YORK, EXPECTED_LYON_PARIS, EXPECTED_LONDON_NEW_YORK, LYON, PARIS, NEW_YORK, LONDON +@pytest.mark.parametrize( + 'unit', [Unit.KILOMETERS, Unit.METERS, Unit.INCHES] +) def test_pair(unit): def test_lyon_paris(unit): expected_lyon_paris = EXPECTED_LYON_PARIS[unit] @@ -25,13 +29,6 @@ def test_haversine_vector_comb(): expected ) -test_pair(Unit.KILOMETERS) -test_pair(Unit.METERS) -test_pair(Unit.INCHES) -test_haversine_vector_comb() - def test_units_enum(): from haversine.haversine import _CONVERSIONS assert all(unit in _CONVERSIONS for unit in Unit) - -test_units_enum() \ No newline at end of file From 32c2813e5ade6724456184dcf03ca75b982f6b4e Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 28 Feb 2022 07:31:30 +0100 Subject: [PATCH 22/59] Migrate from master to main in workflow --- .github/workflows/python-app.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 3ba24c0..1eb90b2 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -5,9 +5,9 @@ name: Python application on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: build: From d609107ba9bcb83658ba85050252ced07b33c275 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 28 Feb 2022 07:49:24 +0100 Subject: [PATCH 23/59] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..e3c9c1d --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '39 12 * * 3' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From fc1772f0061dee7c1d9059955eed64a693af6bea Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 23 May 2022 09:06:52 +0200 Subject: [PATCH 24/59] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b40171a..161993b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ ## 2.4.0 - Added inver haversine functionality [#39](https://github.com/mapado/haversine/pull/39) by [@CrapsJeroen](https://github.com/CrapsJeroen) -- Adds radians and degrees units [#40](https://github.com/mapado/haversine/pull/40) by [@https://github.com/merschformann](https://github.com/merschformann) +- Adds radians and degrees units [#40](https://github.com/mapado/haversine/pull/40) by [@merschformann](https://github.com/merschformann) ## 2.3.1 From 2f174f41207aea6326d059116e5b6739415d019e Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 13 Jun 2022 12:40:17 +0200 Subject: [PATCH 25/59] add test and explaination about degrees and radians. Fixes #45 --- README.md | 10 ++++++++++ tests/test_haversine.py | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/README.md b/README.md index d350811..4a5c64d 100755 --- a/README.md +++ b/README.md @@ -48,6 +48,16 @@ outputs , ) ``` + +#### Note for radians and degrees + +The radian and degrees returns the [great circle distance](https://en.wikipedia.org/wiki/Great-circle_distance) between two points on a sphere. + +Notes: + + - on a unit-sphere the angular distance in radians equals the distance between the two points on the sphere (definition of radians) + - When using "degree", this angle is just converted from radians to degrees + ### Inverse Haversine Formula Calculates a point from a given vector (distance and direction) and start point. Currently explicitly supports both cardinal (north, east, south, west) and intercardinal (northeast, southeast, southwest, northwest) directions. diff --git a/tests/test_haversine.py b/tests/test_haversine.py index e2a145c..8ee967c 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -35,3 +35,11 @@ def test_haversine_deg_rad(): p1, p2 = (45, 0), (-45, 180) assert haversine(p1, p2, unit=Unit.RADIANS) == pi assert round(haversine(p1, p2, unit=Unit.DEGREES), 13) == 180.0 + +def test_haversine_deg_rad_great_circle_distance(): + """ + Test makes sure the haversine functions returns the great circle distance (https://en.wikipedia.org/wiki/Great-circle_distance) between two points on a sphere. + See https://github.com/mapado/haversine/issues/45 + """ + p1, p2 = (0, -45), (0, 45) + assert haversine(p1, p2, Unit.DEGREES) == 89.99999999999997 From 8c9c62805955571ba8d297f4171b6e1905dd4497 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Fri, 8 Jul 2022 02:38:11 +0200 Subject: [PATCH 26/59] Adds normalization of lat/lon to their corresponding ranges --- haversine/haversine.py | 10 ++++++++++ tests/geo_ressources.py | 16 ++++++++-------- tests/test_haversine.py | 9 +++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/haversine/haversine.py b/haversine/haversine.py index d66da50..e4a74e9 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -88,6 +88,10 @@ def haversine(point1, point2, unit=Unit.KILOMETERS): lat1, lng1 = point1 lat2, lng2 = point2 + # normalize latitude to [-90, 90] and longitude to [-180, 180] ranges + lat1, lat2 = (lat1 + 90) % 180 - 90, (lat2 + 90) % 180 - 90 + lng1, lng2 = (lng1 + 180) % 360 - 180, (lng2 + 180) % 360 - 180 + # convert all latitudes/longitudes from decimal degrees to radians lat1 = radians(lat1) lng1 = radians(lng1) @@ -137,6 +141,12 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): lat1, lng1 = array1[:, 0], array1[:, 1] lat2, lng2 = array2[:, 0], array2[:, 1] + # normalize latitude to [-90, 90] and longitude to [-180, 180] ranges + lat1 = (lat1 + 90) % 180 - 90 + lat2 = (lat2 + 90) % 180 - 90 + lng1 = (lng1 + 180) % 360 - 180 + lng2 = (lng2 + 180) % 360 - 180 + # convert all latitudes/longitudes from decimal degrees to radians lat1 = numpy.radians(lat1) lng1 = numpy.radians(lng1) diff --git a/tests/geo_ressources.py b/tests/geo_ressources.py index 7069642..84d0e2f 100644 --- a/tests/geo_ressources.py +++ b/tests/geo_ressources.py @@ -5,14 +5,14 @@ NEW_YORK = (40.7033962, -74.2351462) LONDON = (51.509865, -0.118092) -EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595594006, - Unit.METERS: 392217.2595594006, - Unit.MILES: 243.71250609539814, - Unit.NAUTICAL_MILES: 211.78037755311516, - Unit.FEET: 1286802.0326751503, - Unit.INCHES: 15441624.392102592, - Unit.RADIANS: 0.061562818679421795, - Unit.DEGREES: 3.5272896852600164} +EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595593981, + Unit.METERS: 392217.2595593981, + Unit.MILES: 243.71250609539658, + Unit.NAUTICAL_MILES: 211.78037755311382, + Unit.FEET: 1286802.0326751422, + Unit.INCHES: 15441624.392102493, + Unit.RADIANS: 0.0615628186794214, + Unit.DEGREES: 3.5272896852599938} EXPECTED_LYON_NEW_YORK = {Unit.KILOMETERS: 6163.43638211, Unit.METERS: 61634363.8211 } EXPECTED_PARIS_NEW_YORK = {Unit.KILOMETERS: 5853.32898662, diff --git a/tests/test_haversine.py b/tests/test_haversine.py index 8ee967c..bd41dc2 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -36,6 +36,15 @@ def test_haversine_deg_rad(): assert haversine(p1, p2, unit=Unit.RADIANS) == pi assert round(haversine(p1, p2, unit=Unit.DEGREES), 13) == 180.0 + +def test_normalization(): + """ + Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. + """ + p1, p2 = (0 - 180, 360 - 45), (0, 45) + assert haversine(p1, p2, Unit.DEGREES) == 89.99999999999997 + + def test_haversine_deg_rad_great_circle_distance(): """ Test makes sure the haversine functions returns the great circle distance (https://en.wikipedia.org/wiki/Great-circle_distance) between two points on a sphere. From ada73514b2af9b32c09b5475e96abf238ed31acb Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Fri, 8 Jul 2022 02:49:37 +0200 Subject: [PATCH 27/59] Adding normalization note to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4a5c64d..a95c9cb 100755 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ haversine(lyon, paris, unit=Unit.NAUTICAL_MILES) >> 211.78037755311516 # in nautical miles ``` +The lat/lon values need to be provided in degrees. If values are outside the allowed ranges [-90, 90] or [-180, 180], they will be normalized. + The `haversine.Unit` enum contains all supported units: ```python From c2f3c995230d3bed514a20a77d750d492628701a Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Fri, 8 Jul 2022 02:54:37 +0200 Subject: [PATCH 28/59] Leaving a note for the test values --- tests/test_haversine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index bd41dc2..7fe6e03 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -41,7 +41,7 @@ def test_normalization(): """ Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. """ - p1, p2 = (0 - 180, 360 - 45), (0, 45) + p1, p2 = (0 - 180, -45 + 360), (0, 45) # Use same values as below assert haversine(p1, p2, Unit.DEGREES) == 89.99999999999997 From cd5f38db8c4069ed0fe6616c07d7a75828737ff2 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Fri, 8 Jul 2022 15:52:45 +0200 Subject: [PATCH 29/59] Changing normalization style --- haversine/haversine.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/haversine/haversine.py b/haversine/haversine.py index e4a74e9..de7fadb 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -1,6 +1,6 @@ from math import radians, cos, sin, asin, sqrt, degrees, pi, atan2 from enum import Enum -from typing import Union +from typing import Union, Tuple # mean earth radius - https://en.wikipedia.org/wiki/Earth_radius#Mean_radius @@ -60,6 +60,18 @@ def get_avg_earth_radius(unit): return _AVG_EARTH_RADIUS_KM * _CONVERSIONS[unit] +def normalize(lat: float, lon: float) -> Tuple[float, float]: + """ + Normalize point to [-90, 90] latitude and [-180, 180] longitude. + """ + lat = (lat + 90) % 360 - 90 + if lat > 90: + lat = 180 - lat + lon += 180 + lon = (lon + 180) % 360 - 180 + return lat, lon + + def haversine(point1, point2, unit=Unit.KILOMETERS): """ Calculate the great-circle distance between two points on the Earth surface. @@ -88,9 +100,9 @@ def haversine(point1, point2, unit=Unit.KILOMETERS): lat1, lng1 = point1 lat2, lng2 = point2 - # normalize latitude to [-90, 90] and longitude to [-180, 180] ranges - lat1, lat2 = (lat1 + 90) % 180 - 90, (lat2 + 90) % 180 - 90 - lng1, lng2 = (lng1 + 180) % 360 - 180, (lng2 + 180) % 360 - 180 + # normalize points + lat1, lng1 = normalize(lat1, lng1) + lat2, lng2 = normalize(lat2, lng2) # convert all latitudes/longitudes from decimal degrees to radians lat1 = radians(lat1) @@ -137,16 +149,14 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): if array1.shape != array2.shape: raise IndexError("When not in combination mode, arrays must be of same size. If mode is required, use comb=True as argument.") + # normalize points + array1 = numpy.array([normalize(p[0], p[1]) for p in array1]) + array2 = numpy.array([normalize(p[0], p[1]) for p in array2]) + # unpack latitude/longitude lat1, lng1 = array1[:, 0], array1[:, 1] lat2, lng2 = array2[:, 0], array2[:, 1] - # normalize latitude to [-90, 90] and longitude to [-180, 180] ranges - lat1 = (lat1 + 90) % 180 - 90 - lat2 = (lat2 + 90) % 180 - 90 - lng1 = (lng1 + 180) % 360 - 180 - lng2 = (lng2 + 180) % 360 - 180 - # convert all latitudes/longitudes from decimal degrees to radians lat1 = numpy.radians(lat1) lng1 = numpy.radians(lng1) From b949e32246976f14f192c97c9bb0b82b8e1ee451 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Fri, 8 Jul 2022 20:35:29 +0200 Subject: [PATCH 30/59] Check lat/lon by default and allow normalization --- haversine/haversine.py | 37 +++++++++++++++++++++++++--------- tests/geo_ressources.py | 16 +++++++-------- tests/test_haversine.py | 2 +- tests/test_haversine_vector.py | 8 ++++++++ 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/haversine/haversine.py b/haversine/haversine.py index de7fadb..e7f694b 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -60,7 +60,7 @@ def get_avg_earth_radius(unit): return _AVG_EARTH_RADIUS_KM * _CONVERSIONS[unit] -def normalize(lat: float, lon: float) -> Tuple[float, float]: +def _normalize(lat: float, lon: float) -> Tuple[float, float]: """ Normalize point to [-90, 90] latitude and [-180, 180] longitude. """ @@ -72,7 +72,17 @@ def normalize(lat: float, lon: float) -> Tuple[float, float]: return lat, lon -def haversine(point1, point2, unit=Unit.KILOMETERS): +def _ensure_lat_lon(lat: float, lon: float): + """ + Ensure that the given latitude and longitude have proper values. An exception is raised if they are not. + """ + if lat < -90 or lat > 90: + raise ValueError(f"Latitude {lat} is out of range [-90, 90]") + if lon < -180 or lon > 180: + raise ValueError(f"Longitude {lon} is out of range [-180, 180]") + + +def haversine(point1, point2, unit=Unit.KILOMETERS, normalize=False): """ Calculate the great-circle distance between two points on the Earth surface. Takes two 2-tuples, containing the latitude and longitude of each point in decimal degrees, @@ -83,6 +93,7 @@ def haversine(point1, point2, unit=Unit.KILOMETERS): :param unit: a member of haversine.Unit, or, equivalently, a string containing the initials of its corresponding unit of measurement (i.e. miles = mi) default 'km' (kilometers). + :param normalize: if True, normalize the points to [-90, 90] latitude and [-180, 180] longitude. Example: ``haversine((45.7597, 4.8422), (48.8567, 2.3508), unit=Unit.METERS)`` @@ -100,9 +111,13 @@ def haversine(point1, point2, unit=Unit.KILOMETERS): lat1, lng1 = point1 lat2, lng2 = point2 - # normalize points - lat1, lng1 = normalize(lat1, lng1) - lat2, lng2 = normalize(lat2, lng2) + # normalize points or ensure they are proper lat/lon, i.e., in [-90, 90] and [-180, 180] + if normalize: + lat1, lng1 = _normalize(lat1, lng1) + lat2, lng2 = _normalize(lat2, lng2) + else: + _ensure_lat_lon(lat1, lng1) + _ensure_lat_lon(lat2, lng2) # convert all latitudes/longitudes from decimal degrees to radians lat1 = radians(lat1) @@ -118,7 +133,7 @@ def haversine(point1, point2, unit=Unit.KILOMETERS): return 2 * get_avg_earth_radius(unit) * asin(sqrt(d)) -def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): +def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False, normalize=False): ''' The exact same function as "haversine", except that this version replaces math functions with numpy functions. @@ -149,9 +164,13 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False): if array1.shape != array2.shape: raise IndexError("When not in combination mode, arrays must be of same size. If mode is required, use comb=True as argument.") - # normalize points - array1 = numpy.array([normalize(p[0], p[1]) for p in array1]) - array2 = numpy.array([normalize(p[0], p[1]) for p in array2]) + # normalize points or ensure they are proper lat/lon, i.e., in [-90, 90] and [-180, 180] + if normalize: + array1 = numpy.array([_normalize(p[0], p[1]) for p in array1]) + array2 = numpy.array([_normalize(p[0], p[1]) for p in array2]) + else: + [_ensure_lat_lon(p[0], p[1]) for p in array1] + [_ensure_lat_lon(p[0], p[1]) for p in array2] # unpack latitude/longitude lat1, lng1 = array1[:, 0], array1[:, 1] diff --git a/tests/geo_ressources.py b/tests/geo_ressources.py index 84d0e2f..7069642 100644 --- a/tests/geo_ressources.py +++ b/tests/geo_ressources.py @@ -5,14 +5,14 @@ NEW_YORK = (40.7033962, -74.2351462) LONDON = (51.509865, -0.118092) -EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595593981, - Unit.METERS: 392217.2595593981, - Unit.MILES: 243.71250609539658, - Unit.NAUTICAL_MILES: 211.78037755311382, - Unit.FEET: 1286802.0326751422, - Unit.INCHES: 15441624.392102493, - Unit.RADIANS: 0.0615628186794214, - Unit.DEGREES: 3.5272896852599938} +EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595594006, + Unit.METERS: 392217.2595594006, + Unit.MILES: 243.71250609539814, + Unit.NAUTICAL_MILES: 211.78037755311516, + Unit.FEET: 1286802.0326751503, + Unit.INCHES: 15441624.392102592, + Unit.RADIANS: 0.061562818679421795, + Unit.DEGREES: 3.5272896852600164} EXPECTED_LYON_NEW_YORK = {Unit.KILOMETERS: 6163.43638211, Unit.METERS: 61634363.8211 } EXPECTED_PARIS_NEW_YORK = {Unit.KILOMETERS: 5853.32898662, diff --git a/tests/test_haversine.py b/tests/test_haversine.py index 7fe6e03..f317ea6 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -42,7 +42,7 @@ def test_normalization(): Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. """ p1, p2 = (0 - 180, -45 + 360), (0, 45) # Use same values as below - assert haversine(p1, p2, Unit.DEGREES) == 89.99999999999997 + assert haversine(p1, p2, Unit.DEGREES, normalize=True) == 89.99999999999997 def test_haversine_deg_rad_great_circle_distance(): diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index f1cd9b1..54f470f 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -17,6 +17,14 @@ def test_lyon_paris(unit): return test_lyon_paris(unit) +def test_normalization(): + """ + Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. + """ + p1, p2 = (0 - 180, -45 + 360), (0, 45) # Use same values as below + assert haversine_vector([p1], [p2], Unit.DEGREES, normalize=True) == 89.99999999999997 + + def test_haversine_vector_comb(): unit = Unit.KILOMETERS expected = [ From 93530116f96724a107d7018c1e481b4c920dd4fc Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Fri, 8 Jul 2022 20:38:34 +0200 Subject: [PATCH 31/59] Updated readme for lat/lon handling behavior --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a95c9cb..5fb53a4 100755 --- a/README.md +++ b/README.md @@ -32,7 +32,8 @@ haversine(lyon, paris, unit=Unit.NAUTICAL_MILES) >> 211.78037755311516 # in nautical miles ``` -The lat/lon values need to be provided in degrees. If values are outside the allowed ranges [-90, 90] or [-180, 180], they will be normalized. +The lat/lon values need to be provided in degrees of the ranges [-90,90] (lat) and [-180,180] (lon). +If values are outside their ranges, an error will be raised. This can be avoided by automatic normalization via the `normalize` parameter. The `haversine.Unit` enum contains all supported units: From 16d464b338c185df285e29eafb49a7c50e35346b Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 10 Jul 2022 00:10:42 +0200 Subject: [PATCH 32/59] upgrade to pytest 7.1.2 --- Pipfile | 2 +- Pipfile.lock | 139 +++++++++++++++++++++++++++------------------------ 2 files changed, 74 insertions(+), 67 deletions(-) diff --git a/Pipfile b/Pipfile index 7106e41..1052741 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [dev-packages] -pytest = {version = "~=3.9"} +pytest = {version = "~=7.1"} numpy = "*" [packages] diff --git a/Pipfile.lock b/Pipfile.lock index 9031af8..ad83ac5 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c35288661eedea1e3d91a418cce6d5ba4797560a7ef2ebf01afd602c5cf24871" + "sha256": "d8c0d754e40d55ded3783dccd95744277f2a2d3e722215c958ef0eb753bf9d47" }, "pipfile-spec": 6, "requires": {}, @@ -15,70 +15,71 @@ }, "default": {}, "develop": { - "atomicwrites": { - "hashes": [ - "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197", - "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a" - ], - "version": "==1.4.0" - }, "attrs": { "hashes": [ - "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", - "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" + "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", + "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], - "version": "==21.2.0" + "version": "==21.4.0" }, "importlib-metadata": { "hashes": [ - "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15", - "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1" + "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", + "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" ], "markers": "python_version < '3.8'", - "version": "==4.8.1" + "version": "==4.12.0" }, - "more-itertools": { + "iniconfig": { "hashes": [ - "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d", - "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a" + "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", + "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" ], - "version": "==8.8.0" + "version": "==1.1.1" }, "numpy": { "hashes": [ - "sha256:09858463db6dd9f78b2a1a05c93f3b33d4f65975771e90d2cf7aadb7c2f66edf", - "sha256:209666ce9d4a817e8a4597cd475b71b4878a85fa4b8db41d79fdb4fdee01dde2", - "sha256:298156f4d3d46815eaf0fcf0a03f9625fc7631692bd1ad851517ab93c3168fc6", - "sha256:30fc68307c0155d2a75ad19844224be0f2c6f06572d958db4e2053f816b859ad", - "sha256:423216d8afc5923b15df86037c6053bf030d15cc9e3224206ef868c2d63dd6dc", - "sha256:426a00b68b0d21f2deb2ace3c6d677e611ad5a612d2c76494e24a562a930c254", - "sha256:466e682264b14982012887e90346d33435c984b7fead7b85e634903795c8fdb0", - "sha256:51a7b9db0a2941434cd930dacaafe0fc9da8f3d6157f9d12f761bbde93f46218", - "sha256:52a664323273c08f3b473548bf87c8145b7513afd63e4ebba8496ecd3853df13", - "sha256:550564024dc5ceee9421a86fc0fb378aa9d222d4d0f858f6669eff7410c89bef", - "sha256:5de64950137f3a50b76ce93556db392e8f1f954c2d8207f78a92d1f79aa9f737", - "sha256:640c1ccfd56724f2955c237b6ccce2e5b8607c3bc1cc51d3933b8c48d1da3723", - "sha256:7fdc7689daf3b845934d67cb221ba8d250fdca20ac0334fea32f7091b93f00d3", - "sha256:805459ad8baaf815883d0d6f86e45b3b0b67d823a8f3fa39b1ed9c45eaf5edf1", - "sha256:92a0ab128b07799dd5b9077a9af075a63467d03ebac6f8a93e6440abfea4120d", - "sha256:9f2dc79c093f6c5113718d3d90c283f11463d77daa4e83aeeac088ec6a0bda52", - "sha256:a5109345f5ce7ddb3840f5970de71c34a0ff7fceb133c9441283bb8250f532a3", - "sha256:a55e4d81c4260386f71d22294795c87609164e22b28ba0d435850fbdf82fc0c5", - "sha256:a9da45b748caad72ea4a4ed57e9cd382089f33c5ec330a804eb420a496fa760f", - "sha256:b160b9a99ecc6559d9e6d461b95c8eec21461b332f80267ad2c10394b9503496", - "sha256:b342064e647d099ca765f19672696ad50c953cac95b566af1492fd142283580f", - "sha256:b5e8590b9245803c849e09bae070a8e1ff444f45e3f0bed558dd722119eea724", - "sha256:bf75d5825ef47aa51d669b03ce635ecb84d69311e05eccea083f31c7570c9931", - "sha256:c01b59b33c7c3ba90744f2c695be571a3bd40ab2ba7f3d169ffa6db3cfba614f", - "sha256:d96a6a7d74af56feb11e9a443150216578ea07b7450f7c05df40eec90af7f4a7", - "sha256:dd0e3651d210068d13e18503d75aaa45656eef51ef0b261f891788589db2cc38", - "sha256:e167b9805de54367dcb2043519382be541117503ce99e3291cc9b41ca0a83557", - "sha256:e42029e184008a5fd3d819323345e25e2337b0ac7f5c135b7623308530209d57", - "sha256:f545c082eeb09ae678dd451a1b1dbf17babd8a0d7adea02897a76e639afca310", - "sha256:fde50062d67d805bc96f1a9ecc0d37bfc2a8f02b937d2c50824d186aa91f2419" + "sha256:1dbe1c91269f880e364526649a52eff93ac30035507ae980d2fed33aaee633ac", + "sha256:357768c2e4451ac241465157a3e929b265dfac85d9214074985b1786244f2ef3", + "sha256:3820724272f9913b597ccd13a467cc492a0da6b05df26ea09e78b171a0bb9da6", + "sha256:4391bd07606be175aafd267ef9bea87cf1b8210c787666ce82073b05f202add1", + "sha256:4aa48afdce4660b0076a00d80afa54e8a97cd49f457d68a4342d188a09451c1a", + "sha256:58459d3bad03343ac4b1b42ed14d571b8743dc80ccbf27444f266729df1d6f5b", + "sha256:5c3c8def4230e1b959671eb959083661b4a0d2e9af93ee339c7dada6759a9470", + "sha256:5f30427731561ce75d7048ac254dbe47a2ba576229250fb60f0fb74db96501a1", + "sha256:643843bcc1c50526b3a71cd2ee561cf0d8773f062c8cbaf9ffac9fdf573f83ab", + "sha256:67c261d6c0a9981820c3a149d255a76918278a6b03b6a036800359aba1256d46", + "sha256:67f21981ba2f9d7ba9ade60c9e8cbaa8cf8e9ae51673934480e45cf55e953673", + "sha256:6aaf96c7f8cebc220cdfc03f1d5a31952f027dda050e5a703a0d1c396075e3e7", + "sha256:7c4068a8c44014b2d55f3c3f574c376b2494ca9cc73d2f1bd692382b6dffe3db", + "sha256:7c7e5fa88d9ff656e067876e4736379cc962d185d5cd808014a8a928d529ef4e", + "sha256:7f5ae4f304257569ef3b948810816bc87c9146e8c446053539947eedeaa32786", + "sha256:82691fda7c3f77c90e62da69ae60b5ac08e87e775b09813559f8901a88266552", + "sha256:8737609c3bbdd48e380d463134a35ffad3b22dc56295eff6f79fd85bd0eeeb25", + "sha256:9f411b2c3f3d76bba0865b35a425157c5dcf54937f82bbeb3d3c180789dd66a6", + "sha256:a6be4cb0ef3b8c9250c19cc122267263093eee7edd4e3fa75395dfda8c17a8e2", + "sha256:bcb238c9c96c00d3085b264e5c1a1207672577b93fa666c3b14a45240b14123a", + "sha256:bf2ec4b75d0e9356edea834d1de42b31fe11f726a81dfb2c2112bc1eaa508fcf", + "sha256:d136337ae3cc69aa5e447e78d8e1514be8c3ec9b54264e680cf0b4bd9011574f", + "sha256:d4bf4d43077db55589ffc9009c0ba0a94fa4908b9586d6ccce2e0b164c86303c", + "sha256:d6a96eef20f639e6a97d23e57dd0c1b1069a7b4fd7027482a4c5c451cd7732f4", + "sha256:d9caa9d5e682102453d96a0ee10c7241b72859b01a941a397fd965f23b3e016b", + "sha256:dd1c8f6bd65d07d3810b90d02eba7997e32abbdf1277a481d698969e921a3be0", + "sha256:e31f0bb5928b793169b87e3d1e070f2342b22d5245c755e2b81caa29756246c3", + "sha256:ecb55251139706669fdec2ff073c98ef8e9a84473e51e716211b41aa0f18e656", + "sha256:ee5ec40fdd06d62fe5d4084bef4fd50fd4bb6bfd2bf519365f569dc470163ab0", + "sha256:f17e562de9edf691a42ddb1eb4a5541c20dd3f9e65b09ded2beb0799c0cf29bb", + "sha256:fdffbfb6832cd0b300995a2b08b8f6fa9f6e856d562800fea9182316d99c4e8e" ], "index": "pypi", - "version": "==1.21.2" + "version": "==1.21.6" + }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "version": "==21.3" }, "pluggy": { "hashes": [ @@ -89,41 +90,47 @@ }, "py": { "hashes": [ - "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", - "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" + "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", + "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" + ], + "version": "==1.11.0" + }, + "pyparsing": { + "hashes": [ + "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", + "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" ], - "version": "==1.10.0" + "version": "==3.0.9" }, "pytest": { "hashes": [ - "sha256:3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec", - "sha256:e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660" + "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c", + "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45" ], "index": "pypi", - "version": "==3.10.1" + "version": "==7.1.2" }, - "six": { + "tomli": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" ], - "version": "==1.16.0" + "version": "==2.0.1" }, "typing-extensions": { "hashes": [ - "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e", - "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7", - "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34" + "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", + "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" ], "markers": "python_version < '3.8'", - "version": "==3.10.0.2" + "version": "==4.3.0" }, "zipp": { "hashes": [ - "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3", - "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4" + "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", + "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" ], - "version": "==3.5.0" + "version": "==3.8.0" } } } From 946a029873259aa4943b608af3c30d01282a5074 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Jul 2022 22:15:51 +0000 Subject: [PATCH 33/59] Bump numpy from 1.21.2 to 1.22.0 Bumps [numpy](https://github.com/numpy/numpy) from 1.21.2 to 1.22.0. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst) - [Commits](https://github.com/numpy/numpy/compare/v1.21.2...v1.22.0) --- updated-dependencies: - dependency-name: numpy dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- Pipfile.lock | 84 ++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index ad83ac5..1f78c84 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -20,16 +20,9 @@ "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==21.4.0" }, - "importlib-metadata": { - "hashes": [ - "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", - "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" - ], - "markers": "python_version < '3.8'", - "version": "==4.12.0" - }, "iniconfig": { "hashes": [ "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", @@ -39,46 +32,38 @@ }, "numpy": { "hashes": [ - "sha256:1dbe1c91269f880e364526649a52eff93ac30035507ae980d2fed33aaee633ac", - "sha256:357768c2e4451ac241465157a3e929b265dfac85d9214074985b1786244f2ef3", - "sha256:3820724272f9913b597ccd13a467cc492a0da6b05df26ea09e78b171a0bb9da6", - "sha256:4391bd07606be175aafd267ef9bea87cf1b8210c787666ce82073b05f202add1", - "sha256:4aa48afdce4660b0076a00d80afa54e8a97cd49f457d68a4342d188a09451c1a", - "sha256:58459d3bad03343ac4b1b42ed14d571b8743dc80ccbf27444f266729df1d6f5b", - "sha256:5c3c8def4230e1b959671eb959083661b4a0d2e9af93ee339c7dada6759a9470", - "sha256:5f30427731561ce75d7048ac254dbe47a2ba576229250fb60f0fb74db96501a1", - "sha256:643843bcc1c50526b3a71cd2ee561cf0d8773f062c8cbaf9ffac9fdf573f83ab", - "sha256:67c261d6c0a9981820c3a149d255a76918278a6b03b6a036800359aba1256d46", - "sha256:67f21981ba2f9d7ba9ade60c9e8cbaa8cf8e9ae51673934480e45cf55e953673", - "sha256:6aaf96c7f8cebc220cdfc03f1d5a31952f027dda050e5a703a0d1c396075e3e7", - "sha256:7c4068a8c44014b2d55f3c3f574c376b2494ca9cc73d2f1bd692382b6dffe3db", - "sha256:7c7e5fa88d9ff656e067876e4736379cc962d185d5cd808014a8a928d529ef4e", - "sha256:7f5ae4f304257569ef3b948810816bc87c9146e8c446053539947eedeaa32786", - "sha256:82691fda7c3f77c90e62da69ae60b5ac08e87e775b09813559f8901a88266552", - "sha256:8737609c3bbdd48e380d463134a35ffad3b22dc56295eff6f79fd85bd0eeeb25", - "sha256:9f411b2c3f3d76bba0865b35a425157c5dcf54937f82bbeb3d3c180789dd66a6", - "sha256:a6be4cb0ef3b8c9250c19cc122267263093eee7edd4e3fa75395dfda8c17a8e2", - "sha256:bcb238c9c96c00d3085b264e5c1a1207672577b93fa666c3b14a45240b14123a", - "sha256:bf2ec4b75d0e9356edea834d1de42b31fe11f726a81dfb2c2112bc1eaa508fcf", - "sha256:d136337ae3cc69aa5e447e78d8e1514be8c3ec9b54264e680cf0b4bd9011574f", - "sha256:d4bf4d43077db55589ffc9009c0ba0a94fa4908b9586d6ccce2e0b164c86303c", - "sha256:d6a96eef20f639e6a97d23e57dd0c1b1069a7b4fd7027482a4c5c451cd7732f4", - "sha256:d9caa9d5e682102453d96a0ee10c7241b72859b01a941a397fd965f23b3e016b", - "sha256:dd1c8f6bd65d07d3810b90d02eba7997e32abbdf1277a481d698969e921a3be0", - "sha256:e31f0bb5928b793169b87e3d1e070f2342b22d5245c755e2b81caa29756246c3", - "sha256:ecb55251139706669fdec2ff073c98ef8e9a84473e51e716211b41aa0f18e656", - "sha256:ee5ec40fdd06d62fe5d4084bef4fd50fd4bb6bfd2bf519365f569dc470163ab0", - "sha256:f17e562de9edf691a42ddb1eb4a5541c20dd3f9e65b09ded2beb0799c0cf29bb", - "sha256:fdffbfb6832cd0b300995a2b08b8f6fa9f6e856d562800fea9182316d99c4e8e" + "sha256:0cfe07133fd00b27edee5e6385e333e9eeb010607e8a46e1cd673f05f8596595", + "sha256:11a1f3816ea82eed4178102c56281782690ab5993251fdfd75039aad4d20385f", + "sha256:2762331de395739c91f1abb88041f94a080cb1143aeec791b3b223976228af3f", + "sha256:283d9de87c0133ef98f93dfc09fad3fb382f2a15580de75c02b5bb36a5a159a5", + "sha256:3d22662b4b10112c545c91a0741f2436f8ca979ab3d69d03d19322aa970f9695", + "sha256:41388e32e40b41dd56eb37fcaa7488b2b47b0adf77c66154d6b89622c110dfe9", + "sha256:42c16cec1c8cf2728f1d539bd55aaa9d6bb48a7de2f41eb944697293ef65a559", + "sha256:47ee7a839f5885bc0c63a74aabb91f6f40d7d7b639253768c4199b37aede7982", + "sha256:5a311ee4d983c487a0ab546708edbdd759393a3dc9cd30305170149fedd23c88", + "sha256:5dc65644f75a4c2970f21394ad8bea1a844104f0fe01f278631be1c7eae27226", + "sha256:6ed0d073a9c54ac40c41a9c2d53fcc3d4d4ed607670b9e7b0de1ba13b4cbfe6f", + "sha256:76ba7c40e80f9dc815c5e896330700fd6e20814e69da9c1267d65a4d051080f1", + "sha256:818b9be7900e8dc23e013a92779135623476f44a0de58b40c32a15368c01d471", + "sha256:a024181d7aef0004d76fb3bce2a4c9f2e67a609a9e2a6ff2571d30e9976aa383", + "sha256:a955e4128ac36797aaffd49ab44ec74a71c11d6938df83b1285492d277db5397", + "sha256:a97a954a8c2f046d3817c2bce16e3c7e9a9c2afffaf0400f5c16df5172a67c9c", + "sha256:a97e82c39d9856fe7d4f9b86d8a1e66eff99cf3a8b7ba48202f659703d27c46f", + "sha256:b55b953a1bdb465f4dc181758570d321db4ac23005f90ffd2b434cc6609a63dd", + "sha256:bb02929b0d6bfab4c48a79bd805bd7419114606947ec8284476167415171f55b", + "sha256:bece0a4a49e60e472a6d1f70ac6cdea00f9ab80ff01132f96bd970cdd8a9e5a9", + "sha256:e41e8951749c4b5c9a2dc5fdbc1a4eec6ab2a140fdae9b460b0f557eed870f4d", + "sha256:f71d57cc8645f14816ae249407d309be250ad8de93ef61d9709b45a0ddf4050c" ], "index": "pypi", - "version": "==1.21.6" + "version": "==1.22.0" }, "packaging": { "hashes": [ "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" ], + "markers": "python_version >= '3.6'", "version": "==21.3" }, "pluggy": { @@ -86,6 +71,7 @@ "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], + "markers": "python_version >= '3.6'", "version": "==1.0.0" }, "py": { @@ -93,6 +79,7 @@ "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.11.0" }, "pyparsing": { @@ -100,6 +87,7 @@ "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" ], + "markers": "python_full_version >= '3.6.8'", "version": "==3.0.9" }, "pytest": { @@ -115,22 +103,8 @@ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" ], + "markers": "python_version >= '3.7'", "version": "==2.0.1" - }, - "typing-extensions": { - "hashes": [ - "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", - "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" - ], - "markers": "python_version < '3.8'", - "version": "==4.3.0" - }, - "zipp": { - "hashes": [ - "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", - "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" - ], - "version": "==3.8.0" } } } From 7e2fbc40e4080b6acd347fb420c83f483a95d976 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 00:56:56 +0200 Subject: [PATCH 34/59] Checking expectation failure cause --- tests/test_haversine_vector.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index 54f470f..b6c7d82 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -22,7 +22,8 @@ def test_normalization(): Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. """ p1, p2 = (0 - 180, -45 + 360), (0, 45) # Use same values as below - assert haversine_vector([p1], [p2], Unit.DEGREES, normalize=True) == 89.99999999999997 + res = haversine_vector([p1], [p2], Unit.DEGREES, normalize=True)[0] + assert res == 89.99999999999997 def test_haversine_vector_comb(): From 289389073cbb14d465f60c4fe0a23d4ba25a37f3 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 01:01:10 +0200 Subject: [PATCH 35/59] Using approx. for apparent numerical machine/version dependence --- tests/test_haversine_vector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index b6c7d82..ba7334b 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -23,7 +23,7 @@ def test_normalization(): """ p1, p2 = (0 - 180, -45 + 360), (0, 45) # Use same values as below res = haversine_vector([p1], [p2], Unit.DEGREES, normalize=True)[0] - assert res == 89.99999999999997 + assert res == pytest.approx(89.99999999999997, abs=1e-13) def test_haversine_vector_comb(): From a640989e4f7330836eebe2defbef0911503caf83 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 01:18:23 +0200 Subject: [PATCH 36/59] Adding tests for range check --- tests/test_haversine.py | 15 +++++++++++++++ tests/test_haversine_vector.py | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index f317ea6..b288ae7 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -1,5 +1,6 @@ from haversine import haversine, Unit from math import pi +import pytest from tests.geo_ressources import LYON, PARIS, NEW_YORK, LONDON, EXPECTED_LYON_PARIS @@ -45,6 +46,20 @@ def test_normalization(): assert haversine(p1, p2, Unit.DEGREES, normalize=True) == 89.99999999999997 +def test_out_of_bounds(): + """ + Test makes sure that a ValueError is raised when latitude or longitude values are out of bounds. + """ + with pytest.raises(ValueError): + haversine((-90.0001, 0), (0, 0), Unit.DEGREES, normalize=False) + with pytest.raises(ValueError): + haversine((0, 0), (90.0001, 0), Unit.DEGREES, normalize=False) + with pytest.raises(ValueError): + haversine((0, -180.0001), (0, 0), Unit.DEGREES, normalize=False) + with pytest.raises(ValueError): + haversine((0, 0), (0, 180.0001), Unit.DEGREES, normalize=False) + + def test_haversine_deg_rad_great_circle_distance(): """ Test makes sure the haversine functions returns the great circle distance (https://en.wikipedia.org/wiki/Great-circle_distance) between two points on a sphere. diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index ba7334b..aec25b1 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -26,6 +26,20 @@ def test_normalization(): assert res == pytest.approx(89.99999999999997, abs=1e-13) +def test_out_of_bounds(): + """ + Test makes sure that a ValueError is raised when latitude or longitude values are out of bounds. + """ + with pytest.raises(ValueError): + haversine_vector([(-90.0001, 0)], [(0, 0)], Unit.DEGREES, normalize=False) + with pytest.raises(ValueError): + haversine_vector([(0, 0)], [(90.0001, 0)], Unit.DEGREES, normalize=False) + with pytest.raises(ValueError): + haversine_vector([(0, -180.0001)], [(0, 0)], Unit.DEGREES, normalize=False) + with pytest.raises(ValueError): + haversine_vector([(0, 0)], [(0, 180.0001)], Unit.DEGREES, normalize=False) + + def test_haversine_vector_comb(): unit = Unit.KILOMETERS expected = [ From bb51b5ff8eabf65627fab353830805f2174c7dc2 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 15:16:54 +0200 Subject: [PATCH 37/59] Extending test cases --- tests/test_haversine.py | 59 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index b288ae7..bc03051 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -42,8 +42,47 @@ def test_normalization(): """ Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. """ - p1, p2 = (0 - 180, -45 + 360), (0, 45) # Use same values as below - assert haversine(p1, p2, Unit.DEGREES, normalize=True) == 89.99999999999997 + normalized, straight = ( + haversine((-90.0001, 0), (0, 0), Unit.DEGREES, normalize=True), + haversine((-89.9999, 180), (0, 0), Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine((-90.0001, 30), (0, 0), Unit.DEGREES, normalize=True), + haversine((-89.9999, -150), (0, 0), Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine((0, 0), (90.0001, 0), Unit.DEGREES, normalize=True), + haversine((0, 0), (89.9999, -180), Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine((0, 0), (90.0001, 30), Unit.DEGREES, normalize=True), + haversine((0, 0), (89.9999, -150), Unit.DEGREES, normalize=True), + ) + assert normalized == straight + + normalized, straight = ( + haversine((0, -180.0001), (0, 0), Unit.DEGREES, normalize=True), + haversine((0, 179.99990000000003), (0, 0), Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine((30, -180.0001), (0, 0), Unit.DEGREES, normalize=True), + haversine((30, 179.99990000000003), (0, 0), Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine((0, 0), (0, 180.0001), Unit.DEGREES, normalize=True), + haversine((0, 0), (0, -179.99990000000003), Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine((0, 0), (30, 180.0001), Unit.DEGREES, normalize=True), + haversine((0, 0), (30, -179.99990000000003), Unit.DEGREES, normalize=True), + ) + assert normalized == straight def test_out_of_bounds(): @@ -51,13 +90,21 @@ def test_out_of_bounds(): Test makes sure that a ValueError is raised when latitude or longitude values are out of bounds. """ with pytest.raises(ValueError): - haversine((-90.0001, 0), (0, 0), Unit.DEGREES, normalize=False) + haversine((-90.0001, 0), (0, 0)) + with pytest.raises(ValueError): + haversine((0, 0), (90.0001, 0)) + with pytest.raises(ValueError): + haversine((0, -180.0001), (0, 0)) + with pytest.raises(ValueError): + haversine((0, 0), (0, 180.0001)) + with pytest.raises(ValueError): + haversine((-90.0001, 0), (0, 0), normalize=False) with pytest.raises(ValueError): - haversine((0, 0), (90.0001, 0), Unit.DEGREES, normalize=False) + haversine((0, 0), (90.0001, 0), normalize=False) with pytest.raises(ValueError): - haversine((0, -180.0001), (0, 0), Unit.DEGREES, normalize=False) + haversine((0, -180.0001), (0, 0), normalize=False) with pytest.raises(ValueError): - haversine((0, 0), (0, 180.0001), Unit.DEGREES, normalize=False) + haversine((0, 0), (0, 180.0001), normalize=False) def test_haversine_deg_rad_great_circle_distance(): From d214c2d17f189571cc3629500ba2e0f93e26a607 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 15:17:24 +0200 Subject: [PATCH 38/59] Tiny cleanup --- tests/test_haversine.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index bc03051..040d95e 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -62,7 +62,6 @@ def test_normalization(): haversine((0, 0), (89.9999, -150), Unit.DEGREES, normalize=True), ) assert normalized == straight - normalized, straight = ( haversine((0, -180.0001), (0, 0), Unit.DEGREES, normalize=True), haversine((0, 179.99990000000003), (0, 0), Unit.DEGREES, normalize=True), From 42b265b26c8b86f58422654db1b81bace3567d08 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 15:50:43 +0200 Subject: [PATCH 39/59] Using clean values --- tests/test_haversine.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index 040d95e..2c22a42 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -64,22 +64,22 @@ def test_normalization(): assert normalized == straight normalized, straight = ( haversine((0, -180.0001), (0, 0), Unit.DEGREES, normalize=True), - haversine((0, 179.99990000000003), (0, 0), Unit.DEGREES, normalize=True), + haversine((0, 179.9999), (0, 0), Unit.DEGREES, normalize=True), ) assert normalized == straight normalized, straight = ( haversine((30, -180.0001), (0, 0), Unit.DEGREES, normalize=True), - haversine((30, 179.99990000000003), (0, 0), Unit.DEGREES, normalize=True), + haversine((30, 179.9999), (0, 0), Unit.DEGREES, normalize=True), ) assert normalized == straight normalized, straight = ( haversine((0, 0), (0, 180.0001), Unit.DEGREES, normalize=True), - haversine((0, 0), (0, -179.99990000000003), Unit.DEGREES, normalize=True), + haversine((0, 0), (0, -179.9999), Unit.DEGREES, normalize=True), ) assert normalized == straight normalized, straight = ( haversine((0, 0), (30, 180.0001), Unit.DEGREES, normalize=True), - haversine((0, 0), (30, -179.99990000000003), Unit.DEGREES, normalize=True), + haversine((0, 0), (30, -179.9999), Unit.DEGREES, normalize=True), ) assert normalized == straight From 979dd1e8118b700fc43d0c81c72f51b65e382bde Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 15:57:37 +0200 Subject: [PATCH 40/59] Extending normalization test cases to vectorized version --- tests/test_haversine_vector.py | 43 +++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index aec25b1..bff1e55 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -21,9 +21,46 @@ def test_normalization(): """ Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. """ - p1, p2 = (0 - 180, -45 + 360), (0, 45) # Use same values as below - res = haversine_vector([p1], [p2], Unit.DEGREES, normalize=True)[0] - assert res == pytest.approx(89.99999999999997, abs=1e-13) + normalized, straight = ( + haversine_vector([(-90.0001, 0)], [(0, 0)], Unit.DEGREES, normalize=True), + haversine_vector([(-89.9999, 180)], [(0, 0)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine_vector([(-90.0001, 30)], [(0, 0)], Unit.DEGREES, normalize=True), + haversine_vector([(-89.9999, -150)], [(0, 0)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine_vector([(0, 0)], [(90.0001, 0)], Unit.DEGREES, normalize=True), + haversine_vector([(0, 0)], [(89.9999, -180)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine_vector([(0, 0)], [(90.0001, 30)], Unit.DEGREES, normalize=True), + haversine_vector([(0, 0)], [(89.9999, -150)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine_vector([(0, -180.0001)], [(0, 0)], Unit.DEGREES, normalize=True), + haversine_vector([(0, 179.9999)], [(0, 0)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine_vector([(30, -180.0001)], [(0, 0)], Unit.DEGREES, normalize=True), + haversine_vector([(30, 179.9999)], [(0, 0)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine_vector([(0, 0)], [(0, 180.0001)], Unit.DEGREES, normalize=True), + haversine_vector([(0, 0)], [(0, -179.9999)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight + normalized, straight = ( + haversine_vector([(0, 0)], [(30, 180.0001)], Unit.DEGREES, normalize=True), + haversine_vector([(0, 0)], [(30, -179.9999)], Unit.DEGREES, normalize=True), + ) + assert normalized == straight def test_out_of_bounds(): From b7e74af8512eac85d3b7cb122172d3b1bed0aa44 Mon Sep 17 00:00:00 2001 From: Marius Merschformann Date: Sun, 10 Jul 2022 16:35:13 +0200 Subject: [PATCH 41/59] Using parameterized tests to condense code --- tests/test_haversine.py | 88 +++++++++++++--------------------- tests/test_haversine_vector.py | 80 +++++++++++++------------------ 2 files changed, 64 insertions(+), 104 deletions(-) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index 2c22a42..afe2fe1 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -38,72 +38,48 @@ def test_haversine_deg_rad(): assert round(haversine(p1, p2, unit=Unit.DEGREES), 13) == 180.0 -def test_normalization(): +@pytest.mark.parametrize( + "oob_from,oob_to,proper_from,proper_to", [ + ((-90.0001, 0), (0, 0), (-89.9999, 180), (0, 0)), + ((-90.0001, 30), (0, 0), (-89.9999, -150), (0, 0)), + ((0, 0), (90.0001, 0), (0, 0), (89.9999, -180)), + ((0, 0), (90.0001, 30), (0, 0), (89.9999, -150)), + ((0, -180.0001), (0, 0), (0, 179.9999), (0, 0)), + ((30, -180.0001), (0, 0), (30, 179.9999), (0, 0)), + ((0, 0), (0, 180.0001), (0, 0), (0, -179.9999)), + ((0, 0), (30, 180.0001), (0, 0), (30, -179.9999)), + ] +) +def test_normalization(oob_from, oob_to, proper_from, proper_to): """ - Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. + Test makes sure that normalization works as expected by comparing distance of out of + bounds points cases to equal cases where all points are within lat/lon ranges. The + results are expected to be equal (within some tolerance to account for numerical + issues). """ - normalized, straight = ( - haversine((-90.0001, 0), (0, 0), Unit.DEGREES, normalize=True), - haversine((-89.9999, 180), (0, 0), Unit.DEGREES, normalize=True), + normalized_during, normalized_already = ( + haversine(oob_from, oob_to, Unit.DEGREES, normalize=True), + haversine(proper_from, proper_to, Unit.DEGREES, normalize=True), ) - assert normalized == straight - normalized, straight = ( - haversine((-90.0001, 30), (0, 0), Unit.DEGREES, normalize=True), - haversine((-89.9999, -150), (0, 0), Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine((0, 0), (90.0001, 0), Unit.DEGREES, normalize=True), - haversine((0, 0), (89.9999, -180), Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine((0, 0), (90.0001, 30), Unit.DEGREES, normalize=True), - haversine((0, 0), (89.9999, -150), Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine((0, -180.0001), (0, 0), Unit.DEGREES, normalize=True), - haversine((0, 179.9999), (0, 0), Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine((30, -180.0001), (0, 0), Unit.DEGREES, normalize=True), - haversine((30, 179.9999), (0, 0), Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine((0, 0), (0, 180.0001), Unit.DEGREES, normalize=True), - haversine((0, 0), (0, -179.9999), Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine((0, 0), (30, 180.0001), Unit.DEGREES, normalize=True), - haversine((0, 0), (30, -179.9999), Unit.DEGREES, normalize=True), - ) - assert normalized == straight + assert normalized_during == pytest.approx(normalized_already, abs=1e-10) -def test_out_of_bounds(): +@pytest.mark.parametrize( + "oob_from,oob_to", [ + ((-90.0001, 0), (0, 0)), + ((0, 0), (90.0001, 0)), + ((0, -180.0001), (0, 0)), + ((0, 0), (0, 180.0001)), + ] +) +def test_out_of_bounds(oob_from, oob_to): """ Test makes sure that a ValueError is raised when latitude or longitude values are out of bounds. """ with pytest.raises(ValueError): - haversine((-90.0001, 0), (0, 0)) - with pytest.raises(ValueError): - haversine((0, 0), (90.0001, 0)) - with pytest.raises(ValueError): - haversine((0, -180.0001), (0, 0)) - with pytest.raises(ValueError): - haversine((0, 0), (0, 180.0001)) - with pytest.raises(ValueError): - haversine((-90.0001, 0), (0, 0), normalize=False) - with pytest.raises(ValueError): - haversine((0, 0), (90.0001, 0), normalize=False) - with pytest.raises(ValueError): - haversine((0, -180.0001), (0, 0), normalize=False) + haversine(oob_from, oob_to) with pytest.raises(ValueError): - haversine((0, 0), (0, 180.0001), normalize=False) + haversine(oob_from, oob_to, normalize=False) def test_haversine_deg_rad_great_circle_distance(): diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index bff1e55..0f84ce5 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -17,64 +17,48 @@ def test_lyon_paris(unit): return test_lyon_paris(unit) -def test_normalization(): +@pytest.mark.parametrize( + "oob_from,oob_to,proper_from,proper_to", [ + ((-90.0001, 0), (0, 0), (-89.9999, 180), (0, 0)), + ((-90.0001, 30), (0, 0), (-89.9999, -150), (0, 0)), + ((0, 0), (90.0001, 0), (0, 0), (89.9999, -180)), + ((0, 0), (90.0001, 30), (0, 0), (89.9999, -150)), + ((0, -180.0001), (0, 0), (0, 179.9999), (0, 0)), + ((30, -180.0001), (0, 0), (30, 179.9999), (0, 0)), + ((0, 0), (0, 180.0001), (0, 0), (0, -179.9999)), + ((0, 0), (30, 180.0001), (0, 0), (30, -179.9999)), + ] +) +def test_normalization(oob_from, oob_to, proper_from, proper_to): """ - Test makes sure that latitude values outside of [-90,90] and longitude values outside of [-180,180] are normalized into their ranges. + Test makes sure that normalization works as expected by comparing distance of out of + bounds points cases to equal cases where all points are within lat/lon ranges. The + results are expected to be equal (within some tolerance to account for numerical + issues). """ - normalized, straight = ( - haversine_vector([(-90.0001, 0)], [(0, 0)], Unit.DEGREES, normalize=True), - haversine_vector([(-89.9999, 180)], [(0, 0)], Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine_vector([(-90.0001, 30)], [(0, 0)], Unit.DEGREES, normalize=True), - haversine_vector([(-89.9999, -150)], [(0, 0)], Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine_vector([(0, 0)], [(90.0001, 0)], Unit.DEGREES, normalize=True), - haversine_vector([(0, 0)], [(89.9999, -180)], Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine_vector([(0, 0)], [(90.0001, 30)], Unit.DEGREES, normalize=True), - haversine_vector([(0, 0)], [(89.9999, -150)], Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine_vector([(0, -180.0001)], [(0, 0)], Unit.DEGREES, normalize=True), - haversine_vector([(0, 179.9999)], [(0, 0)], Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine_vector([(30, -180.0001)], [(0, 0)], Unit.DEGREES, normalize=True), - haversine_vector([(30, 179.9999)], [(0, 0)], Unit.DEGREES, normalize=True), + normalized_during, normalized_already = ( + haversine_vector([oob_from], [oob_to], Unit.DEGREES, normalize=True), + haversine_vector([proper_from], [proper_to], Unit.DEGREES, normalize=True), ) - assert normalized == straight - normalized, straight = ( - haversine_vector([(0, 0)], [(0, 180.0001)], Unit.DEGREES, normalize=True), - haversine_vector([(0, 0)], [(0, -179.9999)], Unit.DEGREES, normalize=True), - ) - assert normalized == straight - normalized, straight = ( - haversine_vector([(0, 0)], [(30, 180.0001)], Unit.DEGREES, normalize=True), - haversine_vector([(0, 0)], [(30, -179.9999)], Unit.DEGREES, normalize=True), - ) - assert normalized == straight + assert normalized_during == pytest.approx(normalized_already, abs=1e-10) -def test_out_of_bounds(): +@pytest.mark.parametrize( + "oob_from,oob_to", [ + ((-90.0001, 0), (0, 0)), + ((0, 0), (90.0001, 0)), + ((0, -180.0001), (0, 0)), + ((0, 0), (0, 180.0001)), + ] +) +def test_out_of_bounds(oob_from, oob_to): """ Test makes sure that a ValueError is raised when latitude or longitude values are out of bounds. """ with pytest.raises(ValueError): - haversine_vector([(-90.0001, 0)], [(0, 0)], Unit.DEGREES, normalize=False) - with pytest.raises(ValueError): - haversine_vector([(0, 0)], [(90.0001, 0)], Unit.DEGREES, normalize=False) - with pytest.raises(ValueError): - haversine_vector([(0, -180.0001)], [(0, 0)], Unit.DEGREES, normalize=False) + haversine_vector([oob_from], [oob_to]) with pytest.raises(ValueError): - haversine_vector([(0, 0)], [(0, 180.0001)], Unit.DEGREES, normalize=False) + haversine_vector([oob_from], [oob_to], normalize=False) def test_haversine_vector_comb(): From 846d0140970979090dd917e3a652ca48d8fdf899 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 10 Jul 2022 20:36:16 +0200 Subject: [PATCH 42/59] improve makefile --- Makefile | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 108f96d..eb81ee3 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,27 @@ -.PHONY: build +.DEFAULT_GOAL := help +## clean: Clean directory for build clean: rm -rf dist/* +.PHONY: build +## build: Build package build: pipenv run python setup.py sdist bdist_wheel +## deploy: Deploy haversine to pypi deploy: clean build pipenv install twine pipenv run twine upload dist/* pipenv uninstall twine + + +.PHONY: help +## help: Prints this help text. +help: + @echo '' + @echo ' Usage:' + @echo ' make ' + @echo '' + @echo ' Targets:' + @sed -n 's/^## \?/ /p' $(MAKEFILE_LIST) From eb34dbd521ff2784291165792c1c7e6f517f9b8e Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 10 Jul 2022 20:39:47 +0200 Subject: [PATCH 43/59] changelog for 2.6.0 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 161993b..37f0720 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 2.6.0 + +- Check or normalize given lat/lon. [#49](https://github.com/mapado/haversine/issues/49) by [@uri-rodberg](https://github.com/uri-rodberg) and [@merschformann](https://github.com/merschformann) + ## 2.5.1 - Reset type hinting for `inverse_haversine` From 515854f004d883492904b47915fd681d733a2b8b Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 10 Jul 2022 20:40:02 +0200 Subject: [PATCH 44/59] =?UTF-8?q?Bump=20version:=202.5.1=20=E2=86=92=202.6?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index a387d0a..191152a 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -2,5 +2,5 @@ files = ./setup.py commit = True tag = True -current_version = 2.5.1 +current_version = 2.6.0 diff --git a/setup.py b/setup.py index bb6792d..8ae5dfe 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='haversine', - version='2.5.1', + version='2.6.0', description='Calculate the distance between 2 points on Earth.', long_description=open('README.md').read(), long_description_content_type="text/markdown", From f439d02323e883990c107bc65f6f8a899af2a404 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 10 Jul 2022 21:48:46 +0200 Subject: [PATCH 45/59] Test python-publish --- .github/workflows/python-publish.yml | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/python-publish.yml diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..e9f90f0 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,31 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + workflow_dispatch: ~ + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Publish package + run: TWINE_USERNAME=__token__ TWINE_PASSWORD=${{ secrets.TESTPIPY_HAVERSINE_TOKEN }} make deploy From 3e92106a2d1ddcb8362e3138e9f4d4438538e6ca Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 10 Jul 2022 21:52:03 +0200 Subject: [PATCH 46/59] Update python-publish.yml --- .github/workflows/python-publish.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index e9f90f0..9ff2ef2 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -10,8 +10,9 @@ name: Upload Python Package on: workflow_dispatch: ~ - release: - types: [published] + create: + tags: + - v* permissions: contents: read From 19d4bf8d5bae2bd07bde8116c84b637571b316cb Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 10 Jul 2022 23:59:07 +0200 Subject: [PATCH 47/59] Update python-publish.yml --- .github/workflows/python-publish.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 9ff2ef2..e286c44 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -25,8 +25,11 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: '3.x' + cache: 'pipenv' + - name: Install pipenv + run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python - name: Publish package run: TWINE_USERNAME=__token__ TWINE_PASSWORD=${{ secrets.TESTPIPY_HAVERSINE_TOKEN }} make deploy From 5831881e03462a104f518eb8117c6b6590bd16af Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 11 Jul 2022 00:00:47 +0200 Subject: [PATCH 48/59] Update python-publish.yml --- .github/workflows/python-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index e286c44..f014b3c 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -32,4 +32,4 @@ jobs: - name: Install pipenv run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python - name: Publish package - run: TWINE_USERNAME=__token__ TWINE_PASSWORD=${{ secrets.TESTPIPY_HAVERSINE_TOKEN }} make deploy + run: TWINE_USERNAME=__token__ TWINE_PASSWORD=${{ secrets.PIPY_HAVERSINE_TOKEN }} make deploy From 232d7d6226342aff5e51713e49360c30aad3bd52 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 11 Jul 2022 09:46:27 +0200 Subject: [PATCH 49/59] rollback pip file after build --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index eb81ee3..0dbc9a7 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ deploy: clean build pipenv install twine pipenv run twine upload dist/* pipenv uninstall twine + git checkout -- Pipfile.lock .PHONY: help From 78320df85a99b309c192a685f16f7c36b8b86c7c Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 11 Jul 2022 11:16:28 +0200 Subject: [PATCH 50/59] add test to check that "in bounds" lat/lng do not throw. --- tests/test_haversine.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_haversine.py b/tests/test_haversine.py index afe2fe1..ae93adf 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -81,6 +81,20 @@ def test_out_of_bounds(oob_from, oob_to): with pytest.raises(ValueError): haversine(oob_from, oob_to, normalize=False) +@pytest.mark.parametrize( + "in_bounds_from,in_bounds_to", [ + ((-90, 0), (0, 0)), + ((0, 0), (90, 0)), + ((0, -180), (0, 0)), + ((0, 0), (0, 180)), + ] +) +def test_in_bounds(in_bounds_from, in_bounds_to): + """ + Test makes sure that a ValueError is NOT raised when latitude or longitude values are in bounds. + """ + assert haversine(in_bounds_from, in_bounds_to) > 0 + def test_haversine_deg_rad_great_circle_distance(): """ From 91cfb1f8e9d7f1ce3299daa6d730adf1376839c0 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 11 Jul 2022 13:42:07 +0200 Subject: [PATCH 51/59] add classifier for 3.10, 3.11 and 3.12 --- setup.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8ae5dfe..9617914 100755 --- a/setup.py +++ b/setup.py @@ -24,6 +24,10 @@ 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', - 'Topic :: Scientific/Engineering :: Mathematics' + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Topic :: Scientific/Engineering :: Mathematics', + 'Topic :: Scientific/Engineering :: GIS' ], ) From b018ba71f330a8b61ef7840fb4fd01bf2813fdf2 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 11 Jul 2022 13:46:29 +0200 Subject: [PATCH 52/59] add test until python 3.12 --- .github/workflows/python-app.yml | 57 +++++++++++++++++--------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 1eb90b2..d11b981 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -5,41 +5,44 @@ name: Python application on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: build: - runs-on: ubuntu-latest - + strategy: matrix: python-version: - - 3.5 - - 3.6 - - 3.7 - - 3.8 - - 3.9 - + - '3.5' + - '3.6' + - '3.7' + - '3.8' + - '3.9' + - '3.10' + - '3.11-dev' + name: Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Install pipenv - run: | - python -m pip install --upgrade pip - pip install pipenv - - - name: Install dependencies - run: pipenv install --dev - - - name: Test with pytest - run: | - pipenv run py.test + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pipenv' + + - name: Install pipenv + run: | + python -m pip install --upgrade pip + pip install pipenv + + - name: Install dependencies + run: pipenv install --dev + + - name: Test with pytest + run: | + pipenv run py.test From 2095c67c636ecfb2b0becbc6ce301036db688248 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 11 Jul 2022 14:00:07 +0200 Subject: [PATCH 53/59] Create dependabot.yml --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..90e05c4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" From 0d29aef728bb9c20c6c757419b546ef4a942ebf4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 12:00:37 +0000 Subject: [PATCH 54/59] Bump github/codeql-action from 1 to 2 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1...v2) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e3c9c1d..6759d18 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,7 +53,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -67,4 +67,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From b6020c34c66c335ce9bcf4055f81871877a2eb9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 12:00:44 +0000 Subject: [PATCH 55/59] Bump actions/checkout from 2 to 3 Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e3c9c1d..2c62681 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL From d4b3cdfb8fe1ac4b6599477cc0b858ecaabe08e0 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Fri, 15 Jul 2022 12:03:39 +0200 Subject: [PATCH 56/59] run autopep8 --- haversine/haversine.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/haversine/haversine.py b/haversine/haversine.py index e7f694b..8140ef9 100755 --- a/haversine/haversine.py +++ b/haversine/haversine.py @@ -162,7 +162,8 @@ def haversine_vector(array1, array2, unit=Unit.KILOMETERS, comb=False, normalize # Asserts that both arrays have same dimensions if not in combination mode if not comb: if array1.shape != array2.shape: - raise IndexError("When not in combination mode, arrays must be of same size. If mode is required, use comb=True as argument.") + raise IndexError( + "When not in combination mode, arrays must be of same size. If mode is required, use comb=True as argument.") # normalize points or ensure they are proper lat/lon, i.e., in [-90, 90] and [-180, 180] if normalize: @@ -206,8 +207,10 @@ def inverse_haversine(point, distance, direction: Union[Direction, float], unit= r = get_avg_earth_radius(unit) brng = direction.value if isinstance(direction, Direction) else direction - return_lat = asin(sin(lat) * cos(d / r) + cos(lat) * sin(d / r) * cos(brng)) - return_lng = lng + atan2(sin(brng) * sin(d / r) * cos(lat), cos(d / r) - sin(lat) * sin(return_lat)) + return_lat = asin(sin(lat) * cos(d / r) + cos(lat) + * sin(d / r) * cos(brng)) + return_lng = lng + atan2(sin(brng) * sin(d / r) * + cos(lat), cos(d / r) - sin(lat) * sin(return_lat)) return_lat, return_lng = map(degrees, (return_lat, return_lng)) return return_lat, return_lng From e71ddf41d12c6077790a389bc7a9b8b937dc6732 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Fri, 15 Jul 2022 12:12:05 +0200 Subject: [PATCH 57/59] Run autopep8 on tests --- tests/geo_ressources.py | 18 +++++++++--------- tests/test_haversine.py | 2 ++ tests/test_haversine_vector.py | 10 +++++++--- tests/test_inverse_haversine.py | 10 +++++++--- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/tests/geo_ressources.py b/tests/geo_ressources.py index 7069642..a23fc18 100644 --- a/tests/geo_ressources.py +++ b/tests/geo_ressources.py @@ -6,16 +6,16 @@ LONDON = (51.509865, -0.118092) EXPECTED_LYON_PARIS = {Unit.KILOMETERS: 392.2172595594006, - Unit.METERS: 392217.2595594006, - Unit.MILES: 243.71250609539814, - Unit.NAUTICAL_MILES: 211.78037755311516, - Unit.FEET: 1286802.0326751503, - Unit.INCHES: 15441624.392102592, - Unit.RADIANS: 0.061562818679421795, - Unit.DEGREES: 3.5272896852600164} + Unit.METERS: 392217.2595594006, + Unit.MILES: 243.71250609539814, + Unit.NAUTICAL_MILES: 211.78037755311516, + Unit.FEET: 1286802.0326751503, + Unit.INCHES: 15441624.392102592, + Unit.RADIANS: 0.061562818679421795, + Unit.DEGREES: 3.5272896852600164} EXPECTED_LYON_NEW_YORK = {Unit.KILOMETERS: 6163.43638211, - Unit.METERS: 61634363.8211 } + Unit.METERS: 61634363.8211} EXPECTED_PARIS_NEW_YORK = {Unit.KILOMETERS: 5853.32898662, - Unit.METERS: 58533289.8662 } + Unit.METERS: 58533289.8662} EXPECTED_LONDON_PARIS = {Unit.KILOMETERS: 343.37455271} EXPECTED_LONDON_NEW_YORK = {Unit.KILOMETERS: 5586.48447423} diff --git a/tests/test_haversine.py b/tests/test_haversine.py index ae93adf..07fc867 100755 --- a/tests/test_haversine.py +++ b/tests/test_haversine.py @@ -4,6 +4,7 @@ from tests.geo_ressources import LYON, PARIS, NEW_YORK, LONDON, EXPECTED_LYON_PARIS + def haversine_test_factory(unit): def test(): expected = EXPECTED_LYON_PARIS[unit] @@ -81,6 +82,7 @@ def test_out_of_bounds(oob_from, oob_to): with pytest.raises(ValueError): haversine(oob_from, oob_to, normalize=False) + @pytest.mark.parametrize( "in_bounds_from,in_bounds_to", [ ((-90, 0), (0, 0)), diff --git a/tests/test_haversine_vector.py b/tests/test_haversine_vector.py index 0f84ce5..e10b080 100644 --- a/tests/test_haversine_vector.py +++ b/tests/test_haversine_vector.py @@ -4,6 +4,7 @@ from tests.geo_ressources import EXPECTED_LONDON_PARIS, EXPECTED_LYON_NEW_YORK, EXPECTED_LYON_PARIS, EXPECTED_LONDON_NEW_YORK, LYON, PARIS, NEW_YORK, LONDON + @pytest.mark.parametrize( 'unit', [Unit.KILOMETERS, Unit.METERS, Unit.INCHES] ) @@ -12,7 +13,8 @@ def test_lyon_paris(unit): expected_lyon_paris = EXPECTED_LYON_PARIS[unit] assert haversine_vector(LYON, PARIS, unit=unit) == expected_lyon_paris assert isinstance(unit.value, str) - assert haversine_vector(LYON, PARIS, unit=unit.value) == expected_lyon_paris + assert haversine_vector( + LYON, PARIS, unit=unit.value) == expected_lyon_paris return test_lyon_paris(unit) @@ -38,7 +40,8 @@ def test_normalization(oob_from, oob_to, proper_from, proper_to): """ normalized_during, normalized_already = ( haversine_vector([oob_from], [oob_to], Unit.DEGREES, normalize=True), - haversine_vector([proper_from], [proper_to], Unit.DEGREES, normalize=True), + haversine_vector([proper_from], [proper_to], + Unit.DEGREES, normalize=True), ) assert normalized_during == pytest.approx(normalized_already, abs=1e-10) @@ -68,11 +71,12 @@ def test_haversine_vector_comb(): [EXPECTED_LYON_NEW_YORK[unit], EXPECTED_LONDON_NEW_YORK[unit]] ] - assert_allclose( # See https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_allclose.html#numpy.testing.assert_allclose + assert_allclose( # See https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_allclose.html#numpy.testing.assert_allclose haversine_vector([LYON, LONDON], [PARIS, NEW_YORK], unit, comb=True), expected ) + def test_units_enum(): from haversine.haversine import _CONVERSIONS assert all(unit in _CONVERSIONS for unit in Unit) diff --git a/tests/test_inverse_haversine.py b/tests/test_inverse_haversine.py index 34cb6fb..7538ed9 100755 --- a/tests/test_inverse_haversine.py +++ b/tests/test_inverse_haversine.py @@ -5,6 +5,7 @@ from tests.geo_ressources import LYON, PARIS, NEW_YORK, LONDON + @pytest.mark.parametrize( "point, dir, dist, result", [ @@ -18,7 +19,8 @@ ], ) def test_inverse_kilometers(point, dir, dist, result): - assert isclose(inverse_haversine(point, dist, dir), result, rtol=1e-5).all() + assert isclose(inverse_haversine(point, dist, dir), + result, rtol=1e-5).all() @pytest.mark.parametrize( @@ -36,8 +38,10 @@ def test_back_and_forth(point, direction, distance, unit): def test_inverse_miles(): - assert isclose(inverse_haversine(PARIS, 50, Direction.NORTH, unit=Unit.MILES), (49.5803579218996, 2.3508), rtol=1e-5).all() + assert isclose(inverse_haversine(PARIS, 50, Direction.NORTH, + unit=Unit.MILES), (49.5803579218996, 2.3508), rtol=1e-5).all() def test_nautical_inverse_miles(): - assert isclose(inverse_haversine(PARIS, 10, Direction.SOUTH, unit=Unit.NAUTICAL_MILES), (48.69014586638915, 2.3508), rtol=1e-5).all() + assert isclose(inverse_haversine(PARIS, 10, Direction.SOUTH, + unit=Unit.NAUTICAL_MILES), (48.69014586638915, 2.3508), rtol=1e-5).all() From dda2d859a75c06f7d4553fd67b025dc90a15b946 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Fri, 15 Jul 2022 23:36:12 +0200 Subject: [PATCH 58/59] Fix readme examples --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5fb53a4..a76b4c0 100755 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ haversine(lyon, paris) >> 392.2172595594006 # in kilometers haversine(lyon, paris, unit=Unit.MILES) ->> 243.71201856934454 # in miles +>> 243.71250609539814 # in miles # you can also use the string abbreviation for units: haversine(lyon, paris, unit='mi') ->> 243.71201856934454 # in miles +>> 243.71250609539814 # in miles haversine(lyon, paris, unit=Unit.NAUTICAL_MILES) >> 211.78037755311516 # in nautical miles @@ -51,38 +51,39 @@ outputs , ) ``` - #### Note for radians and degrees The radian and degrees returns the [great circle distance](https://en.wikipedia.org/wiki/Great-circle_distance) between two points on a sphere. Notes: - - on a unit-sphere the angular distance in radians equals the distance between the two points on the sphere (definition of radians) - - When using "degree", this angle is just converted from radians to degrees +- on a unit-sphere the angular distance in radians equals the distance between the two points on the sphere (definition of radians) +- When using "degree", this angle is just converted from radians to degrees ### Inverse Haversine Formula + Calculates a point from a given vector (distance and direction) and start point. Currently explicitly supports both cardinal (north, east, south, west) and intercardinal (northeast, southeast, southwest, northwest) directions. But also allows for explicit angles expressed in Radians. ## Example: Finding arbitary point from Paris + ```python from haversine import inverse_haversine, Direction from math import pi paris = (48.8567, 2.3508) # (lat, lon) # Finding 32 km west of Paris inverse_haversine(paris, 32, Direction.WEST) -# returns tuple (49.1444, 2.3508) +# returns tuple (48.85587279023947, 1.9134085092836945) # Finding 32 km southwest of Paris inverse_haversine(paris, 32, pi * 1.25) -# returns tuple (48.5377, 1.8705) +# returns tuple (48.65279552300661, 2.0427666779658806) # Finding 50 miles north of Paris inverse_haversine(paris, 50, Direction.NORTH, unit=Unit.MILES) -# returns tuple (49.5803, 2.3508) +# returns tuple (49.58035791599536, 2.3508) # Finding 10 nautical miles south of Paris inverse_haversine(paris, 10, Direction.SOUTH, unit=Unit.NAUTICAL_MILES) -# returns tuple (48.6901, 2.3508) +# returns tuple (48.690145868497645, 2.3508) ``` ### Performance optimisation for distances between all points in two vectors From 41fd2e5de233533447c63d45a90ef12c1273c212 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sun, 4 Sep 2022 13:10:46 +0200 Subject: [PATCH 59/59] =?UTF-8?q?Bump=20version:=202.6.0=20=E2=86=92=202.7?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 191152a..8d86cee 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -2,5 +2,5 @@ files = ./setup.py commit = True tag = True -current_version = 2.6.0 +current_version = 2.7.0 diff --git a/setup.py b/setup.py index 9617914..77c3c20 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='haversine', - version='2.6.0', + version='2.7.0', description='Calculate the distance between 2 points on Earth.', long_description=open('README.md').read(), long_description_content_type="text/markdown",