s+: semi-working conversion to shareabletext
This commit is contained in:
parent
30e6c009cc
commit
528255a8cb
|
@ -220,6 +220,35 @@
|
||||||
"source": [
|
"source": [
|
||||||
"StringQuery(query=\"Ngee Ann Polytechnic\").to_lat_long_coord(geocoder=default_geocoder)"
|
"StringQuery(query=\"Ngee Ann Polytechnic\").to_lat_long_coord(geocoder=default_geocoder)"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Reverser Dictionary Output"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"{\n",
|
||||||
|
" \"amenity\": \"\",\n",
|
||||||
|
" \"house_number\": \"\",\n",
|
||||||
|
" \"road\": \"\",\n",
|
||||||
|
" \"suburb\": \"\",\n",
|
||||||
|
" \"city\": \"\",\n",
|
||||||
|
" \"county\": \"\",\n",
|
||||||
|
" \"ISO3166-2-lvl6\": \"\",\n",
|
||||||
|
" \"postcode\": \"\",\n",
|
||||||
|
" \"country\": \"\",\n",
|
||||||
|
" \"country_code\": \"\",\n",
|
||||||
|
" \"original response\": \"{'place_id': 297946059, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright', 'osm_type': 'relation', 'osm_id': 2535118, 'lat': '1.33318835', 'lon': '103.77461234638255', 'class': 'amenity', 'type': 'university', 'place_rank': 30, 'importance': 0.34662169301918117, 'addresstype': 'amenity', 'name': 'Ngee Ann Polytechnic', 'display_name': 'Ngee Ann Polytechnic, 535, Clementi Road, Bukit Timah, Singapore, Northwest, 599489, Singapore', 'address': {'amenity': 'Ngee Ann Polytechnic', 'house_number': '535', 'road': 'Clementi Road', 'suburb': 'Bukit Timah', 'city': 'Singapore', 'county': 'Northwest', 'ISO3166-2-lvl6': 'SG-03', 'postcode': '599489', 'country': 'Singapore', 'country_code': 'sg'}, 'boundingbox': ['1.3289692', '1.3372184', '103.7701481', '103.7783945']}\",\n",
|
||||||
|
" \"latitude\": \"1.33318835\",\n",
|
||||||
|
"}"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
|
179
surplus.py
179
surplus.py
|
@ -84,6 +84,7 @@ OUTPUT_LINE_0_KEYS: Final[tuple[str, ...]] = (
|
||||||
)
|
)
|
||||||
OUTPUT_LINE_1_KEYS: Final[tuple[str, ...]] = ("building",)
|
OUTPUT_LINE_1_KEYS: Final[tuple[str, ...]] = ("building",)
|
||||||
OUTPUT_LINE_2_KEYS: Final[tuple[str, ...]] = ("highway",)
|
OUTPUT_LINE_2_KEYS: Final[tuple[str, ...]] = ("highway",)
|
||||||
|
OUTPUT_LINE_3_NAME: Final[tuple[str, ...]] = ("house_name", "road")
|
||||||
OUTPUT_LINE_3_KEYS: Final[tuple[str, ...]] = (
|
OUTPUT_LINE_3_KEYS: Final[tuple[str, ...]] = (
|
||||||
"house_number",
|
"house_number",
|
||||||
"house_name",
|
"house_name",
|
||||||
|
@ -434,18 +435,32 @@ def default_geocoder(place: str) -> Latlong:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def default_reverser(latlong: Latlong) -> dict[str, Any]:
|
def default_reverser(latlong: Latlong) -> dict[str, str]:
|
||||||
"""default geocoder for surplus, uses OpenStreetMap Nominatim"""
|
"""default geocoder for surplus, uses OpenStreetMap Nominatim"""
|
||||||
location: _geopy_Location | None = _geopy_Nominatim(user_agent=USER_AGENT).reverse(
|
location: _geopy_Location | None = _geopy_Nominatim(user_agent=USER_AGENT).reverse(
|
||||||
str(latlong)
|
str(latlong)
|
||||||
)
|
)
|
||||||
|
|
||||||
if location is None:
|
if location is None:
|
||||||
raise NoSuitableLocationError(
|
raise NoSuitableLocationError(f"could not reverse '{str(latlong)}'")
|
||||||
f"No suitable location could be reversed from '{str(latlong)}'"
|
|
||||||
)
|
|
||||||
|
|
||||||
return location.raw
|
location_dict: dict[str, str] = {}
|
||||||
|
|
||||||
|
for key in (address := location.raw.get("address", {})):
|
||||||
|
location_dict[key] = str(address.get(key, ""))
|
||||||
|
|
||||||
|
_bounding_box_default: list[float] = [0.0] * 4
|
||||||
|
|
||||||
|
location_dict["original response"] = str(location.raw)
|
||||||
|
location_dict["latitude"] = str(location.longitude)
|
||||||
|
location_dict["latitude"] = str(location.latitude)
|
||||||
|
|
||||||
|
# location_dict["boundingbox1"] = str(location.raw.get("boundingbox", _bounding_box_default)[0])
|
||||||
|
# location_dict["boundingbox2"] = str(location.raw.get("boundingbox", _bounding_box_default)[1])
|
||||||
|
# location_dict["boundingbox3"] = str(location.raw.get("boundingbox", _bounding_box_default)[2])
|
||||||
|
# location_dict["boundingbox4"] = str(location.raw.get("boundingbox", _bounding_box_default)[3])
|
||||||
|
|
||||||
|
return location_dict
|
||||||
|
|
||||||
|
|
||||||
class Behaviour(NamedTuple):
|
class Behaviour(NamedTuple):
|
||||||
|
@ -458,7 +473,7 @@ class Behaviour(NamedTuple):
|
||||||
geocoder: Callable[[str], Latlong]
|
geocoder: Callable[[str], Latlong]
|
||||||
name string to location function, must take in a string and return a Latlong.
|
name string to location function, must take in a string and return a Latlong.
|
||||||
exceptions are handled by the caller.
|
exceptions are handled by the caller.
|
||||||
reverser: Callable[[str], dict[str, Any]]
|
reverser: Callable[[str], dict[str, str]]
|
||||||
Latlong object to dictionary function, must take in a string and return a
|
Latlong object to dictionary function, must take in a string and return a
|
||||||
dict. exceptions are handled by the caller.
|
dict. exceptions are handled by the caller.
|
||||||
stderr: TextIO = stderr
|
stderr: TextIO = stderr
|
||||||
|
@ -475,7 +490,7 @@ class Behaviour(NamedTuple):
|
||||||
|
|
||||||
query: list[str]
|
query: list[str]
|
||||||
geocoder: Callable[[str], Latlong] = default_geocoder
|
geocoder: Callable[[str], Latlong] = default_geocoder
|
||||||
reverser: Callable[[Latlong], dict[str, Any]] = default_reverser
|
reverser: Callable[[Latlong], dict[str, str]] = default_reverser
|
||||||
stderr: TextIO = stderr
|
stderr: TextIO = stderr
|
||||||
stdout: TextIO = stdout
|
stdout: TextIO = stdout
|
||||||
debug: bool = False
|
debug: bool = False
|
||||||
|
@ -713,6 +728,100 @@ def handle_args() -> Behaviour:
|
||||||
return behaviour
|
return behaviour
|
||||||
|
|
||||||
|
|
||||||
|
def _unique(l: Sequence[str]) -> list[str]:
|
||||||
|
"""(internal function) returns a in-order unique list from list"""
|
||||||
|
unique: OrderedDict = OrderedDict()
|
||||||
|
for line in l:
|
||||||
|
unique.update({line: None})
|
||||||
|
return list(unique.keys())
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_text(location: dict[str, str], debug: bool = False) -> str:
|
||||||
|
"""(internal function) generate shareable text from location dict"""
|
||||||
|
|
||||||
|
def _generate_text_line(
|
||||||
|
line_number: int,
|
||||||
|
line_keys: Sequence[str],
|
||||||
|
seperator: str = ", ",
|
||||||
|
element_check: Callable[[str], bool] = lambda e: True,
|
||||||
|
debug: bool = False,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
(internal function) generate a line of shareable text from a list of keys
|
||||||
|
|
||||||
|
arguments
|
||||||
|
line_number: int
|
||||||
|
line number to prefix with
|
||||||
|
line_keys: Sequence[str]
|
||||||
|
list of keys to .get() from location dict
|
||||||
|
element_check: Callable[[str], bool] = lambda e: True
|
||||||
|
function that takes in a string and returns a bool, used to filter
|
||||||
|
elements from line_keys
|
||||||
|
debug: bool = False
|
||||||
|
whether to prefix line with line_number
|
||||||
|
|
||||||
|
returns str
|
||||||
|
"""
|
||||||
|
|
||||||
|
line_prefix: str = f"{line_number}\t" if debug else ""
|
||||||
|
basket: list[str] = []
|
||||||
|
|
||||||
|
for detail in _unique([location.get(detail, "") for detail in line_keys]):
|
||||||
|
if detail == "":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if element_check(detail):
|
||||||
|
basket.append(detail)
|
||||||
|
|
||||||
|
line = line_prefix + seperator.join(basket)
|
||||||
|
|
||||||
|
return (line + "\n") if (line != "") else ""
|
||||||
|
|
||||||
|
text: list[str] = []
|
||||||
|
|
||||||
|
seen_names: list[str] = [
|
||||||
|
detail
|
||||||
|
for detail in _unique(
|
||||||
|
[
|
||||||
|
location.get(location_key, "")
|
||||||
|
for location_key in (
|
||||||
|
OUTPUT_LINE_0_KEYS
|
||||||
|
+ OUTPUT_LINE_1_KEYS
|
||||||
|
+ OUTPUT_LINE_2_KEYS
|
||||||
|
+ OUTPUT_LINE_3_NAME
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
if detail != ""
|
||||||
|
]
|
||||||
|
|
||||||
|
general_global_info: list[str] = [
|
||||||
|
location.get(detail, "") for detail in OUTPUT_LINE_6_KEYS
|
||||||
|
]
|
||||||
|
|
||||||
|
text.append(_generate_text_line(0, OUTPUT_LINE_0_KEYS, debug=debug))
|
||||||
|
text.append(_generate_text_line(1, OUTPUT_LINE_1_KEYS, debug=debug))
|
||||||
|
text.append(_generate_text_line(2, OUTPUT_LINE_2_KEYS, debug=debug))
|
||||||
|
text.append(_generate_text_line(3, OUTPUT_LINE_3_KEYS, seperator=" ", debug=debug))
|
||||||
|
text.append(
|
||||||
|
_generate_text_line(
|
||||||
|
4,
|
||||||
|
OUTPUT_LINE_4_KEYS,
|
||||||
|
element_check=lambda ak: all(
|
||||||
|
[
|
||||||
|
ak not in general_global_info,
|
||||||
|
any(True if (ak not in sn) else False for sn in seen_names),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
debug=debug,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
text.append(_generate_text_line(5, OUTPUT_LINE_5_KEYS, debug=debug))
|
||||||
|
text.append(_generate_text_line(6, OUTPUT_LINE_6_KEYS, debug=debug))
|
||||||
|
|
||||||
|
return "".join(text)
|
||||||
|
|
||||||
|
|
||||||
def surplus(
|
def surplus(
|
||||||
query: PlusCodeQuery | LocalCodeQuery | LatlongQuery | StringQuery,
|
query: PlusCodeQuery | LocalCodeQuery | LatlongQuery | StringQuery,
|
||||||
behaviour: Behaviour,
|
behaviour: Behaviour,
|
||||||
|
@ -729,36 +838,42 @@ def surplus(
|
||||||
returns Result[str]
|
returns Result[str]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _unique(l: Sequence[str]) -> list[str]:
|
|
||||||
"""(internal function) returns a in-order unique list from list"""
|
|
||||||
unique: OrderedDict = OrderedDict()
|
|
||||||
for line in l:
|
|
||||||
unique.update({line: None})
|
|
||||||
return list(unique.keys())
|
|
||||||
|
|
||||||
def _generate_text(line_keys: Sequence[str]) -> str:
|
|
||||||
"""(internal function) TODO DOCSTRING"""
|
|
||||||
# TODO
|
|
||||||
return ""
|
|
||||||
|
|
||||||
"""
|
|
||||||
# get latlong and handle result
|
|
||||||
latlong = query.to_lat_long_coord(geocoder=behaviour.geocoder)
|
|
||||||
|
|
||||||
if not latlong:
|
|
||||||
return Result[str]("", error=latlong.error)
|
|
||||||
|
|
||||||
if behaviour.debug:
|
|
||||||
behaviour.stderr.write(f"debug: {latlong.get()=}\n")
|
|
||||||
"""
|
|
||||||
|
|
||||||
# operate on query
|
# operate on query
|
||||||
text: str = ""
|
text: str = ""
|
||||||
|
|
||||||
match behaviour.convert_to_type:
|
match behaviour.convert_to_type:
|
||||||
case ConversionResultTypeEnum.SHAREABLE_TEXT:
|
case ConversionResultTypeEnum.SHAREABLE_TEXT:
|
||||||
# TODO
|
# get latlong and handle result
|
||||||
return Result[str](text, error="TODO")
|
latlong = query.to_lat_long_coord(geocoder=behaviour.geocoder)
|
||||||
|
|
||||||
|
if not latlong:
|
||||||
|
return Result[str]("", error=latlong.error)
|
||||||
|
|
||||||
|
if behaviour.debug:
|
||||||
|
behaviour.stderr.write(f"debug: {latlong.get()=}\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
location: dict[str, str] = behaviour.reverser(latlong.get())
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
return Result[str]("", error=exc)
|
||||||
|
|
||||||
|
if behaviour.debug:
|
||||||
|
behaviour.stderr.write(f"debug: {location=}\n")
|
||||||
|
|
||||||
|
if behaviour.debug:
|
||||||
|
behaviour.stderr.write(
|
||||||
|
_generate_text(
|
||||||
|
location=location,
|
||||||
|
debug=behaviour.debug,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
text = _generate_text(
|
||||||
|
location=location,
|
||||||
|
).rstrip()
|
||||||
|
|
||||||
|
return Result[str](text)
|
||||||
|
|
||||||
case ConversionResultTypeEnum.PLUS_CODE:
|
case ConversionResultTypeEnum.PLUS_CODE:
|
||||||
# TODO: https://github.com/markjoshwel/surplus/issues/18
|
# TODO: https://github.com/markjoshwel/surplus/issues/18
|
||||||
|
|
Loading…
Reference in a new issue