Linting src in backend #40
| @@ -345,7 +345,7 @@ indent-after-paren=4 | |||||||
| indent-string='    ' | indent-string='    ' | ||||||
|  |  | ||||||
| # Maximum number of characters on a single line. | # Maximum number of characters on a single line. | ||||||
| max-line-length=100 | max-line-length=105 | ||||||
|  |  | ||||||
| # Maximum number of lines in a module. | # Maximum number of lines in a module. | ||||||
| max-module-lines=1000 | max-module-lines=1000 | ||||||
| @@ -410,7 +410,6 @@ logging-modules=logging | |||||||
|  |  | ||||||
|  |  | ||||||
| [MESSAGES CONTROL] | [MESSAGES CONTROL] | ||||||
| disable=E0401 |  | ||||||
|  |  | ||||||
| # Only show warnings with the listed confidence levels. Leave empty to show | # Only show warnings with the listed confidence levels. Leave empty to show | ||||||
| # all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, | # all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, | ||||||
| @@ -439,7 +438,8 @@ disable=raw-checker-failed, | |||||||
|         deprecated-pragma, |         deprecated-pragma, | ||||||
|         use-symbolic-message-instead, |         use-symbolic-message-instead, | ||||||
|         use-implicit-booleaness-not-comparison-to-string, |         use-implicit-booleaness-not-comparison-to-string, | ||||||
|         use-implicit-booleaness-not-comparison-to-zero |         use-implicit-booleaness-not-comparison-to-zero, | ||||||
|  |         import-error | ||||||
|  |  | ||||||
| # Enable the message, report, category or checker with the given id(s). You can | # Enable the message, report, category or checker with the given id(s). You can | ||||||
| # either give multiple identifier separated by comma (,) or put this option | # either give multiple identifier separated by comma (,) or put this option | ||||||
|   | |||||||
| @@ -22,31 +22,54 @@ refiner = Refiner(optimizer=optimizer) | |||||||
|  |  | ||||||
|  |  | ||||||
| @app.post("/trip/new") | @app.post("/trip/new") | ||||||
| def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[float, float] | None = None) -> Trip: | def new_trip(preferences: Preferences, | ||||||
|  |              start: tuple[float, float], | ||||||
|  |              end: tuple[float, float] | None = None) -> Trip: | ||||||
|     """ |     """ | ||||||
|     Main function to call the optimizer. |     Main function to call the optimizer. | ||||||
|  |  | ||||||
|     Args: |     Args: | ||||||
|         preferences (Preferences)   : the preferences specified by the user as the post body |         preferences : the preferences specified by the user as the post body | ||||||
|         start (tuple)   : the coordinates of the starting point as a tuple of floats (as url query parameters) |         start       : the coordinates of the starting point | ||||||
|         end (tuple)     : the coordinates of the finishing point as a tuple of floats (as url query parameters) |         end         : the coordinates of the finishing point | ||||||
|     Returns:  |     Returns:  | ||||||
|         (uuid) : The uuid of the first landmark in the optimized route |         (uuid) : The uuid of the first landmark in the optimized route | ||||||
|     """ |     """ | ||||||
|     if preferences is None: |     if preferences is None: | ||||||
|         raise HTTPException(status_code=406, detail="Preferences not provided") |         raise HTTPException(status_code=406, | ||||||
|     if preferences.shopping.score == 0 and preferences.sightseeing.score == 0 and preferences.nature.score == 0: |                             detail="Preferences not provided or incomplete.") | ||||||
|         raise HTTPException(status_code=406, detail="All preferences are 0.") |     if (preferences.shopping.score == 0 and | ||||||
|  |         preferences.sightseeing.score == 0 and | ||||||
|  |         preferences.nature.score == 0) : | ||||||
|  |         raise HTTPException(status_code=406, | ||||||
|  |                             detail="All preferences are 0.") | ||||||
|     if start is None: |     if start is None: | ||||||
|         raise HTTPException(status_code=406, detail="Start coordinates not provided") |         raise HTTPException(status_code=406, | ||||||
|  |                             detail="Start coordinates not provided") | ||||||
|     if not (-90 <= start[0] <= 90 or -180 <= start[1] <= 180): |     if not (-90 <= start[0] <= 90 or -180 <= start[1] <= 180): | ||||||
|         raise HTTPException(status_code=423, detail="Start coordinates not in range") |         raise HTTPException(status_code=423, | ||||||
|  |                             detail="Start coordinates not in range") | ||||||
|     if end is None: |     if end is None: | ||||||
|         end = start |         end = start | ||||||
|         logger.info("No end coordinates provided. Using start=end.") |         logger.info("No end coordinates provided. Using start=end.") | ||||||
|  |  | ||||||
|     start_landmark = Landmark(name='start', type='start', location=(start[0], start[1]), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0) |     start_landmark = Landmark(name='start', | ||||||
|     end_landmark = Landmark(name='finish', type='finish', location=(end[0], end[1]), osm_type='end', osm_id=0, attractiveness=0, must_do=True, n_tags = 0) |                               type='start', | ||||||
|  |                               location=(start[0], start[1]), | ||||||
|  |                               osm_type='start', | ||||||
|  |                               osm_id=0, | ||||||
|  |                               attractiveness=0, | ||||||
|  |                               must_do=True, | ||||||
|  |                               n_tags = 0) | ||||||
|  |      | ||||||
|  |     end_landmark = Landmark(name='finish', | ||||||
|  |                             type='finish', | ||||||
|  |                             location=(end[0], end[1]), | ||||||
|  |                             osm_type='end', | ||||||
|  |                             osm_id=0, | ||||||
|  |                             attractiveness=0, | ||||||
|  |                             must_do=True, | ||||||
|  |                             n_tags = 0) | ||||||
|  |  | ||||||
|     # Generate the landmarks from the start location |     # Generate the landmarks from the start location | ||||||
|     landmarks, landmarks_short = manager.generate_landmarks_list( |     landmarks, landmarks_short = manager.generate_landmarks_list( | ||||||
| @@ -67,10 +90,12 @@ def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[fl | |||||||
|         raise HTTPException(status_code=500, detail="Optimzation took too long") from exc |         raise HTTPException(status_code=500, detail="Optimzation took too long") from exc | ||||||
|  |  | ||||||
|     # Second stage optimization |     # Second stage optimization | ||||||
|     refined_tour = refiner.refine_optimization(landmarks, base_tour, preferences.max_time_minute, preferences.detour_tolerance_minute) |     refined_tour = refiner.refine_optimization(landmarks, base_tour, | ||||||
|  |                                                preferences.max_time_minute, | ||||||
|  |                                                preferences.detour_tolerance_minute) | ||||||
|  |  | ||||||
|     linked_tour = LinkedLandmarks(refined_tour) |     linked_tour = LinkedLandmarks(refined_tour) | ||||||
|     # upon creation of the trip, persistence of both the trip and its landmarks is ensured |     # upon creation of the trip, persistence of both the trip and its landmarks is ensured. | ||||||
|     trip = Trip.from_linked_landmarks(linked_tour, cache_client) |     trip = Trip.from_linked_landmarks(linked_tour, cache_client) | ||||||
|     return trip |     return trip | ||||||
|  |  | ||||||
| @@ -109,4 +134,5 @@ def get_landmark(landmark_uuid: str) -> Landmark: | |||||||
|         landmark = cache_client.get(f"landmark_{landmark_uuid}") |         landmark = cache_client.get(f"landmark_{landmark_uuid}") | ||||||
|         return landmark |         return landmark | ||||||
|     except KeyError as exc: |     except KeyError as exc: | ||||||
|         raise HTTPException(status_code=404, detail="Landmark not found") from exc |         raise HTTPException(status_code=404, | ||||||
|  |                             detail="Landmark not found") from exc | ||||||
|   | |||||||
| @@ -70,13 +70,14 @@ class Landmark(BaseModel) : | |||||||
|             str: A formatted string with the landmark's type, name, location, attractiveness score, |             str: A formatted string with the landmark's type, name, location, attractiveness score, | ||||||
|             time to the next landmark (if available), and whether the landmark is secondary. |             time to the next landmark (if available), and whether the landmark is secondary. | ||||||
|         """ |         """ | ||||||
|         time_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else "" |         t_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else "" | ||||||
|         is_secondary_str = ", secondary" if self.is_secondary else "" |         is_secondary_str = ", secondary" if self.is_secondary else "" | ||||||
|         type_str = '(' + self.type + ')' |         type_str = '(' + self.type + ')' | ||||||
|         if self.type in ["start", "finish", "nature", "shopping"] : |         if self.type in ["start", "finish", "nature", "shopping"] : | ||||||
|             type_str += '\t ' |             type_str += '\t ' | ||||||
|  |  | ||||||
|         return f'Landmark{type_str}: [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}{is_secondary_str}]' |         return (f'Landmark{type_str}: [{self.name} @{self.location}, ' | ||||||
|  |                 f'score={self.attractiveness}{t_to_next_str}{is_secondary_str}]') | ||||||
|  |  | ||||||
|     def distance(self, value: 'Landmark') -> float: |     def distance(self, value: 'Landmark') -> float: | ||||||
|         """ |         """ | ||||||
| @@ -113,4 +114,6 @@ class Landmark(BaseModel) : | |||||||
|         # in particular, if two objects are equal, their hash must be equal |         # in particular, if two objects are equal, their hash must be equal | ||||||
|         # uuid and osm_id are just shortcuts to avoid comparing all the properties |         # uuid and osm_id are just shortcuts to avoid comparing all the properties | ||||||
|         # if they are equal, we know that the name is also equal and in turn the hash is equal |         # if they are equal, we know that the name is also equal and in turn the hash is equal | ||||||
|         return self.uuid == value.uuid or self.osm_id == value.osm_id or (self.name == value.name and self.distance(value) < 0.001) |         return (self.uuid == value.uuid or | ||||||
|  |                 self.osm_id == value.osm_id or | ||||||
|  |                 (self.name == value.name and self.distance(value) < 0.001)) | ||||||
|   | |||||||
| @@ -6,9 +6,11 @@ from ..utils.get_time_separation import get_time | |||||||
| class LinkedLandmarks: | class LinkedLandmarks: | ||||||
|     """ |     """ | ||||||
|     A list of landmarks that are linked together, e.g. in a route. |     A list of landmarks that are linked together, e.g. in a route. | ||||||
|     Each landmark serves as a node in the linked list, but since we expect these to be consumed through the rest API, |     Each landmark serves as a node in the linked list, but since we expect | ||||||
|     a pythonic reference to the next landmark is not well suited. Instead we use the uuid of the next landmark |     these to be consumed through the rest API, a pythonic reference to the next | ||||||
|     to reference the next landmark in the list. This is not very efficient, but appropriate for the expected use case |     landmark is not well suited. Instead we use the uuid of the next landmark | ||||||
|  |     to reference the next landmark in the list. This is not very efficient, | ||||||
|  |     but appropriate for the expected use case | ||||||
|     ("short" trips with onyl few landmarks). |     ("short" trips with onyl few landmarks). | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
| @@ -21,7 +23,8 @@ class LinkedLandmarks: | |||||||
|         where the first landmark is the starting point and the last landmark is the end point. |         where the first landmark is the starting point and the last landmark is the end point. | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             data (list[Landmark], optional): The list of landmarks that are linked together. Defaults to None. |             data (list[Landmark], optional):    The list of landmarks that are linked together. | ||||||
|  |                                                 Defaults to None. | ||||||
|         """ |         """ | ||||||
|         self._landmarks = data if data else [] |         self._landmarks = data if data else [] | ||||||
|         self._link_landmarks() |         self._link_landmarks() | ||||||
| @@ -29,7 +32,8 @@ class LinkedLandmarks: | |||||||
|  |  | ||||||
|     def _link_landmarks(self) -> None: |     def _link_landmarks(self) -> None: | ||||||
|         """ |         """ | ||||||
|         Create the links between the landmarks in the list by setting their .next_uuid and the .time_to_next attributes. |         Create the links between the landmarks in the list by setting their  | ||||||
|  |         .next_uuid and the .time_to_next attributes. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         # Mark secondary landmarks as such |         # Mark secondary landmarks as such | ||||||
| @@ -57,12 +61,12 @@ class LinkedLandmarks: | |||||||
|         if len(scores) >= 10: |         if len(scores) >= 10: | ||||||
|             threshold_score = scores[9] |             threshold_score = scores[9] | ||||||
|         else: |         else: | ||||||
|             # If there are fewer than 10 landmarks, use the lowest score in the list as the threshold |             # If there are fewer than 10 landmarks, use the lowest score as the threshold | ||||||
|             threshold_score = min(scores) if scores else 0 |             threshold_score = min(scores) if scores else 0 | ||||||
|  |  | ||||||
|         # Update 'is_secondary' for landmarks with attractiveness below the threshold score |         # Update 'is_secondary' for landmarks with attractiveness below the threshold score | ||||||
|         for landmark in self._landmarks: |         for landmark in self._landmarks: | ||||||
|             if landmark.attractiveness < threshold_score and landmark.type not in ["start", "finish"]: |             if (landmark.attractiveness < threshold_score and landmark.type not in ["start", "finish"]): | ||||||
|                 landmark.is_secondary = True |                 landmark.is_secondary = True | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -36,8 +36,11 @@ class Trip(BaseModel): | |||||||
|  |  | ||||||
|         # Store the trip in the cache |         # Store the trip in the cache | ||||||
|         cache_client.set(f"trip_{trip.uuid}", trip) |         cache_client.set(f"trip_{trip.uuid}", trip) | ||||||
|         # make sure to await the result (noreply=False). Otherwise the cache might not be inplace when the trip is actually requested |  | ||||||
|         cache_client.set_many({f"landmark_{landmark.uuid}": landmark for landmark in landmarks}, expire=3600, noreply=False) |         # Make sure to await the result (noreply=False). | ||||||
|  |         # Otherwise the cache might not be inplace when the trip is actually requested. | ||||||
|  |         cache_client.set_many({f"landmark_{landmark.uuid}": landmark for landmark in landmarks}, | ||||||
|  |                               expire=3600, noreply=False) | ||||||
|         # is equivalent to: |         # is equivalent to: | ||||||
|         # for landmark in landmarks: |         # for landmark in landmarks: | ||||||
|         #     cache_client.set(f"landmark_{landmark.uuid}", landmark, expire=3600) |         #     cache_client.set(f"landmark_{landmark.uuid}", landmark, expire=3600) | ||||||
|   | |||||||
| @@ -57,7 +57,11 @@ def test_bellecour(client, request) :   # pylint: disable=redefined-outer-name | |||||||
|     response = client.post( |     response = client.post( | ||||||
|         "/trip/new", |         "/trip/new", | ||||||
|         json={ |         json={ | ||||||
|             "preferences": {"sightseeing": {"type": "sightseeing", "score": 5}, "nature": {"type": "nature", "score": 5}, "shopping": {"type": "shopping", "score": 5}, "max_time_minute": duration_minutes, "detour_tolerance_minute": 0}, |             "preferences": {"sightseeing": {"type": "sightseeing", "score": 5}, | ||||||
|  |                             "nature": {"type": "nature", "score": 5}, | ||||||
|  |                             "shopping": {"type": "shopping", "score": 5}, | ||||||
|  |                             "max_time_minute": duration_minutes, | ||||||
|  |                             "detour_tolerance_minute": 0}, | ||||||
|             "start": [45.7576485, 4.8330241] |             "start": [45.7576485, 4.8330241] | ||||||
|             } |             } | ||||||
|         ) |         ) | ||||||
| @@ -79,7 +83,11 @@ def test_bellecour(client, request) :   # pylint: disable=redefined-outer-name | |||||||
| #     response = client.post( | #     response = client.post( | ||||||
| #         "/trip/new", | #         "/trip/new", | ||||||
| #         json={ | #         json={ | ||||||
| #             "preferences": {"sightseeing": {"type": "sightseeing", "score": 1}, "nature": {"type": "nature", "score": 1}, "shopping": {"type": "shopping", "score": 1}, "max_time_minute": 360, "detour_tolerance_minute": 0}, | #             "preferences": {"sightseeing": {"type": "sightseeing", "score": 1}, | ||||||
|  | #             "nature": {"type": "nature", "score": 1}, | ||||||
|  | #             "shopping": {"type": "shopping", "score": 1}, | ||||||
|  | #             "max_time_minute": 360, | ||||||
|  | #             "detour_tolerance_minute": 0}, | ||||||
| #             "start": [48.8566, 2.3522] | #             "start": [48.8566, 2.3522] | ||||||
| #             } | #             } | ||||||
| #         ) | #         ) | ||||||
|   | |||||||
| @@ -34,7 +34,8 @@ def fetch_landmark(client, landmark_uuid: str): | |||||||
|     response = client.get(f"/landmark/{landmark_uuid}") |     response = client.get(f"/landmark/{landmark_uuid}") | ||||||
|  |  | ||||||
|     if response.status_code != 200: |     if response.status_code != 200: | ||||||
|         raise HTTPException(status_code=999, detail=f"Failed to fetch landmark with UUID {landmark_uuid}: {response.status_code}") |         raise HTTPException(status_code=999, | ||||||
|  |                             detail=f"Failed to fetch landmark with UUID {landmark_uuid}: {response.status_code}") | ||||||
|  |  | ||||||
|     json_data = response.json() |     json_data = response.json() | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user