python-package/lets_plot/geo_data/gis/response.py (190 lines of code) (raw):
import enum
from typing import List, Optional, Dict, Union
from .geometry import GeometryBase, GeoPoint, GeoRect, Polygon, Multipolygon
from .request import LevelKind
from ..type_assertion import assert_list_type, assert_optional_type, assert_type, assert_optional_list_type
class Status(enum.Enum):
success = 'success'
ambiguous = 'ambiguous'
error = 'error'
class NamesakeParent:
def __init__(self, name: str, level: LevelKind):
assert_type(name, str)
assert_type(level, LevelKind)
self.name: str = name
self.level: LevelKind = level
class Namesake:
def __init__(self, name: str, parents: List[NamesakeParent]):
assert_type(name, str)
assert_list_type(parents, NamesakeParent)
self.name: str = name
self.parents: List[NamesakeParent] = parents
class Boundary(GeometryBase):
def __init__(self, geometry: Union[Multipolygon, Polygon, GeoPoint]):
self.geometry: Union[Multipolygon, Polygon, GeoPoint] = geometry
class GeocodedFeature:
def __init__(self,
id: str, name: str,
highlights: Optional[List[str]] = None,
boundary: Optional[Boundary] = None,
centroid: Optional[GeoPoint] = None,
limit: Optional[GeoRect] = None,
position: Optional[GeoRect] = None):
assert_type(id, str)
assert_type(name, str)
assert_optional_list_type(highlights, str)
assert_optional_type(boundary, Boundary)
assert_optional_type(centroid, GeoPoint)
assert_optional_type(limit, GeoRect)
assert_optional_type(position, GeoRect)
self.id: str = id
self.name: str = name
self.highlights: Optional[List[str]] = highlights
self.boundary: Optional[Boundary] = boundary
self.centroid: Optional[GeoPoint] = centroid
self.limit: Optional[GeoRect] = limit
self.position: Optional[GeoRect] = position
class AmbiguousFeature:
def __init__(self, query: str, total_namesake_count: int, namesake_examples: List[Namesake]):
assert_type(query, str)
assert_type(total_namesake_count, int)
assert_list_type(namesake_examples, Namesake)
self.query: str = query
self.total_namesake_count: int = total_namesake_count
self.namesake_examples: List[Namesake] = namesake_examples
class Response:
def __init__(self, message: str):
assert_type(message, str)
self.message: str = message
class Answer:
def __init__(self, features: List[GeocodedFeature]):
assert_list_type(features, GeocodedFeature)
self.features: List[GeocodedFeature] = features
class SuccessResponse(Response):
def __init__(self, message: str, level: LevelKind, answers: List[Answer]):
super().__init__(message)
assert_type(message, str)
assert_optional_type(level, LevelKind)
assert_list_type(answers, Answer)
self.level: LevelKind = level
self.answers: List[Answer] = answers
features = []
for answer in answers:
features.extend(answer.features)
self.features: List[GeocodedFeature] = features
class AmbiguousResponse(Response):
def __init__(self, message: str, level: LevelKind, features: List[AmbiguousFeature]):
super().__init__(message)
assert_type(message, str)
assert_optional_type(level, LevelKind)
assert_list_type(features, AmbiguousFeature)
self.level: LevelKind = level
self.features: List[AmbiguousFeature] = features
class ErrorResponse(Response):
def __init__(self, message: str):
super().__init__(message)
class FeatureBuilder:
def __init__(self):
self.query: Optional[str] = None
self.id: Optional[str] = None
self.name: Optional[str] = None
self.highlights: Optional[List[str]] = None
self.boundary: Optional[Boundary] = None
self.centroid: Optional[GeoPoint] = None
self.limit: Optional[GeoRect] = None
self.position: Optional[GeoRect] = None
self.total_namesake_count: Optional[int] = None
self.namesake_examples: List[Namesake] = []
def set_query(self, v: Optional[str]) -> 'FeatureBuilder':
assert_optional_type(v, str)
self.query = v
return self
def set_id(self, v: str) -> 'FeatureBuilder':
assert_type(v, str)
self.id = v
return self
def set_name(self, v: str) -> 'FeatureBuilder':
assert_type(v, str)
self.name = v
return self
def set_highlights(self, v: List[str]) -> 'FeatureBuilder':
assert_list_type(v, str)
self.highlights = v
return self
def set_boundary(self, v: Union[Multipolygon, Polygon, GeoPoint]) -> 'FeatureBuilder':
assert_type(v, (Multipolygon, Polygon, GeoPoint))
self.boundary = Boundary(v)
return self
def set_centroid(self, v: GeoPoint) -> 'FeatureBuilder':
assert_type(v, GeoPoint)
self.centroid = v
return self
def set_limit(self, v: GeoRect) -> 'FeatureBuilder':
assert_type(v, GeoRect)
self.limit = v
return self
def set_position(self, v: GeoRect) -> 'FeatureBuilder':
assert_type(v, GeoRect)
self.position = v
return self
def set_total_namesake_count(self, v: int) -> 'FeatureBuilder':
assert_type(v, int)
self.total_namesake_count = v
return self
def set_namesake_examples(self, v: List[Namesake]) -> 'FeatureBuilder':
assert_list_type(v, Namesake)
self.namesake_examples = v
return self
def add_namesake(self, namesake: Namesake) -> 'FeatureBuilder':
assert_type(namesake, Namesake)
self.namesake_examples.append(namesake)
return self
def build_ambiguous(self) -> AmbiguousFeature:
return AmbiguousFeature(self.query, self.total_namesake_count, self.namesake_examples)
def build_geocoded(self) -> GeocodedFeature:
return GeocodedFeature(self.id, self.name, self.highlights, self.boundary, self.centroid, self.limit,
self.position)
class ResponseBuilder:
def __init__(self):
self.status: Status = None
self.level: LevelKind = None
self.message: str = None
self.answers: List[Answer] = None
self.ambiguous_features: List[AmbiguousFeature] = None
self.data: Dict = None
def set_status(self, v: Status) -> 'ResponseBuilder':
assert_type(v, Status)
self.status = v
return self
def set_level(self, v: LevelKind) -> 'ResponseBuilder':
assert_type(v, LevelKind)
self.level = v
return self
def set_message(self, v: str) -> 'ResponseBuilder':
assert_type(v, str)
self.message = v
return self
def set_ambiguous_features(self, v: List[AmbiguousFeature]) -> 'ResponseBuilder':
assert_list_type(v, AmbiguousFeature)
self.ambiguous_features = v
return self
def set_answers(self, v: List[Answer]) -> 'ResponseBuilder':
assert_list_type(v, Answer)
self.answers = v
return self
def set_geocoded_features(self, v: List[GeocodedFeature]):
'''
Exactly matching non-exploding features, i.e. one feature per answer
'''
assert_list_type(v, GeocodedFeature)
self.answers = [Answer([f]) for f in v]
return self
def build(self) -> Response:
if self.status == Status.error:
return ErrorResponse(self.message)
elif self.status == Status.success:
return SuccessResponse(self.message, self.level, self.answers)
elif self.status == Status.ambiguous:
return AmbiguousResponse(self.message, self.level, self.ambiguous_features)
else:
raise ValueError('Unknown status: ' + str(self.status))