shorter lines
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m27s
Run linting on the backend code / Build (pull_request) Failing after 36s
Run testing on the backend code / Build (pull_request) Failing after 1m25s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 15s
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m27s
Run linting on the backend code / Build (pull_request) Failing after 36s
Run testing on the backend code / Build (pull_request) Failing after 1m25s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 15s
This commit is contained in:
parent
eec3be5122
commit
70a93c7143
@ -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()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user