anyway/backend/src/utils/toilets_manager.py
Helldragon67 259b0d36fd
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 1m48s
Run linting on the backend code / Build (pull_request) Successful in 27s
Run testing on the backend code / Build (pull_request) Failing after 4m30s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 22s
corrcected msitakes
2025-01-23 16:22:41 +01:00

126 lines
4.4 KiB
Python

"""Module for finding public toilets around given coordinates."""
import logging
import xml.etree.ElementTree as ET
from ..overpass.overpass import Overpass, get_base_info
from ..structs.landmark import Toilets
from ..constants import OSM_CACHE_DIR
# silence the overpass logger
logging.getLogger('Overpass').setLevel(level=logging.CRITICAL)
class ToiletsManager:
"""
Manages the process of fetching and caching toilet information from
OpenStreetMap (OSM) based on a specified location and radius.
This class is responsible for:
- Fetching toilet data from OSM using Overpass API around a given set of
coordinates (latitude, longitude).
- Using a caching strategy to optimize requests by saving and retrieving
data from a local cache.
- Logging important events and errors related to data fetching.
Attributes:
logger (logging.Logger): Logger for the class to capture events.
location (tuple[float, float]): Latitude and longitude representing the
location to search around.
radius (int): The search radius in meters for finding nearby toilets.
overpass (Overpass): The Overpass API instance used to query OSM.
"""
logger = logging.getLogger(__name__)
location: tuple[float, float]
radius: int # radius in meters
def __init__(self, location: tuple[float, float], radius : int) -> None:
self.radius = radius
self.location = location
# 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] :
"""
Generates a list of toilet locations by fetching data from OpenStreetMap (OSM)
around the given coordinates stored in `self.location`.
Returns:
list[Toilets]: A list of `Toilets` objects containing detailed information
about the toilets found around the given coordinates.
"""
bbox = tuple((self.radius, self.location[0], self.location[1]))
osm_types = ['node', 'way', 'relation']
toilets_list = []
query = self.overpass.build_query(
area = bbox,
osm_types = osm_types,
selector = '"amenity"="toilets"',
out = 'ids center tags'
)
self.logger.debug(f"Query: {query}")
try:
result = self.overpass.send_query(query)
except Exception as e:
self.logger.error(f"Error fetching landmarks: {e}")
return None
toilets_list = self.xml_to_toilets(result)
return toilets_list
def xml_to_toilets(self, root: ET.Element) -> list[Toilets]:
"""
Parse the Overpass API result and extract landmarks.
This method processes the XML root element returned by the Overpass API and
extracts landmarks of types 'node', 'way', and 'relation'. It retrieves
relevant information such as name, coordinates, and tags, and converts them
into Landmark objects.
Args:
root (ET.Element): The root element of the XML response from Overpass API.
elem_type (str): The type of landmark (e.g., node, way, relation).
Returns:
list[Landmark]: A list of Landmark objects extracted from the XML data.
"""
if root is None :
return []
toilets_list = []
for osm_type in ['node', 'way', 'relation'] :
for elem in root.findall(osm_type):
# Get coordinates and append them to the points list
_, coords = get_base_info(elem, osm_type)
if coords is None :
continue
toilets = Toilets(location=coords)
# Extract tags as a dictionary
tags = {tag.get('k'): tag.get('v') for tag in elem.findall('tag')}
if 'wheelchair' in tags.keys() and tags['wheelchair'] == 'yes':
toilets.wheelchair = True
if 'changing_table' in tags.keys() and tags['changing_table'] == 'yes':
toilets.changing_table = True
if 'fee' in tags.keys() and tags['fee'] == 'yes':
toilets.fee = True
if 'opening_hours' in tags.keys() :
toilets.opening_hours = tags['opening_hours']
toilets_list.append(toilets)
return toilets_list