]> git.openstreetmap.org Git - nominatim.git/blobdiff - nominatim/api/types.py
switch reverse() to new Geometry datatype
[nominatim.git] / nominatim / api / types.py
index 9042e707db920ac46b2139156b3e53fcb5b6006e..7cb7b1334fc91304a6d13821d178209bcb71bf8f 100644 (file)
@@ -14,9 +14,9 @@ import dataclasses
 import enum
 import math
 from struct import unpack
 import enum
 import math
 from struct import unpack
+from binascii import unhexlify
 
 
-from geoalchemy2 import WKTElement
-import geoalchemy2.functions
+import sqlalchemy as sa
 
 from nominatim.errors import UsageError
 
 
 from nominatim.errors import UsageError
 
@@ -73,9 +73,11 @@ class Point(NamedTuple):
 
 
     @staticmethod
 
 
     @staticmethod
-    def from_wkb(wkb: bytes) -> 'Point':
+    def from_wkb(wkb: Union[str, bytes]) -> 'Point':
         """ Create a point from EWKB as returned from the database.
         """
         """ Create a point from EWKB as returned from the database.
         """
+        if isinstance(wkb, str):
+            wkb = unhexlify(wkb)
         if len(wkb) != 25:
             raise ValueError("Point wkb has unexpected length")
         if wkb[0] == 0:
         if len(wkb) != 25:
             raise ValueError("Point wkb has unexpected length")
         if wkb[0] == 0:
@@ -122,10 +124,10 @@ class Point(NamedTuple):
         return Point(x, y)
 
 
         return Point(x, y)
 
 
-    def sql_value(self) -> WKTElement:
+    def sql_value(self) -> str:
         """ Create an SQL expression for the point.
         """
         """ Create an SQL expression for the point.
         """
-        return WKTElement(f'POINT({self.x} {self.y})', srid=4326)
+        return f'POINT({self.x} {self.y})'
 
 
 
 
 
 
@@ -182,7 +184,7 @@ class Bbox:
     def sql_value(self) -> Any:
         """ Create an SQL expression for the box.
         """
     def sql_value(self) -> Any:
         """ Create an SQL expression for the box.
         """
-        return geoalchemy2.functions.ST_MakeEnvelope(*self.coords, 4326)
+        return sa.func.ST_MakeEnvelope(*self.coords, 4326)
 
 
     def contains(self, pt: Point) -> bool:
 
 
     def contains(self, pt: Point) -> bool:
@@ -193,13 +195,16 @@ class Bbox:
 
 
     @staticmethod
 
 
     @staticmethod
-    def from_wkb(wkb: Optional[bytes]) -> 'Optional[Bbox]':
+    def from_wkb(wkb: Union[None, str, bytes]) -> 'Optional[Bbox]':
         """ Create a Bbox from a bounding box polygon as returned by
             the database. Return s None if the input value is None.
         """
         if wkb is None:
             return None
 
         """ Create a Bbox from a bounding box polygon as returned by
             the database. Return s None if the input value is None.
         """
         if wkb is None:
             return None
 
+        if isinstance(wkb, str):
+            wkb = unhexlify(wkb)
+
         if len(wkb) != 97:
             raise ValueError("WKB must be a bounding box polygon")
         if wkb.startswith(WKB_BBOX_HEADER_LE):
         if len(wkb) != 97:
             raise ValueError("WKB must be a bounding box polygon")
         if wkb.startswith(WKB_BBOX_HEADER_LE):
@@ -296,16 +301,17 @@ def format_excluded(ids: Any) -> List[int]:
     """
     plist: Sequence[str]
     if isinstance(ids, str):
     """
     plist: Sequence[str]
     if isinstance(ids, str):
-        plist = ids.split(',')
+        plist = [s.strip() for s in ids.split(',')]
     elif isinstance(ids, abc.Sequence):
         plist = ids
     else:
         raise UsageError("Parameter 'excluded' needs to be a comma-separated list "
                          "or a Python list of numbers.")
     elif isinstance(ids, abc.Sequence):
         plist = ids
     else:
         raise UsageError("Parameter 'excluded' needs to be a comma-separated list "
                          "or a Python list of numbers.")
-    if any(not isinstance(i, int) or (isinstance(i, str) and not i.isdigit()) for i in plist):
+    if not all(isinstance(i, int) or
+               (isinstance(i, str) and (not i or i.isdigit())) for i in plist):
         raise UsageError("Parameter 'excluded' only takes place IDs.")
 
         raise UsageError("Parameter 'excluded' only takes place IDs.")
 
-    return [int(id) for id in plist if id]
+    return [int(id) for id in plist if id] or [0]
 
 
 def format_categories(categories: List[Tuple[str, str]]) -> List[Tuple[str, str]]:
 
 
 def format_categories(categories: List[Tuple[str, str]]) -> List[Tuple[str, str]]:
@@ -400,7 +406,8 @@ class SearchDetails(LookupDetails):
                                      )
     """ Highest address rank to return.
     """
                                      )
     """ Highest address rank to return.
     """
-    layers: Optional[DataLayer] = None
+    layers: Optional[DataLayer] = dataclasses.field(default=None,
+                                                    metadata={'transform': lambda r : r})
     """ Filter which kind of data to include. When 'None' (the default) then
         filtering by layers is disabled.
     """
     """ Filter which kind of data to include. When 'None' (the default) then
         filtering by layers is disabled.
     """
@@ -427,7 +434,8 @@ class SearchDetails(LookupDetails):
                                               metadata={'transform': Point.from_param})
     """ Order results by distance to the given point.
     """
                                               metadata={'transform': Point.from_param})
     """ Order results by distance to the given point.
     """
-    near_radius: Optional[float] = None
+    near_radius: Optional[float] = dataclasses.field(default=None,
+                                              metadata={'transform': lambda r : r})
     """ Use near point as a filter and drop results outside the given
         radius. Radius is given in degrees WSG84.
     """
     """ Use near point as a filter and drop results outside the given
         radius. Radius is given in degrees WSG84.
     """