"""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