Source code for geoenv.resolver
"""
*resolver.py*
The primary client-facing API for resolving spatial geometries to environmental
descriptions.
"""
import asyncio
from typing import List
import daiquiri
from geoenv.data_sources.data_source import DataSource
from geoenv.geometry import Geometry
from geoenv.response import construct_response, Response
logger = daiquiri.getLogger(__name__)
[docs]class Resolver:
"""
The Resolver class serves as the primary client-facing API for querying
environmental data. Clients configure an instance with one or more
``DataSource`` objects and use the ``resolve`` method to retrieve
environment descriptions based on geographic locations.
The results are mapped to a specified semantic resource (default: ENVO)
and returned in a structured ``Response`` object.
"""
def __init__(self, data_source: List[DataSource]):
"""
Initializes the Resolver with a list of ``DataSource`` instances.
:param data_source: A list of ``DataSource`` objects that provide
environmental data.
"""
self._data_source = data_source
@property
def data_source(self) -> List[DataSource]:
"""
Retrieves the list of configured ``DataSource`` instances.
:return: The list of data sources.
"""
return self._data_source
@data_source.setter
def data_source(self, data_source: List[DataSource]):
"""
Updates the list of ``DataSource`` instances used by the resolver.
:param data_source: A new list of data sources.
"""
self._data_source = data_source
[docs] async def resolve(
self,
geometry: Geometry,
semantic_resource: str = "ENVO",
identifier: str = None,
description: str = None,
) -> Response:
"""
Resolves a given ``Geometry`` to one or more environments using the
configured data sources. The results are mapped to a semantic resource
(e.g., ENVO) and returned as a ``Response`` object.
:param geometry: The spatial geometry to resolve.
:param semantic_resource: The semantic resource to use for mapping
(default: "ENVO").
:param identifier: An optional identifier for tracking the resolution
request.
:param description: An optional description to annotate the resolution
request.
:return: A ``Response`` object containing the resolved environmental
data.
"""
logger.info(
f"Resolving geometry with identifier: '{identifier}' and "
f"description: '{description}'"
)
try:
tasks = [item.get_environment(geometry) for item in self.data_source]
results_nested = await asyncio.gather(*tasks)
results = []
for environment in results_nested:
results.extend(environment)
result = construct_response(
geometry=geometry,
environment=results,
identifier=identifier,
description=description,
)
result.apply_term_mapping(semantic_resource)
logger.info("Resolution complete for geometry")
return result
except Exception as e:
logger.error(f"Failed to resolve geometry: {e}", exc_info=True)
result = construct_response(geometry=geometry, environment=[])
return result
# if __name__ == "__main__":
#
# import time
# from json import dumps
# from geoenv.data_sources import (WorldTerrestrialEcosystems,
# EcologicalMarineUnits,
# EcologicalCoastalUnits)
# from geoenv.resolver import Resolver
# from geoenv.geometry import Geometry
#
# start_time = time.time()
#
# # Create a geometry in GeoJSON format
# point_on_land = {"type": "Point", "coordinates": [-122.622364, 37.905931]}
# geometry = Geometry(point_on_land)
#
# # Configure the resolver with one or more data sources
# resolver = Resolver(
# data_source=[
# WorldTerrestrialEcosystems(),
# EcologicalMarineUnits(),
# EcologicalCoastalUnits(),
# ]
# )
#
# # Resolve the geometry to environmental descriptions
# response = asyncio.run(
# resolver.resolve(
# geometry,
# identifier="5b4edec5-ea5e-471a-8a3c-2c1171d59dee",
# description="Point on land",
# )
# )
#
# duration = time.time() - start_time
# print(f"requests took {duration:.2f} seconds")
#
# # The response is a GeoJSON feature with environmental properties
# print(dumps(response.data, indent=2))
#
# # Format as Schema.org
# schema_org = response.to_schema_org()