From 577ee232fc842390ce5d0fde2ff86810a7fc8000 Mon Sep 17 00:00:00 2001 From: Helldragon67 <kilian.scheidecker@orange.fr> Date: Thu, 23 Jan 2025 16:02:33 +0100 Subject: [PATCH] overpass as class --- backend/report.html | 10 +- backend/src/overpass/overpass.py | 196 +++++++++++++------------ backend/src/utils/cluster_manager.py | 21 +-- backend/src/utils/landmarks_manager.py | 18 +-- backend/src/utils/toilets_manager.py | 15 +- 5 files changed, 134 insertions(+), 126 deletions(-) diff --git a/backend/report.html b/backend/report.html index ff8c75a..806bcc0 100644 --- a/backend/report.html +++ b/backend/report.html @@ -328,7 +328,7 @@ div.media { </head> <body> <h1 id="title">Backend Testing Report</h1> - <p>Report generated on 23-Jan-2025 at 15:33:01 by <a href="https://pypi.python.org/pypi/pytest-html">pytest-html</a> + <p>Report generated on 23-Jan-2025 at 16:01:46 by <a href="https://pypi.python.org/pypi/pytest-html">pytest-html</a> v4.1.1</p> <div id="environment-header"> <h2>Environment</h2> @@ -382,7 +382,7 @@ div.media { <h2>Summary</h2> <div class="additional-summary prefix"> </div> - <p class="run-count">25 tests took 00:00:54.</p> + <p class="run-count">8 tests took 00:01:50.</p> <p class="filter">(Un)check the boxes to filter the results.</p> <div class="summary__reload"> <div class="summary__reload__button hidden" onclick="location.reload()"> @@ -393,9 +393,9 @@ div.media { <div class="controls"> <div class="filters"> <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="failed" /> - <span class="failed">3 Failed,</span> + <span class="failed">4 Failed,</span> <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="passed" /> - <span class="passed">22 Passed,</span> + <span class="passed">4 Passed,</span> <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="skipped" disabled/> <span class="skipped">0 Skipped,</span> <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="xfailed" disabled/> @@ -432,7 +432,7 @@ div.media { </table> </body> <footer> - <div id="data-container" data-jsonblob="{"environment": {"Python": "3.12.3", "Platform": "Linux-6.8.0-51-generic-x86_64-with-glibc2.39", "Packages": {"pytest": "8.3.4", "pluggy": "1.5.0"}, "Plugins": {"html": "4.1.1", "anyio": "4.8.0", "metadata": "3.1.1"}}, "tests": {"src/tests/test_invalid_input.py::test_input[start0-preferences0-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start0-preferences0-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start0-preferences0-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">67 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_invalid_input.py::test_input[start1-preferences1-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start1-preferences1-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start1-preferences1-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">2 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_invalid_input.py::test_input[start2-preferences2-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start2-preferences2-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start2-preferences2-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">2 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_invalid_input.py::test_input[start3-preferences3-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start3-preferences3-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start3-preferences3-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_invalid_input.py::test_input[start4-preferences4-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start4-preferences4-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start4-preferences4-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_invalid_input.py::test_input[start5-preferences5-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start5-preferences5-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start5-preferences5-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">5 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_invalid_input.py::test_input[start6-preferences6-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start6-preferences6-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start6-preferences6-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_invalid_input.py::test_input[start7-preferences7-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_invalid_input.py::test_input[start7-preferences7-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_invalid_input.py::test_input[start7-preferences7-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">5 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_main.py::test_turckheim": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_turckheim", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_turckheim</td>", "<td>start (0 | 0) - 4 - Square Charles Grad (47 | 5) - 3 - Porte de France (157 | 5) - 5 - finish (0 | 0) - 0</td>", "<td>22 min</td>", "<td>20 min</td>", "<td class=\"col-duration\">43 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 5 landmarks in \t: 0.004 seconds\nINFO src.main:main.py:122 Total computation time\t: 0.034 seconds\nINFO src.main:main.py:127 Generated a trip of 22 minutes with 4 landmarks in 0.038 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_bellecour": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_bellecour", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_bellecour</td>", "<td>start (0 | 0) - 5 - H\u00f4tel de l'Europe (191 | 5) - 5 - Grande Synagogue de Lyon (191 | 5) - 3 - \u00c9glise Saint-Georges (357 | 5) - 7 - Cath\u00e9drale Saint-Jean (305 | 5) - 7 - Basilique Notre-Dame de Fourvi\u00e8re (247 | 5) - 7 - Mus\u00e9es Gadagne (401 | 5) - 1 - Temple du Change (314 | 5) - 10 - Fontaine Bartholdi (305 | 5) - 10 - Basilique Saint-Bonaventure (364 | 5) - 12 - finish (0 | 0) - 0</td>", "<td>112 min</td>", "<td>120 min</td>", "<td class=\"col-duration\">00:00:06</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 182 landmarks in \t: 0.043 seconds\nINFO src.main:main.py:122 Total computation time\t: 6.003 seconds\nINFO src.main:main.py:127 Generated a trip of 112 minutes with 11 landmarks in 6.045 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_cologne": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_cologne", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_cologne</td>", "<td>start (0 | 0) - 4 - R\u00f6misch-Germanisches Museum (698 | 5) - 6 - Wallraf-Richartz-Museum & Foundation Corboud (490 | 5) - 10 - St. Maria Lyskirchen (512 | 5) - 3 - Schokoladenmuseum (581 | 5) - 19 - K\u00f6ln Triangle (571 | 5) - 20 - Deutsches Sport- und Olympiamuseum (535 | 5) - 6 - Trinitatiskirche (467 | 5) - 6 - St. Georg (404 | 5) - 6 - Wasserturm Hotel Cologne (539 | 5) - 5 - St. Peter (417 | 5) - 1 - St. C\u00e4cilien (423 | 5) - 8 - Kreissparkasse K\u00f6ln (539 | 5) - 2 - St. Aposteln (639 | 5) - 13 - St. Gereon (820 | 5) - 12 - Oper der Stadt K\u00f6ln (465 | 5) - 4 - AntoniterCityKirche (423 | 5) - 7 - Duftmuseum im Farina-Haus (539 | 5) - 7 - K\u00f6lner Dom (1141 | 5) - 5 - Museum f\u00fcr Angewandte Kunst (514 | 5) - 4 - St.Andreas (489 | 5) - 2 - Excelsior Hotel Ernst (614 | 5) - 2 - finish (0 | 0) - 0</td>", "<td>257 min</td>", "<td>240 min</td>", "<td class=\"col-duration\">00:00:01</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 244 landmarks in \t: 0.065 seconds\nINFO src.main:main.py:122 Total computation time\t: 1.244 seconds\nINFO src.main:main.py:127 Generated a trip of 257 minutes with 23 landmarks in 1.309 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_strasbourg": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_strasbourg", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_strasbourg</td>", "<td>start (0 | 0) - 8 - \u00c9glise protestante Saint-Pierre-le-Jeune (305 | 5) - 6 - H\u00f4tel de Ville (295 | 5) - 4 - De la Grande \u00eele \u00e0 la Neustadt (364 | 5) - 2 - Mus\u00e9e Tomi Ungerer Centre International de l'Illustration (210 | 5) - 9 - Mosqu\u00e9e Al Fateh (174 | 5) - 10 - \u00c9glise catholique Sainte-Madeleine (210 | 5) - 13 - Centre Administratif Ville et Eurom\u00e9tropole de Strasbourg (405 | 5) - 13 - Mus\u00e9e Historique (314 | 5) - 4 - Cath\u00e9drale Notre-Dame (564 | 5) - 8 - \u00c9glise protestante Saint-Thomas (266 | 5) - 2 - Circuit \u00ab Petite France \u00bb (364 | 5) - 10 - \u00c9glise Catholique Saint-Jean-Baptiste (247 | 5) - 1 - finish (0 | 0) - 0</td>", "<td>150 min</td>", "<td>180 min</td>", "<td class=\"col-duration\">00:00:06</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 118 landmarks in \t: 0.034 seconds\nINFO src.main:main.py:122 Total computation time\t: 5.972 seconds\nINFO src.main:main.py:127 Generated a trip of 150 minutes with 14 landmarks in 6.005 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_zurich": [{"extras": [], "result": "Failed", "testId": "src/tests/test_main.py::test_zurich", "resultsTableRow": ["<td class=\"col-result\">Failed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_zurich</td>", "<td>start (0 | 0) - 3 - Schweizerisches Landesmuseum (336 | 5) - 7 - Globus (325 | 30) - 6 - Synagoge ICZ L\u00f6wenstrasse (207 | 5) - 9 - St. Peter (379 | 5) - 3 - Fraum\u00fcnster (467 | 5) - 4 - Grossm\u00fcnster (425 | 5) - 8 - Predigerkirche (272 | 5) - 11 - Liebfrauenkirche (247 | 5) - 8 - finish (0 | 0) - 0</td>", "<td>124 min</td>", "<td>180 min</td>", "<td class=\"col-duration\">00:00:08</td>", "<td class=\"col-links\"></td>"], "log": "client = &lt;starlette.testclient.TestClient object at 0x7fc595471640&gt;, request = &lt;FixtureRequest for &lt;Function test_zurich&gt;&gt;\n\n def test_zurich(client, request) : # pylint: disable=redefined-outer-name\n &quot;&quot;&quot;\n Test n\u00b02 : Custom test in Lyon centre to ensure proper decision making in crowded area.\n \n Args:\n client:\n request:\n &quot;&quot;&quot;\n start_time = time.time() # Start timer\n duration_minutes = 180\n \n response = client.post(\n &quot;/trip/new&quot;,\n json={\n &quot;preferences&quot;: {&quot;sightseeing&quot;: {&quot;type&quot;: &quot;sightseeing&quot;, &quot;score&quot;: 5},\n &quot;nature&quot;: {&quot;type&quot;: &quot;nature&quot;, &quot;score&quot;: 5},\n &quot;shopping&quot;: {&quot;type&quot;: &quot;shopping&quot;, &quot;score&quot;: 5},\n &quot;max_time_minute&quot;: duration_minutes,\n &quot;detour_tolerance_minute&quot;: 0},\n &quot;start&quot;: [47.377884227, 8.5395114066]\n }\n )\n result = response.json()\n landmarks = load_trip_landmarks(client, result[&#x27;first_landmark_uuid&#x27;])\n \n # Get computation time\n comp_time = time.time() - start_time\n \n # Add details to report\n log_trip_details(request, landmarks, result[&#x27;total_time&#x27;], duration_minutes)\n \n # for elem in landmarks :\n # print(elem)\n \n # checks :\n assert response.status_code == 200 # check for successful planning\n assert comp_time &lt; 30, f&quot;Computation time exceeded 30 seconds: {comp_time:.2f} seconds&quot;\n&gt; assert duration_minutes*0.8 &lt; result[&#x27;total_time&#x27;], f&quot;Trip too short: {result[&#x27;total_time&#x27;]} instead of {duration_minutes}&quot;\nE AssertionError: Trip too short: 124 instead of 180\nE assert (180 * 0.8) &lt; 124\n\nsrc/tests/test_main.py:221: AssertionError\n\n------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 133 landmarks in \t: 0.028 seconds\nINFO src.main:main.py:122 Total computation time\t: 7.736 seconds\nINFO src.main:main.py:127 Generated a trip of 124 minutes with 10 landmarks in 7.763 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_paris": [{"extras": [], "result": "Failed", "testId": "src/tests/test_main.py::test_paris", "resultsTableRow": ["<td class=\"col-result\">Failed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_paris</td>", "<td>start (0 | 0) - 5 - \u00c9glise Saint-Leu - Saint-Gilles (423 | 5) - 6 - Centre Georges Pompidou (865 | 5) - 3 - \u00c9glise Saint-Merri (466 | 5) - 13 - Square Jean XXIII (367 | 5) - 1 - Cath\u00e9drale Notre-Dame de Paris (1138 | 5) - 10 - Tour Saint-Jacques (614 | 5) - 7 - Sainte-Chapelle (1138 | 5) - 1 - Palais de Justice de Paris (467 | 5) - 17 - Palais du Luxembourg (604 | 5) - 11 - \u00c9glise Saint-Germain des Pr\u00e9s (401 | 5) - 15 - Mus\u00e9e d'Orsay (890 | 5) - 11 - Palais du Louvre (690 | 5) - 1 - Mus\u00e9e du Louvre (698 | 5) - 5 - La Seine (447 | 5) - 6 - \u00c9glise Saint-Germain l'Auxerrois (512 | 5) - 5 - Temple de l'Oratoire du Louvre (651 | 5) - 4 - Bourse de Commerce \u2014 Pinault Collection (627 | 5) - 2 - Jardin Nelson Mandela (367 | 5) - 3 - finish (0 | 0) - 0</td>", "<td>216 min</td>", "<td>300 min</td>", "<td class=\"col-duration\">00:00:31</td>", "<td class=\"col-links\"></td>"], "log": "client = &lt;starlette.testclient.TestClient object at 0x7fc595471640&gt;, request = &lt;FixtureRequest for &lt;Function test_paris&gt;&gt;\n\n def test_paris(client, request) : # pylint: disable=redefined-outer-name\n &quot;&quot;&quot;\n Test n\u00b02 : Custom test in Paris (les Halles) centre to ensure proper decision making in crowded area.\n \n Args:\n client:\n request:\n &quot;&quot;&quot;\n start_time = time.time() # Start timer\n duration_minutes = 300\n \n response = client.post(\n &quot;/trip/new&quot;,\n json={\n &quot;preferences&quot;: {&quot;sightseeing&quot;: {&quot;type&quot;: &quot;sightseeing&quot;, &quot;score&quot;: 5},\n &quot;nature&quot;: {&quot;type&quot;: &quot;nature&quot;, &quot;score&quot;: 5},\n &quot;shopping&quot;: {&quot;type&quot;: &quot;shopping&quot;, &quot;score&quot;: 5},\n &quot;max_time_minute&quot;: duration_minutes,\n &quot;detour_tolerance_minute&quot;: 0},\n &quot;start&quot;: [48.86248803298562, 2.346451131285925]\n }\n )\n result = response.json()\n landmarks = load_trip_landmarks(client, result[&#x27;first_landmark_uuid&#x27;])\n \n # Get computation time\n comp_time = time.time() - start_time\n \n # Add details to report\n log_trip_details(request, landmarks, result[&#x27;total_time&#x27;], duration_minutes)\n \n # for elem in landmarks :\n # print(elem)\n \n # checks :\n assert response.status_code == 200 # check for successful planning\n&gt; assert comp_time &lt; 30, f&quot;Computation time exceeded 30 seconds: {comp_time:.2f} seconds&quot;\nE AssertionError: Computation time exceeded 30 seconds: 30.93 seconds\nE assert 30.929898500442505 &lt; 30\n\nsrc/tests/test_main.py:261: AssertionError\n\n------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 363 landmarks in \t: 0.085 seconds\nINFO src.main:main.py:122 Total computation time\t: 30.84 seconds\nINFO src.main:main.py:127 Generated a trip of 216 minutes with 20 landmarks in 30.925 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_new_york": [{"extras": [], "result": "Failed", "testId": "src/tests/test_main.py::test_new_york", "resultsTableRow": ["<td class=\"col-result\">Failed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_new_york</td>", "<td>start (0 | 0) - 6 - St. George's Church (344 | 5) - 7 - Grace Church (401 | 5) - 7 - Union Square Park (482 | 5) - 10 - Flatiron Building (604 | 5) - 5 - Cathedral of St. Sava (401 | 5) - 4 - Madison Square Park (482 | 5) - 7 - Calvary Church (357 | 5) - 17 - Saint Mark's in-the-Bowery (490 | 5) - 7 - Immaculate Conception Church (423 | 5) - 6 - St. Nicholas of Myra Orthodox Church (423 | 5) - 12 - Cathedral of the Holy Virgin Protection (344 | 5) - 6 - New Museum (314 | 5) - 8 - Capitale (627 | 5) - 9 - Saint Patrick's Old Cathedral (379 | 5) - 15 - Duarte Square (512 | 5) - 5 - Tribeca Park (386 | 5) - 4 - Albert Capsouto Park (339 | 5) - 7 - New York City Fire Museum (357 | 5) - 9 - St. Anthony of Padua Church (379 | 5) - 27 - Whitney Museum of American Art (423 | 5) - 24 - Judson Memorial Church (401 | 5) - 13 - finish (0 | 0) - 0</td>", "<td>320 min</td>", "<td>600 min</td>", "<td class=\"col-duration\">00:00:01</td>", "<td class=\"col-links\"></td>"], "log": "client = &lt;starlette.testclient.TestClient object at 0x7fc595471640&gt;\nrequest = &lt;FixtureRequest for &lt;Function test_new_york&gt;&gt;\n\n def test_new_york(client, request) : # pylint: disable=redefined-outer-name\n &quot;&quot;&quot;\n Test n\u00b02 : Custom test in New York (les Halles) centre to ensure proper decision making in crowded area.\n \n Args:\n client:\n request:\n &quot;&quot;&quot;\n start_time = time.time() # Start timer\n duration_minutes = 600\n \n response = client.post(\n &quot;/trip/new&quot;,\n json={\n &quot;preferences&quot;: {&quot;sightseeing&quot;: {&quot;type&quot;: &quot;sightseeing&quot;, &quot;score&quot;: 5},\n &quot;nature&quot;: {&quot;type&quot;: &quot;nature&quot;, &quot;score&quot;: 5},\n &quot;shopping&quot;: {&quot;type&quot;: &quot;shopping&quot;, &quot;score&quot;: 5},\n &quot;max_time_minute&quot;: duration_minutes,\n &quot;detour_tolerance_minute&quot;: 0},\n &quot;start&quot;: [40.72592726802, -73.9920434795]\n }\n )\n result = response.json()\n landmarks = load_trip_landmarks(client, result[&#x27;first_landmark_uuid&#x27;])\n \n # Get computation time\n comp_time = time.time() - start_time\n \n # Add details to report\n log_trip_details(request, landmarks, result[&#x27;total_time&#x27;], duration_minutes)\n \n # for elem in landmarks :\n # print(elem)\n \n # checks :\n assert response.status_code == 200 # check for successful planning\n assert comp_time &lt; 30, f&quot;Computation time exceeded 30 seconds: {comp_time:.2f} seconds&quot;\n&gt; assert duration_minutes*0.8 &lt; result[&#x27;total_time&#x27;], f&quot;Trip too short: {result[&#x27;total_time&#x27;]} instead of {duration_minutes}&quot;\nE AssertionError: Trip too short: 320 instead of 600\nE assert (600 * 0.8) &lt; 320\n\nsrc/tests/test_main.py:303: AssertionError\n\n------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 211 landmarks in \t: 0.043 seconds\nINFO src.main:main.py:122 Total computation time\t: 1.335 seconds\nINFO src.main:main.py:127 Generated a trip of 320 minutes with 23 landmarks in 1.378 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_shopping": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_shopping", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_shopping</td>", "<td>start (0 | 0) - 5 - Grand H\u00f4tel-Dieu (423 | 30) - 8 - Shopping Area (538 | 40) - 4 - Grand Bazar (93 | 30) - 20 - Halles de Lyon Paul Bocuse (210 | 30) - 8 - Westfield La Part-Dieu (423 | 30) - 32 - finish (0 | 0) - 0</td>", "<td>237 min</td>", "<td>240 min</td>", "<td class=\"col-duration\">432 ms</td>", "<td class=\"col-links\"></td>"], "log": "----------------------------- Captured stdout call -----------------------------\nLandmark(start): [start @(45.7576485, 4.8330241), score=0, time_to_next=5]\nLandmark(shopping): [Grand H\u00f4tel-Dieu @(45.7586955, 4.8364597), score=423, time_to_next=8]\nLandmark(shopping): [Shopping Area @(np.float64(45.76223053940519), np.float64(4.833794685873603)), score=538, time_to_next=4]\nLandmark(shopping): [Grand Bazar @(45.7632141, 4.8361975), score=93, time_to_next=20]\nLandmark(shopping): [Halles de Lyon Paul Bocuse @(45.7628282, 4.8505601), score=210, time_to_next=8]\nLandmark(shopping): [Westfield La Part-Dieu @(45.761331, 4.855676), score=423, time_to_next=32]\nLandmark(finish): [finish @(45.7576485, 4.8330241), score=0]\n\n------------------------------ Captured log call -------------------------------\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nINFO src.main:main.py:97 Fetched 7 landmarks in \t: 0.011 seconds\nINFO src.main:main.py:122 Total computation time\t: 0.417 seconds\nINFO src.main:main.py:127 Generated a trip of 237 minutes with 7 landmarks in 0.428 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_toilets.py::test_invalid_input[location0-None-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_invalid_input[location0-None-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_invalid_input[location0-None-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=%7B%7D&amp;radius= &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_toilets.py::test_invalid_input[location1-None-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_invalid_input[location1-None-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_invalid_input[location1-None-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=443&amp;radius= &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_toilets.py::test_invalid_input[location2-None-422]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_invalid_input[location2-None-422]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_invalid_input[location2-None-422]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=443&amp;location=433&amp;radius= &quot;HTTP/1.1 422 Unprocessable Entity&quot;\n\n"}], "src/tests/test_toilets.py::test_no_toilets[location0-200]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_no_toilets[location0-200]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_no_toilets[location0-200]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=48.227&amp;location=7.437 &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_toilets.py::test_no_toilets[location1-200]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_no_toilets[location1-200]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_no_toilets[location1-200]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=10.2012&amp;location=10.123 &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_toilets.py::test_no_toilets[location2-200]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_no_toilets[location2-200]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_no_toilets[location2-200]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=63.989&amp;location=-19.677 &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_toilets.py::test_toilets[location0-200]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_toilets[location0-200]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_toilets[location0-200]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">6 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=45.7576485&amp;location=4.8330241&amp;radius=600 &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_toilets.py::test_toilets[location1-200]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_toilets[location1-200]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_toilets[location1-200]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">3 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=-6.913795&amp;location=107.60278&amp;radius=600 &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_toilets.py::test_toilets[location2-200]": [{"extras": [], "result": "Passed", "testId": "src/tests/test_toilets.py::test_toilets[location2-200]", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_toilets.py::test_toilets[location2-200]</td>", "<td>N/A</td>", "<td>N/A</td>", "<td>N/A</td>", "<td class=\"col-duration\">4 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/toilets/new?location=-22.97014&amp;location=-43.18181&amp;radius=600 &quot;HTTP/1.1 200 OK&quot;\n\n"}]}, "renderCollapsed": ["passed"], "initialSort": "result", "title": "Backend Testing Report"}"></div> + <div id="data-container" data-jsonblob="{"environment": {"Python": "3.12.3", "Platform": "Linux-6.8.0-51-generic-x86_64-with-glibc2.39", "Packages": {"pytest": "8.3.4", "pluggy": "1.5.0"}, "Plugins": {"html": "4.1.1", "anyio": "4.8.0", "metadata": "3.1.1"}}, "tests": {"src/tests/test_main.py::test_turckheim": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_turckheim", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_turckheim</td>", "<td>start (0 | 0) - 4 - Square Charles Grad (47 | 5) - 3 - Porte de France (157 | 5) - 5 - finish (0 | 0) - 0</td>", "<td>22 min</td>", "<td>20 min</td>", "<td class=\"col-duration\">117 ms</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:93 Fetching sightseeing landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28);relation[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[historic](if: count_tags()&gt;5)(around:275, 48.085, 7.28);relation[historic](if: count_tags()&gt;5)(around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28);relation[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water=reflecting_pool](if: count_tags()&gt;5)(around:275, 48.085, 7.28);relation[water=reflecting_pool](if: count_tags()&gt;5)(around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28);relation[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[building=cathedral](if: count_tags()&gt;5)(around:275, 48.085, 7.28);relation[building=cathedral](if: count_tags()&gt;5)(around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 1 landmarks of type sightseeing in (285.5, 48.084588, 7.280405)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:96 Fetching sightseeing clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (way[&quot;historic&quot;~&quot;^(monument|building|yes)$&quot;](around:275, 48.085, 7.28););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:154 Detected 0 sightseeing clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:102 Sightseeing clusters done\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:106 Fetching nature landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[leisure=park](around:275, 48.085, 7.28);relation[leisure=park](around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[geological](around:275, 48.085, 7.28);relation[geological](around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:275, 48.085, 7.28);relation[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:275, 48.085, 7.28);relation[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:275, 48.085, 7.28);node[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:275, 48.085, 7.28);relation[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:275, 48.085, 7.28);relation[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 6 landmarks of type nature in (285.5, 48.084588, 7.280405)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:275, 48.085, 7.28););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 0 landmarks of type shopping in (285.5, 48.084588, 7.280405)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:275, 48.085, 7.28););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:158 Detected 0 shopping clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 5 landmarks in \t: 0.012 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 0 times, objective value : 204\nDEBUG src.optimization.refiner:refiner.py:345 Using 1 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 0 times, objective value : 204\nDEBUG src.main:main.py:120 First stage optimization\t: 0.017 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 0.019 seconds\nINFO src.main:main.py:122 Total computation time\t: 0.037 seconds\nINFO src.main:main.py:127 Generated a trip of 22 minutes with 4 landmarks in 0.049 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_bellecour": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_bellecour", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_bellecour</td>", "<td>start (0 | 0) - 5 - H\u00f4tel de l'Europe (191 | 5) - 5 - Cath\u00e9drale Saint-Jean (305 | 5) - 5 - Impasse Turquet (228 | 5) - 7 - Basilique Notre-Dame de Fourvi\u00e8re (247 | 5) - 7 - Mus\u00e9es Gadagne (401 | 5) - 1 - Temple du Change (314 | 5) - 9 - Mus\u00e9e des Beaux-Arts de Lyon (170 | 5) - 8 - Basilique Saint-Bonaventure (364 | 5) - 4 - Mus\u00e9e de l'Imprimerie et de la communication graphique (357 | 5) - 13 - finish (0 | 0) - 0</td>", "<td>109 min</td>", "<td>120 min</td>", "<td class=\"col-duration\">00:00:08</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:93 Fetching sightseeing landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83);relation[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[historic](if: count_tags()&gt;5)(around:1700, 45.76, 4.83);relation[historic](if: count_tags()&gt;5)(around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83);relation[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water=reflecting_pool](if: count_tags()&gt;5)(around:1700, 45.76, 4.83);relation[water=reflecting_pool](if: count_tags()&gt;5)(around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83);relation[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[building=cathedral](if: count_tags()&gt;5)(around:1700, 45.76, 4.83);relation[building=cathedral](if: count_tags()&gt;5)(around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 139 landmarks of type sightseeing in (1714.0, 45.7576485, 4.8330241)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:96 Fetching sightseeing clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (way[&quot;historic&quot;~&quot;^(monument|building|yes)$&quot;](around:1700, 45.76, 4.83););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 3 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:102 Sightseeing clusters done\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:106 Fetching nature landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[leisure=park](around:1700, 45.76, 4.83);relation[leisure=park](around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[geological](around:1700, 45.76, 4.83);relation[geological](around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:1700, 45.76, 4.83);relation[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:1700, 45.76, 4.83);relation[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:1700, 45.76, 4.83);node[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:1700, 45.76, 4.83);relation[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:1700, 45.76, 4.83);relation[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 67 landmarks of type nature in (1714.0, 45.7576485, 4.8330241)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:1700, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 3 landmarks of type shopping in (1714.0, 45.7576485, 4.8330241)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:1700, 45.76, 4.83););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 5 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 182 landmarks in \t: 0.06 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 2 times, objective value : 3378\nDEBUG src.optimization.refiner:refiner.py:345 Using 15 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 8 times, objective value : 2577\nDEBUG src.main:main.py:120 First stage optimization\t: 1.902 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 5.968 seconds\nINFO src.main:main.py:122 Total computation time\t: 7.87 seconds\nINFO src.main:main.py:127 Generated a trip of 109 minutes with 11 landmarks in 7.93 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_cologne": [{"extras": [], "result": "Failed", "testId": "src/tests/test_main.py::test_cologne", "resultsTableRow": ["<td class=\"col-result\">Failed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_cologne</td>", "<td>start (0 | 0) - 4 - R\u00f6misch-Germanisches Museum (698 | 5) - 5 - Gro\u00df St. Martin (512 | 5) - 10 - Trinitatiskirche (467 | 5) - 6 - St. Georg (404 | 5) - 11 - Wallraf-Richartz-Museum & Foundation Corboud (490 | 5) - 1 - Duftmuseum im Farina-Haus (539 | 5) - 7 - K\u00f6lner Dom (1141 | 5) - 3 - Excelsior Hotel Ernst (614 | 5) - 5 - Museum f\u00fcr Angewandte Kunst (514 | 5) - 6 - Oper der Stadt K\u00f6ln (465 | 5) - 6 - St. C\u00e4cilien (423 | 5) - 10 - St. Maria in der Kupfergasse (401 | 5) - 9 - St. Gereon (820 | 5) - 11 - St.Andreas (489 | 5) - 3 - St. Mari\u00e4 Himmelfahrt (401 | 5) - 10 - St. Kunibert (535 | 5) - 10 - finish (0 | 0) - 0</td>", "<td>197 min</td>", "<td>240 min</td>", "<td class=\"col-duration\">00:00:36</td>", "<td class=\"col-links\"></td>"], "log": "client = &lt;starlette.testclient.TestClient object at 0x7e8480b32a50&gt;\nrequest = &lt;FixtureRequest for &lt;Function test_cologne&gt;&gt;\n\n def test_cologne(client, request) : # pylint: disable=redefined-outer-name\n &quot;&quot;&quot;\n Test n\u00b02 : Custom test in Lyon centre to ensure proper decision making in crowded area.\n \n Args:\n client:\n request:\n &quot;&quot;&quot;\n start_time = time.time() # Start timer\n duration_minutes = 240\n \n response = client.post(\n &quot;/trip/new&quot;,\n json={\n &quot;preferences&quot;: {&quot;sightseeing&quot;: {&quot;type&quot;: &quot;sightseeing&quot;, &quot;score&quot;: 5},\n &quot;nature&quot;: {&quot;type&quot;: &quot;nature&quot;, &quot;score&quot;: 5},\n &quot;shopping&quot;: {&quot;type&quot;: &quot;shopping&quot;, &quot;score&quot;: 5},\n &quot;max_time_minute&quot;: duration_minutes,\n &quot;detour_tolerance_minute&quot;: 0},\n &quot;start&quot;: [50.942352665, 6.957777972392]\n }\n )\n result = response.json()\n landmarks = load_trip_landmarks(client, result[&#x27;first_landmark_uuid&#x27;])\n \n # Get computation time\n comp_time = time.time() - start_time\n \n # Add details to report\n log_trip_details(request, landmarks, result[&#x27;total_time&#x27;], duration_minutes)\n \n # for elem in landmarks :\n # print(elem)\n \n # checks :\n assert response.status_code == 200 # check for successful planning\n&gt; assert comp_time &lt; 30, f&quot;Computation time exceeded 30 seconds: {comp_time:.2f} seconds&quot;\nE AssertionError: Computation time exceeded 30 seconds: 35.68 seconds\nE assert 35.68478322029114 &lt; 30\n\nsrc/tests/test_main.py:138: AssertionError\n\n------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:93 Fetching sightseeing landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96);relation[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[historic](if: count_tags()&gt;5)(around:2000, 50.94, 6.96);relation[historic](if: count_tags()&gt;5)(around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96);relation[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 50.94, 6.96);relation[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96);relation[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[building=cathedral](if: count_tags()&gt;5)(around:2000, 50.94, 6.96);relation[building=cathedral](if: count_tags()&gt;5)(around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 255 landmarks of type sightseeing in (2000, 50.942352665, 6.957777972392)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:96 Fetching sightseeing clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (way[&quot;historic&quot;~&quot;^(monument|building|yes)$&quot;](around:2000, 50.94, 6.96););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:154 Detected 0 sightseeing clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:102 Sightseeing clusters done\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:106 Fetching nature landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[leisure=park](around:2000, 50.94, 6.96);relation[leisure=park](around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[geological](around:2000, 50.94, 6.96);relation[geological](around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 50.94, 6.96);relation[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 50.94, 6.96);relation[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 50.94, 6.96);node[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 50.94, 6.96);relation[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 50.94, 6.96);relation[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 49 landmarks of type nature in (2000, 50.942352665, 6.957777972392)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 50.94, 6.96););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 4 landmarks of type shopping in (2000, 50.942352665, 6.957777972392)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:2000, 50.94, 6.96););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 4 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 244 landmarks in \t: 0.078 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 2 times, objective value : 7130\nDEBUG src.optimization.refiner:refiner.py:345 Using 15 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 9 times, objective value : 8913\nDEBUG src.main:main.py:120 First stage optimization\t: 0.494 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 35.107 seconds\nINFO src.main:main.py:122 Total computation time\t: 35.602 seconds\nINFO src.main:main.py:127 Generated a trip of 197 minutes with 18 landmarks in 35.68 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_strasbourg": [{"extras": [], "result": "Failed", "testId": "src/tests/test_main.py::test_strasbourg", "resultsTableRow": ["<td class=\"col-result\">Failed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_strasbourg</td>", "<td>start (0 | 0) - 8 - \u00c9glise protestante Saint-Pierre-le-Jeune (305 | 5) - 9 - Cath\u00e9drale Notre-Dame (564 | 5) - 5 - H\u00f4tel de Ville (295 | 5) - 6 - Palais du Rhin (466 | 5) - 10 - \u00c9glise Saint-Paul (325 | 5) - 6 - Bains municipaux de Strasbourg (401 | 5) - 9 - \u00c9glise catholique Sainte-Madeleine (210 | 5) - 5 - Mus\u00e9e Historique (314 | 5) - 6 - Porte de l'H\u00f4pital (207 | 5) - 9 - Circuit \u00ab Petite France \u00bb (364 | 5) - 10 - \u00c9glise Catholique Saint-Jean-Baptiste (247 | 5) - 1 - finish (0 | 0) - 0</td>", "<td>139 min</td>", "<td>180 min</td>", "<td class=\"col-duration\">00:00:14</td>", "<td class=\"col-links\"></td>"], "log": "client = &lt;starlette.testclient.TestClient object at 0x7e8480b32a50&gt;\nrequest = &lt;FixtureRequest for &lt;Function test_strasbourg&gt;&gt;\n\n def test_strasbourg(client, request) : # pylint: disable=redefined-outer-name\n &quot;&quot;&quot;\n Test n\u00b02 : Custom test in Lyon centre to ensure proper decision making in crowded area.\n \n Args:\n client:\n request:\n &quot;&quot;&quot;\n start_time = time.time() # Start timer\n duration_minutes = 180\n \n response = client.post(\n &quot;/trip/new&quot;,\n json={\n &quot;preferences&quot;: {&quot;sightseeing&quot;: {&quot;type&quot;: &quot;sightseeing&quot;, &quot;score&quot;: 5},\n &quot;nature&quot;: {&quot;type&quot;: &quot;nature&quot;, &quot;score&quot;: 5},\n &quot;shopping&quot;: {&quot;type&quot;: &quot;shopping&quot;, &quot;score&quot;: 5},\n &quot;max_time_minute&quot;: duration_minutes,\n &quot;detour_tolerance_minute&quot;: 0},\n &quot;start&quot;: [48.5846589226, 7.74078715721]\n }\n )\n result = response.json()\n landmarks = load_trip_landmarks(client, result[&#x27;first_landmark_uuid&#x27;])\n \n # Get computation time\n comp_time = time.time() - start_time\n \n # Add details to report\n log_trip_details(request, landmarks, result[&#x27;total_time&#x27;], duration_minutes)\n \n # for elem in landmarks :\n # print(elem)\n \n # checks :\n assert response.status_code == 200 # check for successful planning\n assert comp_time &lt; 30, f&quot;Computation time exceeded 30 seconds: {comp_time:.2f} seconds&quot;\n&gt; assert duration_minutes*0.8 &lt; result[&#x27;total_time&#x27;], f&quot;Trip too short: {result[&#x27;total_time&#x27;]} instead of {duration_minutes}&quot;\nE AssertionError: Trip too short: 139 instead of 180\nE assert (180 * 0.8) &lt; 139\n\nsrc/tests/test_main.py:180: AssertionError\n\n------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:93 Fetching sightseeing landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74);relation[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[historic](if: count_tags()&gt;5)(around:2000, 48.58, 7.74);relation[historic](if: count_tags()&gt;5)(around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74);relation[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 48.58, 7.74);relation[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74);relation[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[building=cathedral](if: count_tags()&gt;5)(around:2000, 48.58, 7.74);relation[building=cathedral](if: count_tags()&gt;5)(around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 72 landmarks of type sightseeing in (2000, 48.5846589226, 7.74078715721)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:96 Fetching sightseeing clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (way[&quot;historic&quot;~&quot;^(monument|building|yes)$&quot;](around:2000, 48.58, 7.74););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:154 Detected 0 sightseeing clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:102 Sightseeing clusters done\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:106 Fetching nature landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[leisure=park](around:2000, 48.58, 7.74);relation[leisure=park](around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[geological](around:2000, 48.58, 7.74);relation[geological](around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 48.58, 7.74);relation[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 48.58, 7.74);relation[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 48.58, 7.74);node[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 48.58, 7.74);relation[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 48.58, 7.74);relation[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 99 landmarks of type nature in (2000, 48.5846589226, 7.74078715721)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.58, 7.74););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 3 landmarks of type shopping in (2000, 48.5846589226, 7.74078715721)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:2000, 48.58, 7.74););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 2 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 118 landmarks in \t: 0.038 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 4 times, objective value : 4128\nDEBUG src.optimization.refiner:refiner.py:345 Using 15 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 8 times, objective value : 3698\nDEBUG src.main:main.py:120 First stage optimization\t: 1.614 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 12.539 seconds\nINFO src.main:main.py:122 Total computation time\t: 14.153 seconds\nINFO src.main:main.py:127 Generated a trip of 139 minutes with 13 landmarks in 14.19 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_zurich": [{"extras": [], "result": "Failed", "testId": "src/tests/test_main.py::test_zurich", "resultsTableRow": ["<td class=\"col-result\">Failed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_zurich</td>", "<td>start (0 | 0) - 3 - Schweizerisches Landesmuseum (336 | 5) - 7 - Liebfrauenkirche (247 | 5) - 9 - Anlage Z\u00fcrich (174 | 5) - 9 - Kunsthaus (357 | 5) - 4 - Museum Schweizer Hotellerie und Tourismus (191 | 5) - 3 - Wasserkirche (210 | 5) - 3 - Stadthaus (191 | 5) - 6 - Ganymed (191 | 5) - 7 - Fraum\u00fcnster Kreuzgang (174 | 5) - 8 - St. Anna-Kapelle (191 | 5) - 4 - Augustinerkirche (210 | 5) - 2 - St. Peter (379 | 5) - 3 - Fraum\u00fcnster (467 | 5) - 3 - Helmhaus (314 | 5) - 1 - Grossm\u00fcnster (425 | 5) - 8 - Predigerkirche (272 | 5) - 11 - finish (0 | 0) - 0</td>", "<td>171 min</td>", "<td>180 min</td>", "<td class=\"col-duration\">00:00:46</td>", "<td class=\"col-links\"></td>"], "log": "client = &lt;starlette.testclient.TestClient object at 0x7e8480b32a50&gt;, request = &lt;FixtureRequest for &lt;Function test_zurich&gt;&gt;\n\n def test_zurich(client, request) : # pylint: disable=redefined-outer-name\n &quot;&quot;&quot;\n Test n\u00b02 : Custom test in Lyon centre to ensure proper decision making in crowded area.\n \n Args:\n client:\n request:\n &quot;&quot;&quot;\n start_time = time.time() # Start timer\n duration_minutes = 180\n \n response = client.post(\n &quot;/trip/new&quot;,\n json={\n &quot;preferences&quot;: {&quot;sightseeing&quot;: {&quot;type&quot;: &quot;sightseeing&quot;, &quot;score&quot;: 5},\n &quot;nature&quot;: {&quot;type&quot;: &quot;nature&quot;, &quot;score&quot;: 5},\n &quot;shopping&quot;: {&quot;type&quot;: &quot;shopping&quot;, &quot;score&quot;: 5},\n &quot;max_time_minute&quot;: duration_minutes,\n &quot;detour_tolerance_minute&quot;: 0},\n &quot;start&quot;: [47.377884227, 8.5395114066]\n }\n )\n result = response.json()\n landmarks = load_trip_landmarks(client, result[&#x27;first_landmark_uuid&#x27;])\n \n # Get computation time\n comp_time = time.time() - start_time\n \n # Add details to report\n log_trip_details(request, landmarks, result[&#x27;total_time&#x27;], duration_minutes)\n \n # for elem in landmarks :\n # print(elem)\n \n # checks :\n assert response.status_code == 200 # check for successful planning\n&gt; assert comp_time &lt; 30, f&quot;Computation time exceeded 30 seconds: {comp_time:.2f} seconds&quot;\nE AssertionError: Computation time exceeded 30 seconds: 45.55 seconds\nE assert 45.54829788208008 &lt; 30\n\nsrc/tests/test_main.py:220: AssertionError\n\n------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:93 Fetching sightseeing landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54);relation[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[historic](if: count_tags()&gt;5)(around:2000, 47.38, 8.54);relation[historic](if: count_tags()&gt;5)(around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54);relation[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 47.38, 8.54);relation[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54);relation[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[building=cathedral](if: count_tags()&gt;5)(around:2000, 47.38, 8.54);relation[building=cathedral](if: count_tags()&gt;5)(around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 72 landmarks of type sightseeing in (2000, 47.377884227, 8.5395114066)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:96 Fetching sightseeing clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (way[&quot;historic&quot;~&quot;^(monument|building|yes)$&quot;](around:2000, 47.38, 8.54););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:154 Detected 0 sightseeing clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:102 Sightseeing clusters done\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:106 Fetching nature landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[leisure=park](around:2000, 47.38, 8.54);relation[leisure=park](around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[geological](around:2000, 47.38, 8.54);relation[geological](around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 47.38, 8.54);relation[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 47.38, 8.54);relation[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 47.38, 8.54);node[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 47.38, 8.54);relation[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 47.38, 8.54);relation[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 62 landmarks of type nature in (2000, 47.377884227, 8.5395114066)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 47.38, 8.54););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 4 landmarks of type shopping in (2000, 47.377884227, 8.5395114066)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:2000, 47.38, 8.54););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 3 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 133 landmarks in \t: 0.038 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 5 times, objective value : 3604\nDEBUG src.optimization.refiner:refiner.py:345 Using 15 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 4 times, objective value : 4329\nDEBUG src.main:main.py:120 First stage optimization\t: 2.876 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 42.63 seconds\nINFO src.main:main.py:122 Total computation time\t: 45.506 seconds\nINFO src.main:main.py:127 Generated a trip of 171 minutes with 18 landmarks in 45.544 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_paris": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_paris", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_paris</td>", "<td>start (0 | 0) - 14 - Sainte-Chapelle (1138 | 5) - 8 - Cath\u00e9drale Notre-Dame de Paris (1138 | 5) - 4 - M\u00e9morial des Martyrs de la D\u00e9portation (364 | 5) - 20 - Bassin de l'Arsenal (827 | 5) - 22 - \u00c9glise Saint-Nicolas du Chardonnet (512 | 5) - 6 - Square Jean XXIII (367 | 5) - 6 - \u00c9glise Saint-S\u00e9verin (384 | 5) - 7 - Palais de Justice de Paris (467 | 5) - 9 - \u00c9glise Saint-Germain l'Auxerrois (512 | 5) - 8 - Pyramide du Louvre (490 | 5) - 3 - Tunnel des Tuileries (445 | 5) - 10 - Mus\u00e9e d'Orsay (890 | 5) - 13 - \u00c9glise Saint-Roch (490 | 5) - 8 - Palais du Louvre (690 | 5) - 1 - Mus\u00e9e du Louvre (698 | 5) - 5 - Temple de l'Oratoire du Louvre (651 | 5) - 4 - Bourse de Commerce \u2014 Pinault Collection (627 | 5) - 2 - Jardin Nelson Mandela (367 | 5) - 7 - \u00c9glise Saint-Leu - Saint-Gilles (423 | 5) - 6 - Centre Georges Pompidou (865 | 5) - 3 - \u00c9glise Saint-Merri (466 | 5) - 9 - finish (0 | 0) - 0</td>", "<td>280 min</td>", "<td>300 min</td>", "<td class=\"col-duration\">00:00:05</td>", "<td class=\"col-links\"></td>"], "log": "------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:93 Fetching sightseeing landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35);relation[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[historic](if: count_tags()&gt;5)(around:2000, 48.86, 2.35);relation[historic](if: count_tags()&gt;5)(around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35);relation[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 48.86, 2.35);relation[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35);relation[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[building=cathedral](if: count_tags()&gt;5)(around:2000, 48.86, 2.35);relation[building=cathedral](if: count_tags()&gt;5)(around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 317 landmarks of type sightseeing in (2000, 48.86248803298562, 2.346451131285925)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:96 Fetching sightseeing clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (way[&quot;historic&quot;~&quot;^(monument|building|yes)$&quot;](around:2000, 48.86, 2.35););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:154 Detected 0 sightseeing clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:102 Sightseeing clusters done\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:106 Fetching nature landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[leisure=park](around:2000, 48.86, 2.35);relation[leisure=park](around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[geological](around:2000, 48.86, 2.35);relation[geological](around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 48.86, 2.35);relation[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 48.86, 2.35);relation[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 48.86, 2.35);node[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 48.86, 2.35);relation[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 48.86, 2.35);relation[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 127 landmarks of type nature in (2000, 48.86248803298562, 2.346451131285925)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 48.86, 2.35););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 8 landmarks of type shopping in (2000, 48.86248803298562, 2.346451131285925)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:2000, 48.86, 2.35););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 14 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 363 landmarks in \t: 0.111 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 1 times, objective value : 8744\nDEBUG src.optimization.refiner:refiner.py:345 Using 15 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 5 times, objective value : 12811\nDEBUG src.main:main.py:120 First stage optimization\t: 0.563 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 4.514 seconds\nINFO src.main:main.py:122 Total computation time\t: 5.078 seconds\nINFO src.main:main.py:127 Generated a trip of 280 minutes with 23 landmarks in 5.188 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_new_york": [{"extras": [], "result": "Failed", "testId": "src/tests/test_main.py::test_new_york", "resultsTableRow": ["<td class=\"col-result\">Failed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_new_york</td>", "<td>start (0 | 0) - 6 - St. George's Church (344 | 5) - 7 - Grace Church (401 | 5) - 7 - Union Square Park (482 | 5) - 10 - Flatiron Building (604 | 5) - 5 - Cathedral of St. Sava (401 | 5) - 4 - Madison Square Park (482 | 5) - 7 - Calvary Church (357 | 5) - 17 - Saint Mark's in-the-Bowery (490 | 5) - 7 - Immaculate Conception Church (423 | 5) - 6 - St. Nicholas of Myra Orthodox Church (423 | 5) - 12 - Cathedral of the Holy Virgin Protection (344 | 5) - 9 - Saint Patrick's Old Cathedral (379 | 5) - 9 - Capitale (627 | 5) - 7 - Petrosino Square (334 | 5) - 13 - Tribeca Park (386 | 5) - 4 - Albert Capsouto Park (339 | 5) - 1 - Duarte Square (512 | 5) - 11 - St. Anthony of Padua Church (379 | 5) - 13 - Stonewall Inn State Historic Site (357 | 5) - 3 - St. Joseph's Church (364 | 5) - 6 - Judson Memorial Church (401 | 5) - 13 - finish (0 | 0) - 0</td>", "<td>282 min</td>", "<td>600 min</td>", "<td class=\"col-duration\">00:00:01</td>", "<td class=\"col-links\"></td>"], "log": "client = &lt;starlette.testclient.TestClient object at 0x7e8480b32a50&gt;\nrequest = &lt;FixtureRequest for &lt;Function test_new_york&gt;&gt;\n\n def test_new_york(client, request) : # pylint: disable=redefined-outer-name\n &quot;&quot;&quot;\n Test n\u00b02 : Custom test in New York (les Halles) centre to ensure proper decision making in crowded area.\n \n Args:\n client:\n request:\n &quot;&quot;&quot;\n start_time = time.time() # Start timer\n duration_minutes = 600\n \n response = client.post(\n &quot;/trip/new&quot;,\n json={\n &quot;preferences&quot;: {&quot;sightseeing&quot;: {&quot;type&quot;: &quot;sightseeing&quot;, &quot;score&quot;: 5},\n &quot;nature&quot;: {&quot;type&quot;: &quot;nature&quot;, &quot;score&quot;: 5},\n &quot;shopping&quot;: {&quot;type&quot;: &quot;shopping&quot;, &quot;score&quot;: 5},\n &quot;max_time_minute&quot;: duration_minutes,\n &quot;detour_tolerance_minute&quot;: 0},\n &quot;start&quot;: [40.72592726802, -73.9920434795]\n }\n )\n result = response.json()\n landmarks = load_trip_landmarks(client, result[&#x27;first_landmark_uuid&#x27;])\n \n # Get computation time\n comp_time = time.time() - start_time\n \n # Add details to report\n log_trip_details(request, landmarks, result[&#x27;total_time&#x27;], duration_minutes)\n \n # for elem in landmarks :\n # print(elem)\n \n # checks :\n assert response.status_code == 200 # check for successful planning\n assert comp_time &lt; 30, f&quot;Computation time exceeded 30 seconds: {comp_time:.2f} seconds&quot;\n&gt; assert duration_minutes*0.8 &lt; result[&#x27;total_time&#x27;], f&quot;Trip too short: {result[&#x27;total_time&#x27;]} instead of {duration_minutes}&quot;\nE AssertionError: Trip too short: 282 instead of 600\nE assert (600 * 0.8) &lt; 282\n\nsrc/tests/test_main.py:303: AssertionError\n\n------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:93 Fetching sightseeing landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99);relation[tourism~&quot;^(museum|attraction|gallery|artwork|aquarium)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[historic](if: count_tags()&gt;5)(around:2000, 40.73, -73.99);relation[historic](if: count_tags()&gt;5)(around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99);relation[amenity~&quot;^(planetarium|place_of_worship|fountain|townhall)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 40.73, -73.99);relation[water=reflecting_pool](if: count_tags()&gt;5)(around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99);relation[bridge~&quot;^(aqueduct|viaduct|boardwalk|cantilever|abandoned)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[building=cathedral](if: count_tags()&gt;5)(around:2000, 40.73, -73.99);relation[building=cathedral](if: count_tags()&gt;5)(around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 117 landmarks of type sightseeing in (2000, 40.72592726802, -73.9920434795)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:96 Fetching sightseeing clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (way[&quot;historic&quot;~&quot;^(monument|building|yes)$&quot;](around:2000, 40.73, -73.99););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:154 Detected 0 sightseeing clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:102 Sightseeing clusters done\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:106 Fetching nature landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[leisure=park](around:2000, 40.73, -73.99);relation[leisure=park](around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[geological](around:2000, 40.73, -73.99);relation[geological](around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 40.73, -73.99);relation[natural~&quot;^(geyser|hot_spring|arch|volcano|stone)$&quot;](around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 40.73, -73.99);relation[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 40.73, -73.99);node[tourism~&quot;^(alpine_hut|viewpoint|zoo|resort|picnic_site)$&quot;](around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 40.73, -73.99);relation[water~&quot;^(pond|lake|river|basin|stream|lagoon|rapids)$&quot;](around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 40.73, -73.99);relation[waterway~&quot;^(waterfall|river|canal|dam|dock|boatyard)$&quot;](around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 94 landmarks of type nature in (2000, 40.72592726802, -73.9920434795)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 40.73, -73.99););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 4 landmarks of type shopping in (2000, 40.72592726802, -73.9920434795)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:2000, 40.73, -73.99););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 5 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 211 landmarks in \t: 0.041 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 5 times, objective value : 5136\nDEBUG src.optimization.refiner:refiner.py:345 Using 15 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 2 times, objective value : 8829\nDEBUG src.main:main.py:120 First stage optimization\t: 1.035 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 0.212 seconds\nINFO src.main:main.py:122 Total computation time\t: 1.247 seconds\nINFO src.main:main.py:127 Generated a trip of 282 minutes with 23 landmarks in 1.288 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}], "src/tests/test_main.py::test_shopping": [{"extras": [], "result": "Passed", "testId": "src/tests/test_main.py::test_shopping", "resultsTableRow": ["<td class=\"col-result\">Passed</td>", "<td class=\"col-testId\">src/tests/test_main.py::test_shopping</td>", "<td>start (0 | 0) - 5 - Grand H\u00f4tel-Dieu (423 | 30) - 8 - Shopping Area (538 | 40) - 4 - Grand Bazar (93 | 30) - 20 - Halles de Lyon Paul Bocuse (210 | 30) - 8 - Westfield La Part-Dieu (423 | 30) - 32 - finish (0 | 0) - 0</td>", "<td>237 min</td>", "<td>240 min</td>", "<td class=\"col-duration\">499 ms</td>", "<td class=\"col-links\"></td>"], "log": "----------------------------- Captured stdout call -----------------------------\nLandmark(start): [start @(45.7576485, 4.8330241), score=0, time_to_next=5]\nLandmark(shopping): [Grand H\u00f4tel-Dieu @(45.7586955, 4.8364597), score=423, time_to_next=8]\nLandmark(shopping): [Shopping Area @(np.float64(45.76223053940519), np.float64(4.833794685873603)), score=538, time_to_next=4]\nLandmark(shopping): [Grand Bazar @(45.7632141, 4.8361975), score=93, time_to_next=20]\nLandmark(shopping): [Halles de Lyon Paul Bocuse @(45.7628282, 4.8505601), score=210, time_to_next=8]\nLandmark(shopping): [Westfield La Part-Dieu @(45.761331, 4.855676), score=423, time_to_next=32]\nLandmark(finish): [finish @(45.7576485, 4.8330241), score=0]\n\n------------------------------ Captured log call -------------------------------\nDEBUG asyncio:selector_events.py:64 Using selector: EpollSelector\nINFO src.main:main.py:65 No end coordinates provided. Using start=end.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:81 Starting to fetch landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:113 Fetching shopping landmarks...\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:205 Query: (way[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 45.76, 4.83);relation[shop~&quot;^(department_store|mall)$&quot;](if: count_tags()&gt;5)(around:2000, 45.76, 4.83););out center;\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:215 Fetched 7 landmarks of type shopping in (2000, 45.7576485, 4.8330241)\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:115 Fetching shopping clusters...\nDEBUG src.utils.cluster_manager:cluster_manager.py:104 Cluster query: (node[&quot;shop&quot;~&quot;^(bag|boutique|clothes)$&quot;](around:2000, 45.76, 4.83););out ids center;\nDEBUG src.utils.cluster_manager:cluster_manager.py:146 Found 5 different clusters.\nDEBUG src.utils.landmarks_manager:landmarks_manager.py:126 Shopping clusters done\nINFO src.main:main.py:97 Fetched 7 landmarks in \t: 0.008 seconds\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 1 times, objective value : 1687\nDEBUG src.optimization.refiner:refiner.py:345 Using 2 minor landmarks around the predicted path\nDEBUG src.optimization.optimizer:optimizer.py:568 First results are out. Looking out for circles and correcting.\nDEBUG src.optimization.optimizer:optimizer.py:605 Re-optimized 1 times, objective value : 1687\nDEBUG src.main:main.py:120 First stage optimization\t: 0.282 seconds\nDEBUG src.main:main.py:121 Second stage optimization\t: 0.204 seconds\nINFO src.main:main.py:122 Total computation time\t: 0.486 seconds\nINFO src.main:main.py:127 Generated a trip of 237 minutes with 7 landmarks in 0.494 seconds.\nINFO httpx:_client.py:1025 HTTP Request: POST http://testserver/trip/new &quot;HTTP/1.1 200 OK&quot;\n\n"}]}, "renderCollapsed": ["passed"], "initialSort": "result", "title": "Backend Testing Report"}"></div> <script> (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ const { getCollapsedCategory, setCollapsedIds } = require('./storage.js') diff --git a/backend/src/overpass/overpass.py b/backend/src/overpass/overpass.py index 3a60d7f..f46b966 100644 --- a/backend/src/overpass/overpass.py +++ b/backend/src/overpass/overpass.py @@ -5,116 +5,122 @@ import logging import xml.etree.ElementTree as ET from .caching_strategy import get_cache_key, CachingStrategy +from ..constants import OSM_CACHE_DIR + +logger = logging.getLogger('Overpass') +osm_types = List[Literal['way', 'node', 'relation']] -logger = logging.getLogger('overpass') -ElementTypes = List[Literal['way', 'node', 'relation']] - - -def build_query(area: tuple, element_types: ElementTypes, - selector: str, conditions=[], out='center'): +class Overpass : """ - Constructs a query string for the Overpass API to retrieve OpenStreetMap (OSM) data. - - Args: - area (tuple): A tuple representing the geographical search area, typically in the format - (radius, latitude, longitude). The first element is a string like "around:2000" - specifying the search radius, and the second and third elements represent - the latitude and longitude as floats or strings. - element_types (list[str]): A list of OSM element types to search for. Must be one or more of - 'Way', 'Node', or 'Relation'. - selector (str): The key or tag to filter the OSM elements (e.g., 'amenity', 'highway', etc.). - conditions (list, optional): A list of conditions to apply as additional filters for the - selected OSM elements. The conditions should be written in - the Overpass QL format, and they are combined with '&&' if - multiple are provided. Defaults to an empty list. - out (str, optional): Specifies the output type, such as 'center', 'body', or 'tags'. - Defaults to 'center'. - - Returns: - str: The constructed Overpass QL query string. - - Notes: - - If no conditions are provided, the query will just use the `selector` to filter the OSM - elements without additional constraints. - - The search area must always formatted as "(radius, lat, lon)". + Overpass class to manage the query building and sending to overpass api. + The caching strategy is a part of this class and initialized upon creation of the Overpass object. """ - if not isinstance(conditions, list) : - conditions = [conditions] - if not isinstance(element_types, list) : - element_types = [element_types] - - query = '(' - - # Round the radius to nearest 50 and coordinates to generate less queries - if area[0] > 500 : - search_radius = round(area[0] / 50) * 50 - loc = tuple((round(area[1], 2), round(area[2], 2))) - else : - search_radius = round(area[0] / 25) * 25 - loc = tuple((round(area[1], 3), round(area[2], 3))) - - search_area = f"(around:{search_radius}, {str(loc[0])}, {str(loc[1])})" - - if conditions : - conditions = '(if: ' + ' && '.join(conditions) + ')' - else : - conditions = '' - - for elem in element_types : - query += elem + '[' + selector + ']' + conditions + search_area + ';' - - query += ');' + f'out {out};' - - return query + def __init__(self, caching_strategy: str = 'XML', cache_dir: str = OSM_CACHE_DIR) : + """ + Initialize the Overpass instance with the url, headers and caching strategy. + """ + self.overpass_url = "https://overpass-api.de/api/interpreter" + self.headers = {'User-Agent': 'Mozilla/5.0 (compatible; OverpassQuery/1.0; +http://example.com)',} + self.caching_strategy = CachingStrategy.use(caching_strategy, cache_dir=cache_dir) -def send_query(query: str) -> dict: - """ - Sends the Overpass QL query to the Overpass API and returns the parsed JSON response. + def build_query(self, area: tuple, osm_types: osm_types, + selector: str, conditions=[], out='center'): + """ + Constructs a query string for the Overpass API to retrieve OpenStreetMap (OSM) data. - Args: - query (str): The Overpass QL query to be sent to the Overpass API. + Args: + area (tuple): A tuple representing the geographical search area, typically in the format + (radius, latitude, longitude). The first element is a string like "around:2000" + specifying the search radius, and the second and third elements represent + the latitude and longitude as floats or strings. + osm_types (list[str]): A list of OSM element types to search for. Must be one or more of + 'Way', 'Node', or 'Relation'. + selector (str): The key or tag to filter the OSM elements (e.g., 'amenity', 'highway', etc.). + conditions (list, optional): A list of conditions to apply as additional filters for the + selected OSM elements. The conditions should be written in + the Overpass QL format, and they are combined with '&&' if + multiple are provided. Defaults to an empty list. + out (str, optional): Specifies the output type, such as 'center', 'body', or 'tags'. + Defaults to 'center'. - Returns: - dict: The parsed JSON response from the Overpass API, or None if the request fails. - """ + Returns: + str: The constructed Overpass QL query string. - # Generate a cache key for the current query - cache_key = get_cache_key(query) + Notes: + - If no conditions are provided, the query will just use the `selector` to filter the OSM + elements without additional constraints. + - The search area must always formatted as "(radius, lat, lon)". + """ + if not isinstance(conditions, list) : + conditions = [conditions] + if not isinstance(osm_types, list) : + osm_types = [osm_types] - # Try to fetch the result from the cache - cached_response = CachingStrategy.get(cache_key) - if cached_response is not None : - logger.debug("Cache hit.") - return cached_response + query = '(' - # Define the Overpass API endpoint - overpass_url = "https://overpass-api.de/api/interpreter" + # Round the radius to nearest 50 and coordinates to generate less queries + if area[0] > 500 : + search_radius = round(area[0] / 50) * 50 + loc = tuple((round(area[1], 2), round(area[2], 2))) + else : + search_radius = round(area[0] / 25) * 25 + loc = tuple((round(area[1], 3), round(area[2], 3))) - # Prepare the data to be sent as POST request, encoded as bytes - data = urllib.parse.urlencode({'data': query}).encode('utf-8') + search_area = f"(around:{search_radius}, {str(loc[0])}, {str(loc[1])})" - # Create a custom header with a User-Agent - headers = { - 'User-Agent': 'Mozilla/5.0 (compatible; OverpassQuery/1.0; +http://example.com)', - } + if conditions : + conditions = '(if: ' + ' && '.join(conditions) + ')' + else : + conditions = '' - try: - # Create a Request object with the specified URL, data, and headers - request = urllib.request.Request(overpass_url, data=data, headers=headers) + for elem in osm_types : + query += elem + '[' + selector + ']' + conditions + search_area + ';' - # Send the request and read the response - with urllib.request.urlopen(request) as response: - # Read and decode the response - response_data = response.read().decode('utf-8') - root = ET.fromstring(response_data) + query += ');' + f'out {out};' - # Cache the response data as an ElementTree root - CachingStrategy.set(cache_key, root) - logger.debug("Response data added to cache.") + return query - return root - except urllib.error.URLError as e: - raise ConnectionError(f"Error connecting to Overpass API: {e}") from e + def send_query(self, query: str) -> dict: + """ + Sends the Overpass QL query to the Overpass API and returns the parsed JSON response. + + Args: + query (str): The Overpass QL query to be sent to the Overpass API. + + Returns: + dict: The parsed JSON response from the Overpass API, or None if the request fails. + """ + + # Generate a cache key for the current query + cache_key = get_cache_key(query) + + # Try to fetch the result from the cache + cached_response = self.caching_strategy.get(cache_key) + if cached_response is not None : + logger.debug("Cache hit.") + return cached_response + + # Prepare the data to be sent as POST request, encoded as bytes + data = urllib.parse.urlencode({'data': query}).encode('utf-8') + + try: + # Create a Request object with the specified URL, data, and headers + request = urllib.request.Request(self.overpass_url, data=data, headers=self.headers) + + # Send the request and read the response + with urllib.request.urlopen(request) as response: + # Read and decode the response + response_data = response.read().decode('utf-8') + root = ET.fromstring(response_data) + + # Cache the response data as an ElementTree root + self.caching_strategy.set(cache_key, root) + logger.debug("Response data added to cache.") + + return root + + except urllib.error.URLError as e: + raise ConnectionError(f"Error connecting to Overpass API: {e}") from e diff --git a/backend/src/utils/cluster_manager.py b/backend/src/utils/cluster_manager.py index 459dc48..8c8abfe 100644 --- a/backend/src/utils/cluster_manager.py +++ b/backend/src/utils/cluster_manager.py @@ -6,15 +6,14 @@ import numpy as np from sklearn.cluster import DBSCAN from pydantic import BaseModel -from ..overpass.overpass import build_query, send_query -from ..overpass.caching_strategy import CachingStrategy +from ..overpass.overpass import Overpass from ..structs.landmark import Landmark from .get_time_distance import get_distance from ..constants import OSM_CACHE_DIR # silence the overpass logger -logging.getLogger('overpass').setLevel(level=logging.CRITICAL) +logging.getLogger('Overpass').setLevel(level=logging.CRITICAL) class Cluster(BaseModel): @@ -79,7 +78,9 @@ class ClusterManager: Args: bbox: The bounding box coordinates (around:radius, center_lat, center_lon). """ - CachingStrategy.use('XML', cache_dir=OSM_CACHE_DIR) + # Setup the caching in the Overpass class. + self.overpass = Overpass(caching_strategy='XML', cache_dir=OSM_CACHE_DIR) + self.cluster_type = cluster_type if cluster_type == 'shopping' : @@ -94,16 +95,16 @@ class ClusterManager: raise NotImplementedError("Please choose only an available option for cluster detection") # Initialize the points for cluster detection - query = build_query( + query = self.overpass.build_query( area = bbox, - element_types = osm_types, + osm_types = osm_types, selector = sel, out = out ) self.logger.debug(f"Cluster query: {query}") try: - result = send_query(query) + result = self.overpass.send_query(query) except Exception as e: self.logger.error(f"Error fetching landmarks: {e}") @@ -243,15 +244,15 @@ class ClusterManager: osm_types = ['node', 'way', 'relation'] for sel in selectors : - query = build_query( + query = self.overpass.build_query( area = bbox, - element_types = osm_types, + osm_types = osm_types, selector = sel, out = 'ids center' ) try: - result = send_query(query) + result = self.overpass.send_query(query) except Exception as e: self.logger.error(f"Error fetching landmarks: {e}") continue diff --git a/backend/src/utils/landmarks_manager.py b/backend/src/utils/landmarks_manager.py index 600353d..e981929 100644 --- a/backend/src/utils/landmarks_manager.py +++ b/backend/src/utils/landmarks_manager.py @@ -8,13 +8,12 @@ from ..structs.preferences import Preferences from ..structs.landmark import Landmark from .take_most_important import take_most_important from .cluster_manager import ClusterManager -from ..overpass.overpass import build_query, send_query -from ..overpass.caching_strategy import CachingStrategy +from ..overpass.overpass import Overpass from ..constants import AMENITY_SELECTORS_PATH, LANDMARK_PARAMETERS_PATH, OPTIMIZER_PARAMETERS_PATH, OSM_CACHE_DIR # silence the overpass logger -logging.getLogger('overpass').setLevel(level=logging.CRITICAL) +logging.getLogger('Overpass').setLevel(level=logging.CRITICAL) class LandmarkManager: @@ -56,7 +55,8 @@ class LandmarkManager: self.walking_speed = parameters['average_walking_speed'] self.detour_factor = parameters['detour_factor'] - CachingStrategy.use('XML', cache_dir=OSM_CACHE_DIR) + # Setup the caching in the Overpass class. + self.overpass = Overpass(caching_strategy='XML', cache_dir=OSM_CACHE_DIR) self.logger.info('LandmakManager successfully initialized.') @@ -189,15 +189,15 @@ class LandmarkManager: for sel in dict_to_selector_list(amenity_selector): # self.logger.debug(f"Current selector: {sel}") - element_types = ['way', 'relation'] + osm_types = ['way', 'relation'] if 'viewpoint' in sel : query_conditions = [] - element_types.append('node') + osm_types.append('node') - query = build_query( + query = self.overpass.build_query( area = bbox, - element_types = element_types, + osm_types = osm_types, selector = sel, conditions = query_conditions, # except for nature.... out = 'center' @@ -205,7 +205,7 @@ class LandmarkManager: self.logger.debug(f"Query: {query}") try: - result = send_query(query) + result = self.overpass.send_query(query) except Exception as e: self.logger.error(f"Error fetching landmarks: {e}") continue diff --git a/backend/src/utils/toilets_manager.py b/backend/src/utils/toilets_manager.py index 11f3d52..ec59d9f 100644 --- a/backend/src/utils/toilets_manager.py +++ b/backend/src/utils/toilets_manager.py @@ -2,14 +2,13 @@ import logging import xml.etree.ElementTree as ET -from ..overpass.overpass import build_query, send_query -from ..overpass.caching_strategy import CachingStrategy +from ..overpass.overpass import Overpass from ..structs.landmark import Toilets from ..constants import OSM_CACHE_DIR # silence the overpass logger -logging.getLogger('overpass').setLevel(level=logging.CRITICAL) +logging.getLogger('Overpass').setLevel(level=logging.CRITICAL) class ToiletsManager: """ @@ -40,7 +39,9 @@ class ToiletsManager: self.radius = radius self.location = location - CachingStrategy.use('XML', cache_dir=OSM_CACHE_DIR) + + # Setup the caching in the Overpass class. + self.overpass = Overpass(caching_strategy='XML', cache_dir=OSM_CACHE_DIR) def generate_toilet_list(self) -> list[Toilets] : @@ -56,16 +57,16 @@ class ToiletsManager: osm_types = ['node', 'way', 'relation'] toilets_list = [] - query = build_query( + query = self.overpass.build_query( area = bbox, - element_types = osm_types, + osm_types = osm_types, selector = '"amenity"="toilets"', out = 'ids center tags' ) self.logger.debug(f"Query: {query}") try: - result = send_query(query) + result = self.overpass.send_query(query) except Exception as e: self.logger.error(f"Error fetching landmarks: {e}") return None