code: pass ruff

This commit is contained in:
Mark Joshwel 2024-03-26 18:08:49 +00:00
parent 4871b9d352
commit 1ccd66b166
3 changed files with 175 additions and 280 deletions

View file

@ -33,6 +33,7 @@ from datetime import datetime, timedelta, timezone
from os import getenv
from pathlib import Path
from subprocess import run
from sys import exit as sysexit
# NOTE: change this if surplus has moved
path_surplus = Path(__file__).parent.joinpath("./surplus/surplus.py")
@ -42,19 +43,19 @@ build_time = datetime.now(timezone(timedelta(hours=8))) # using SGT
_insert_build_branch = getenv(
"SURPLUS_BUILD_BRANCH",
run(
"git branch --show-current",
"git branch --show-current".split(),
capture_output=True,
text=True,
shell=True,
check=False,
).stdout.strip("\n"),
)
insert_build_branch = _insert_build_branch if _insert_build_branch != "" else "unknown"
insert_build_commit: str = run(
"git rev-parse HEAD",
"git rev-parse HEAD".split(),
capture_output=True,
text=True,
shell=True,
check=False,
).stdout.strip("\n")
insert_build_datetime: str = repr(build_time).replace("datetime.", "")
@ -63,7 +64,7 @@ insert_build_datetime: str = repr(build_time).replace("datetime.", "")
targets: list[tuple[str, str]] = [
(
'VERSION_SUFFIX: Final[str] = "-local"',
'VERSION_SUFFIX: Final[str] = ""',
'VERSION_SUFFIX: Final[str] = "-alpha"',
),
(
'BUILD_BRANCH: Final[str] = "future"',
@ -81,18 +82,19 @@ targets: list[tuple[str, str]] = [
def main() -> int:
assert path_surplus.is_file() and path_surplus.exists(), f"{path_surplus} not found"
if not (path_surplus.is_file() and path_surplus.exists()):
raise FileNotFoundError(path_surplus)
source_surplus: str = path_surplus.read_text(encoding="utf-8")
for old, new in targets:
print(f"new: {new}\nold: {old}\n")
print(f"new: {new}\nold: {old}\n") # noqa: T201
source_surplus = source_surplus.replace(old, new)
path_surplus.write_text(source_surplus, encoding="utf-8")
# path_surplus.write_text(source_surplus, encoding="utf-8")
return 0
if __name__ == "__main__":
exit(main())
sysexit(main())

View file

@ -32,24 +32,13 @@ For more information, please refer to <http://unlicense.org/>
# surplus was and would've been a single-file module, but typing is in the way :(
# https://github.com/python/typing/issues/1333
from .surplus import default_geocoder # deprecated, emulation function
from .surplus import default_reverser # deprecated, emulation function
from .surplus import (
from .surplus import ( # noqa: F401, TID252
BUILD_BRANCH,
BUILD_COMMIT,
BUILD_DATETIME,
CONNECTION_MAX_RETRIES,
CONNECTION_WAIT_SECONDS,
EMPTY_LATLONG,
SHAREABLE_TEXT_LINE_0_KEYS,
SHAREABLE_TEXT_LINE_1_KEYS,
SHAREABLE_TEXT_LINE_2_KEYS,
SHAREABLE_TEXT_LINE_3_KEYS,
SHAREABLE_TEXT_LINE_4_KEYS,
SHAREABLE_TEXT_LINE_5_KEYS,
SHAREABLE_TEXT_LINE_6_KEYS,
SHAREABLE_TEXT_LOCALITY,
SHAREABLE_TEXT_NAMES,
VERSION,
VERSION_SUFFIX,
Behaviour,
@ -68,12 +57,12 @@ from .surplus import (
ResultType,
StringQuery,
SurplusDefaultGeocoding,
SurplusException,
SurplusError,
SurplusGeocoderProtocol,
SurplusReverserProtocol,
__version__,
cli,
generate_fingerprinted_user_agent,
handle_args,
parse_query,
surplus,
)

View file

@ -31,6 +31,7 @@ For more information, please refer to <http://unlicense.org/>
from argparse import ArgumentParser
from collections import OrderedDict
from collections.abc import Callable, Sequence
from copy import deepcopy
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
@ -41,35 +42,35 @@ from json import loads as json_loads
from json.decoder import JSONDecodeError
from platform import platform
from socket import gethostname
from sys import exit as sysexit
from sys import stderr, stdin, stdout
from typing import (
TYPE_CHECKING,
Any,
Callable,
Final,
Generic,
NamedTuple,
Protocol,
Sequence,
TextIO,
TypeAlias,
TypeVar,
)
from uuid import getnode
from geopy import Location as _geopy_Location # type: ignore
from geopy.extra.rate_limiter import RateLimiter as _geopy_RateLimiter # type: ignore
from geopy.geocoders import Nominatim as _geopy_Nominatim # type: ignore
from pluscodes import PlusCode as _PlusCode # type: ignore
from pluscodes import encode as _PlusCode_encode # type: ignore
from pluscodes import encode as _encode # type: ignore
from pluscodes.openlocationcode import recoverNearest as _PlusCode_recoverNearest # type: ignore
from pluscodes.validator import Validator as _PlusCode_Validator # type: ignore
from pluscodes.openlocationcode import ( # type: ignore # isort: skip
recoverNearest as _PlusCode_recoverNearest,
)
if TYPE_CHECKING:
from geopy import Location as _geopy_Location # type: ignore
# constants
VERSION: Final[tuple[int, int, int]] = (2, 2, 0)
__version__ = "2024.0.0-alpha"
VERSION: Final[tuple[int, int, int]] = (2024, 0, 0)
VERSION_SUFFIX: Final[str] = "-local"
BUILD_BRANCH: Final[str] = "future"
BUILD_COMMIT: Final[str] = "latest"
@ -215,15 +216,13 @@ SHAREABLE_TEXT_LINE_6_KEYS.update(
),
}
)
SHAREABLE_TEXT_LINE_SETTINGS.update(
{"IT": deepcopy(SHAREABLE_TEXT_LINE_SETTINGS)["default"]}
)
SHAREABLE_TEXT_LINE_SETTINGS.update({"IT": deepcopy(SHAREABLE_TEXT_LINE_SETTINGS)["default"]})
SHAREABLE_TEXT_LINE_SETTINGS["IT"][5] = (" ", False)
# special per-country key arrangements for MY/Malaysia
SHAREABLE_TEXT_LINE_4_KEYS.update(
{
"MY": tuple(),
"MY": (),
},
)
SHAREABLE_TEXT_LINE_5_KEYS.update(
@ -234,9 +233,7 @@ SHAREABLE_TEXT_LINE_5_KEYS.update(
),
},
)
SHAREABLE_TEXT_LINE_SETTINGS.update(
{"MY": deepcopy(SHAREABLE_TEXT_LINE_SETTINGS)["default"]}
)
SHAREABLE_TEXT_LINE_SETTINGS.update({"MY": deepcopy(SHAREABLE_TEXT_LINE_SETTINGS)["default"]})
SHAREABLE_TEXT_LINE_SETTINGS["MY"][4] = (" ", False)
SHAREABLE_TEXT_LINE_SETTINGS["MY"][5] = (" ", True)
@ -244,30 +241,23 @@ SHAREABLE_TEXT_LINE_SETTINGS["MY"][5] = (" ", True)
# exceptions
class SurplusException(Exception):
class SurplusError(Exception):
"""base skeleton exception for handling and typing surplus exception classes"""
...
class NoSuitableLocationError(SurplusError): ...
class NoSuitableLocationError(SurplusException):
...
class IncompletePlusCodeError(SurplusError): ...
class IncompletePlusCodeError(SurplusException):
...
class PlusCodeNotFoundError(SurplusError): ...
class PlusCodeNotFoundError(SurplusException):
...
class LatlongParseError(SurplusError): ...
class LatlongParseError(SurplusException):
...
class EmptyQueryError(SurplusException):
...
class EmptyQueryError(SurplusError): ...
# data structures
@ -357,7 +347,7 @@ class Result(NamedTuple, Generic[ResultType]):
"""method that returns True if self.error is not None"""
return self.error is None
def cry(self, string: bool = False) -> str:
def cry(self, string: bool = False) -> str: # noqa: FBT001, FBT002
"""
method that raises self.error if is an instance of BaseException,
returns self.error if is an instance of str, or returns an empty string if
@ -438,8 +428,7 @@ class SurplusGeocoderProtocol(Protocol):
exceptions are handled by the caller
"""
def __call__(self, place: str) -> Latlong:
...
def __call__(self, place: str) -> Latlong: ...
class SurplusReverserProtocol(Protocol):
@ -478,8 +467,7 @@ class SurplusReverserProtocol(Protocol):
exceptions are handled by the caller
"""
def __call__(self, latlong: Latlong, level: int = 18) -> dict[str, Any]:
...
def __call__(self, latlong: Latlong, level: int = 18) -> dict[str, Any]: ...
class PlusCodeQuery(NamedTuple):
@ -496,7 +484,7 @@ class PlusCodeQuery(NamedTuple):
code: str
def to_lat_long_coord(self, geocoder: SurplusGeocoderProtocol) -> Result[Latlong]:
def to_lat_long_coord(self, geocoder: SurplusGeocoderProtocol) -> Result[Latlong]: # noqa: ARG002
"""
method that returns a latitude-longitude coordinate pair
@ -520,12 +508,11 @@ class PlusCodeQuery(NamedTuple):
return Result[Latlong](
EMPTY_LATLONG,
error=IncompletePlusCodeError(
"PlusCodeQuery.to_lat_long_coord: "
"Plus Code is not full-length (e.g., 6PH58QMF+FX)"
"PlusCodeQuery.to_lat_long_coord: " "Plus Code is not full-length (e.g., 6PH58QMF+FX)"
),
)
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[Latlong](EMPTY_LATLONG, error=exc)
return Result[Latlong](Latlong(latitude=latitude, longitude=longitude))
@ -578,7 +565,7 @@ class LocalCodeQuery(NamedTuple):
return Result[str](recovered_pluscode)
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[str]("", error=exc)
def to_lat_long_coord(self, geocoder: SurplusGeocoderProtocol) -> Result[Latlong]:
@ -623,7 +610,7 @@ class LatlongQuery(NamedTuple):
latlong: Latlong
def to_lat_long_coord(self, geocoder: SurplusGeocoderProtocol) -> Result[Latlong]:
def to_lat_long_coord(self, geocoder: SurplusGeocoderProtocol) -> Result[Latlong]: # noqa: ARG002
"""
method that returns a latitude-longitude coordinate pair
@ -639,7 +626,7 @@ class LatlongQuery(NamedTuple):
def __str__(self) -> str:
"""method that returns string representation of query"""
return f"{str(self.latlong)}"
return f"{self.latlong!s}"
class StringQuery(NamedTuple):
@ -671,7 +658,7 @@ class StringQuery(NamedTuple):
try:
return Result[Latlong](geocoder(self.query))
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[Latlong](EMPTY_LATLONG, error=exc)
def __str__(self) -> str:
@ -695,22 +682,24 @@ def generate_fingerprinted_user_agent() -> Result[str]:
"""
version: str = ".".join([str(v) for v in VERSION]) + VERSION_SUFFIX
try:
system_info: str = platform()
hostname: str = gethostname()
mac_address: str = ":".join(
[
"{:02x}".format((getnode() >> elements) & 0xFF)
for elements in range(0, 2 * 6, 2)
][::-1]
)
unique_info: str = f"{version}-{system_info}-{hostname}-{mac_address}"
def _try(func: Callable) -> str:
try:
return func()
except Exception as exc:
return Result[str](f"surplus/{version} (generic-user)", error=exc)
except Exception: # noqa: BLE001
return "unknown"
system_info: str = _try(platform)
hostname = _try(gethostname)
mac_address = _try(
lambda: ":".join([f"{(getnode() >> elements) & 0xFF:02x}" for elements in range(0, 2 * 6, 2)][::-1])
)
unique_info = f"{version}-{system_info}-{hostname}-{mac_address}"
if unique_info == "unknown-unknown-unknown-unknown":
return Result[str](f"surplus/{version} (generic-user)")
fingerprint: str = shake_256(unique_info.encode()).hexdigest(5)
return Result[str](f"surplus/{version} ({fingerprint})")
@ -740,17 +729,14 @@ class SurplusDefaultGeocoding:
"""
user_agent: str = default_fingerprint
_ratelimited_raw_geocoder: Callable | None = None
_ratelimited_raw_reverser: Callable | None = None
_ratelimited_raw_geocoder: Callable = lambda _: None # noqa: E731
_ratelimited_raw_reverser: Callable = lambda _: None # noqa: E731
_first_update: bool = False
def update_geocoding_functions(self) -> None:
"""
re-initialise the geocoding functions with the current user agent, also generate
a new user agent if not set properly
recommended to call this before using surplus as by default the geocoding
functions are uninitialised
"""
if not isinstance(self.user_agent, str):
@ -785,26 +771,20 @@ class SurplusDefaultGeocoding:
see SurplusGeocoderProtocol for more information on surplus geocoder functions
"""
if not callable(self._ratelimited_raw_geocoder) or (self._first_update is False):
if self._first_update is False:
self.update_geocoding_functions()
# https://github.com/python/mypy/issues/12155
assert callable(self._ratelimited_raw_geocoder)
location: _geopy_Location | None = self._ratelimited_raw_geocoder(place)
if location is None:
raise NoSuitableLocationError(
f"No suitable location could be geolocated from '{place}'"
)
msg = f"No suitable location could be geolocated from '{place}'"
raise NoSuitableLocationError(msg)
bounding_box: tuple[float, float, float, float] | None = location.raw.get(
"boundingbox", None
)
bounding_box: tuple[float, float, float, float] | None = location.raw.get("boundingbox", None)
if location.raw.get("boundingbox", None) is not None:
_bounding_box = [float(c) for c in location.raw.get("boundingbox", [])]
if len(_bounding_box) == 4:
if len(_bounding_box) == 4: # noqa: PLR2004
bounding_box = (
_bounding_box[0],
_bounding_box[1],
@ -830,18 +810,14 @@ class SurplusDefaultGeocoding:
see SurplusReverserProtocol for more information on surplus reverser functions
"""
if not callable(self._ratelimited_raw_reverser) or (self._first_update is False):
if self._first_update is False:
self.update_geocoding_functions()
# https://github.com/python/mypy/issues/12155
assert callable(self._ratelimited_raw_reverser)
location: _geopy_Location | None = self._ratelimited_raw_reverser(
str(latlong), zoom=level
)
location: _geopy_Location | None = self._ratelimited_raw_reverser(str(latlong), zoom=level)
if location is None:
raise NoSuitableLocationError(f"could not reverse '{str(latlong)}'")
msg = f"could not reverse '{latlong!s}'"
raise NoSuitableLocationError(msg)
location_dict: dict[str, Any] = {}
@ -855,32 +831,7 @@ class SurplusDefaultGeocoding:
return location_dict
default_geocoding: Final[SurplusDefaultGeocoding] = SurplusDefaultGeocoding(
default_fingerprint
)
default_geocoding.update_geocoding_functions()
def default_geocoder(place: str) -> Latlong:
"""(deprecated) geocoder for surplus, uses OpenStreetMap Nominatim"""
print(
"warning: default_geocoder is deprecated. "
"this is a emulation function that will use a fingerprinted user agent.",
file=stderr,
)
return default_geocoding.geocoder(place=place)
def default_reverser(latlong: Latlong, level: int = 18) -> dict[str, Any]:
"""
(deprecated) reverser for surplus, uses OpenStreetMap Nominatim
"""
print(
"warning: default_reverser is deprecated. "
"this is a emulation function that will use a fingerprinted user agent.",
file=stderr,
)
return default_geocoding.reverser(latlong=latlong, level=level)
default_geocoding: Final[SurplusDefaultGeocoding] = SurplusDefaultGeocoding(default_fingerprint)
class Behaviour(NamedTuple):
@ -960,8 +911,8 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
original_query = str(behaviour.query)
split_query = behaviour.query.split(" ")
for word in split_query:
word = word.strip(",").strip()
for _word in split_query:
word = _word.strip(",").strip()
if validator.is_valid(word):
portion_plus_code = word
@ -986,9 +937,7 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
if (portion_locality == "") and (not validator.is_full(portion_plus_code)):
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=IncompletePlusCodeError(
"_match_plus_code: Plus Code is not full-length (e.g., 6PH58QMF+FX)"
),
error=IncompletePlusCodeError("_match_plus_code: Plus Code is not full-length (e.g., 6PH58QMF+FX)"),
)
if behaviour.debug:
@ -1023,7 +972,7 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
print(f"debug: parse_query: {behaviour.query=}", file=behaviour.stderr)
# check if empty
if (behaviour.query == []) or (behaviour.query == ""):
if behaviour.query in ([], ""):
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=EmptyQueryError("empty query string passed"),
@ -1063,7 +1012,8 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
try:
termux_location_json = json_loads(original_query)
if not isinstance(termux_location_json, dict):
raise ValueError("parsed termux-location json is not a dict")
msg = "parsed termux-location json is not a dict"
raise TypeError(msg) # noqa: TRY301
return Result[Query](
LatlongQuery(
@ -1074,21 +1024,19 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
)
)
except (JSONDecodeError, TypeError) as exc:
except (JSONDecodeError, TypeError):
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=ValueError("could not parse termux-location json"),
)
except KeyError as exc:
except KeyError:
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=ValueError(
"could not get 'latitude' or 'longitude' keys from termux-location json"
),
error=ValueError("could not get 'latitude' or 'longitude' keys from termux-location json"),
)
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=exc,
@ -1107,29 +1055,29 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
if "," not in single: # no comma, not a latlong coord
return Result[Query](StringQuery(original_query))
else: # has comma, possibly a latlong coord
comma_split_single: list[str] = single.split(",")
# has comma, possibly a latlong coord
comma_split_single: list[str] = single.split(",")
if len(comma_split_single) == 2:
try: # try to type cast query
latitude = float(comma_split_single[0].strip(","))
longitude = float(comma_split_single[-1].strip(","))
if len(comma_split_single) == 2: # noqa: PLR2004
try: # try to type cast query
latitude = float(comma_split_single[0].strip(","))
longitude = float(comma_split_single[-1].strip(","))
except ValueError: # not a latlong coord, fallback
return Result[Query](StringQuery(single))
except ValueError: # not a latlong coord, fallback
return Result[Query](StringQuery(single))
else: # are floats, so is a latlong coord
return Result[Query](
LatlongQuery(
Latlong(
latitude=latitude,
longitude=longitude,
)
else: # are floats, so is a latlong coord
return Result[Query](
LatlongQuery(
Latlong(
latitude=latitude,
longitude=longitude,
)
)
)
# not a latlong coord, fallback
return Result[Query](StringQuery(original_query))
# not a latlong coord, fallback
return Result[Query](StringQuery(original_query))
case [left_single, right_single]:
# possibly a:
@ -1144,9 +1092,7 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
return Result[Query](StringQuery(original_query))
else: # are floats, so is a latlong coord
return Result[Query](
LatlongQuery(Latlong(latitude=latitude, longitude=longitude))
)
return Result[Query](LatlongQuery(Latlong(latitude=latitude, longitude=longitude)))
case _:
# possibly a:
@ -1193,22 +1139,21 @@ def handle_args() -> Behaviour:
default=False,
help="prints version information to stderr and exits",
)
parser.add_argument(
"-c",
"--convert-to",
type=str,
choices=[str(v.value) for v in ConversionResultTypeEnum],
help=(
"converts query a specific output type, defaults to "
f"'{Behaviour([]).convert_to_type.value}'"
(
parser.add_argument(
"-c",
"--convert-to",
type=str,
choices=[str(v.value) for v in ConversionResultTypeEnum],
help=("converts query a specific output type, defaults to " f"'{Behaviour([]).convert_to_type.value}'"),
default=Behaviour([]).convert_to_type.value,
),
default=Behaviour([]).convert_to_type.value,
),
)
parser.add_argument(
"-u",
"--user-agent",
type=str,
help=f"user agent string to use for geocoding service, defaults to fingerprinted user agent string",
help="user agent string to use for geocoding service, defaults to fingerprinted user agent string",
default=default_fingerprint,
)
parser.add_argument(
@ -1224,20 +1169,11 @@ def handle_args() -> Behaviour:
query: str | list[str] = ""
# "-" stdin check
if args.query == ["-"]:
stdin_query: list[str] = []
for line in stdin:
stdin_query.append(line.strip())
query = "\n".join(stdin_query)
else:
query = args.query
query = "\n".join([line.strip() for line in stdin]) if (args.query == ["-"]) else args.query
# setup structures and return
geocoding = SurplusDefaultGeocoding(args.user_agent)
behaviour = Behaviour(
return Behaviour(
query=query,
geocoder=geocoding.geocoder,
reverser=geocoding.reverser,
@ -1248,13 +1184,12 @@ def handle_args() -> Behaviour:
convert_to_type=ConversionResultTypeEnum(args.convert_to),
using_termux_location=args.using_termux_location,
)
return behaviour
def _unique(l: Sequence[str]) -> list[str]:
def _unique(container: Sequence[str]) -> list[str]:
"""(internal function) returns a in-order unique list from list"""
unique: OrderedDict = OrderedDict()
for line in l:
for line in container:
unique.update({line: None})
return list(unique.keys())
@ -1263,7 +1198,7 @@ def _generate_text(
location: dict[str, Any],
behaviour: Behaviour,
mode: TextGenerationEnum = TextGenerationEnum.SHAREABLE_TEXT,
debug: bool = False,
debug: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
(internal function) generate shareable text from location dict
@ -1286,7 +1221,7 @@ def _generate_text(
line_number: int,
line_keys: Sequence[str],
separator: str = ", ",
filter: Callable[[str], list[bool]] = lambda e: [True],
filter_func: Callable[[str], list[bool]] = lambda _: [True],
) -> str:
"""
(internal function) generate a line of shareable text from a list of keys
@ -1298,7 +1233,7 @@ def _generate_text(
list of keys to .get() from location dict
separator: str = ", "
separator to join elements with
filter: Callable[[str], list[bool]] = lambda e: True
filter_func: Callable[[str], list[bool]] = lambda e: True
function that takes in a string and returns a list of bools, used to
filter elements from line_keys. list will be passed to all(). if all
returns True, then the element is kept.
@ -1313,14 +1248,14 @@ def _generate_text(
if detail == "":
continue
# filtering: if all(filter(detail)) returns True,
# filtering: if all(filter_func(detail)) returns True,
# then the element is kept/added to 'basket'
if filter_status := all(detail_check := filter(detail)) is True:
if filter_status := all(detail_check := filter_func(detail)) is True:
if debug:
print(
"debug: _generate_text_line: "
f"{str(detail_check):<20} -> {str(filter_status):<5} "
f"{detail_check!s:<20} -> {filter_status!s:<5} "
f"-------- '{detail}'",
file=behaviour.stderr,
)
@ -1331,7 +1266,7 @@ def _generate_text(
if debug:
print(
"debug: _generate_text_line: "
f"{str(detail_check):<20} -> {str(filter_status):<5}"
f"{detail_check!s:<20} -> {filter_status!s:<5}"
f" filtered '{detail}'",
file=behaviour.stderr,
)
@ -1358,15 +1293,14 @@ def _generate_text(
C: dict content
"""
DEFAULT = "default"
country: str = DEFAULT
country: str = "default"
if len(iso3166_2) >= 1:
country = split_iso3166_2[0]
if country not in line_keys:
return False, line_keys[DEFAULT]
else:
return True, line_keys[country]
return False, line_keys["default"]
return True, line_keys[country]
# iso3166-2 handling: this allows surplus to have special key arrangements for a
# specific iso3166-2 code for edge cases
@ -1421,8 +1355,7 @@ def _generate_text(
if n_used_special and debug:
print(
"debug: _generate_text: "
f"using special key arrangements for '{iso3166_2}' (Singapore)",
"debug: _generate_text: " f"using special key arrangements for '{iso3166_2}' (Singapore)",
file=behaviour.stderr,
)
@ -1433,18 +1366,14 @@ def _generate_text(
seen_names: list[str] = [
detail
for detail in _unique(
[str(location.get(location_key, "")) for location_key in st_names]
)
for detail in _unique([str(location.get(location_key, "")) for location_key in st_names])
if detail != ""
]
if debug:
print(f"debug: _generate_text: {seen_names=}", file=behaviour.stderr)
general_global_info: list[str] = [
str(location.get(detail, "")) for detail in st_line6_keys
]
general_global_info: list[str] = [str(location.get(detail, "")) for detail in st_line6_keys]
for (
line_number,
@ -1464,11 +1393,11 @@ def _generate_text(
# filter: everything here should be True if the element is to be kept
if line_filter is False:
_filter = lambda e: [True]
_filter = lambda _: [True] # noqa: E731
else:
_filter = lambda ak: [
_filter = lambda ak: [ # noqa: E731
ak not in general_global_info,
not any(True if (ak in sn) else False for sn in seen_names),
not any(ak in sn for sn in seen_names),
]
text.append(
@ -1476,7 +1405,7 @@ def _generate_text(
line_number=line_number,
line_keys=line_keys,
separator=line_separator,
filter=_filter,
filter_func=_filter,
)
)
@ -1489,9 +1418,8 @@ def _generate_text(
)
case _:
raise NotImplementedError(
f"unknown mode '{mode}' (expected a TextGenerationEnum)"
)
msg = f"unknown mode '{mode}' (expected a TextGenerationEnum)"
raise NotImplementedError(msg)
def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
@ -1506,7 +1434,7 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
returns Result[str]
"""
if not isinstance(query, (PlusCodeQuery, LocalCodeQuery, LatlongQuery, StringQuery)):
if not isinstance(query, PlusCodeQuery | LocalCodeQuery | LatlongQuery | StringQuery):
query_result = parse_query(
behaviour=Behaviour(
query=str(query),
@ -1531,9 +1459,7 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
match behaviour.convert_to_type:
case ConversionResultTypeEnum.SHAREABLE_TEXT:
# get latlong and handle result
latlong_result: Result[Latlong] = query.to_lat_long_coord(
geocoder=behaviour.geocoder
)
latlong_result: Result[Latlong] = query.to_lat_long_coord(geocoder=behaviour.geocoder)
if not latlong_result:
return Result[str]("", error=latlong_result.error)
@ -1545,7 +1471,7 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
try:
location = behaviour.reverser(latlong_result.get())
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[str]("", error=exc)
if behaviour.debug:
@ -1585,11 +1511,9 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
# perform operation
try:
pluscode: str = _PlusCode_encode(
lat=latlong_query.get().latitude, lon=latlong_query.get().longitude
)
pluscode: str = _encode(lat=latlong_query.get().latitude, lon=latlong_query.get().longitude)
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[str]("", error=exc)
return Result[str](pluscode)
@ -1612,11 +1536,9 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
# reverse location and handle result
try:
location = behaviour.reverser(
query_latlong, level=LOCALITY_GEOCODER_LEVEL
)
location = behaviour.reverser(query_latlong, level=LOCALITY_GEOCODER_LEVEL)
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[str]("", error=exc)
if behaviour.debug:
@ -1624,13 +1546,14 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
# generate locality portion of local code
if behaviour.debug:
print(
stdout.write(
_generate_text(
location=location,
behaviour=behaviour,
mode=TextGenerationEnum.LOCALITY_TEXT,
debug=behaviour.debug,
).strip()
+ "\n"
)
portion_locality: str = _generate_text(
@ -1644,25 +1567,31 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
locality_latlong: Latlong = behaviour.geocoder(portion_locality)
# check now if bounding_box is set and valid
assert locality_latlong.bounding_box is not None, (
"(shortening) geocoder-returned latlong has .bounding_box=None"
f" - {locality_latlong.bounding_box}"
)
if getattr(locality_latlong, "bounding_box", None) is None:
msg = (
"(shortening) geocoder-returned latlong has .bounding_box=None"
f" - {locality_latlong.bounding_box}"
)
raise AttributeError(msg) # noqa: TRY301
assert len(locality_latlong.bounding_box) == 4, (
"(shortening) geocoder-returned latlong has len(.bounding_box) < 4"
f" - {locality_latlong.bounding_box}"
)
if len(locality_latlong.bounding_box) != 4: # noqa: PLR2004
msg = (
"(shortening) geocoder-returned latlong has len(.bounding_box) != 4"
f" - {locality_latlong.bounding_box}"
)
raise ValueError(msg) # noqa: TRY301
assert all([type(c) == float for c in locality_latlong.bounding_box]), (
"(shortening) geocoder-returned latlong has non-float in .bounding_box"
f" - {locality_latlong.bounding_box}"
)
if not all(type(c) == float(c) for c in locality_latlong.bounding_box):
msg = (
"(shortening) geocoder-returned latlong has non-float in .bounding_box"
f" - {locality_latlong.bounding_box}"
)
raise TypeError(msg) # noqa: TRY301
except Exception as exc:
except Exception as exc: # noqa: BLE001
return Result[str]("", error=exc)
plus_code = _PlusCode_encode(
plus_code = _encode(
lat=query_latlong.latitude,
lon=query_latlong.longitude,
)
@ -1671,47 +1600,27 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
check1 = (
# The center point of the feature is within 0.4 degrees latitude and 0.4
# degrees longitude
(
(query_latlong.latitude - 0.4)
<= locality_latlong.latitude
<= (query_latlong.latitude + 0.4)
),
(
(query_latlong.longitude - 0.4)
<= locality_latlong.longitude
<= (query_latlong.longitude + 0.4)
),
((query_latlong.latitude - 0.4) <= locality_latlong.latitude <= (query_latlong.latitude + 0.4)),
((query_latlong.longitude - 0.4) <= locality_latlong.longitude <= (query_latlong.longitude + 0.4)),
# The bounding box of the feature is less than 0.8 degrees high and wide.
abs(locality_latlong.bounding_box[0] - locality_latlong.bounding_box[1])
< 0.8,
abs(locality_latlong.bounding_box[2] - locality_latlong.bounding_box[3])
< 0.8,
abs(locality_latlong.bounding_box[0] - locality_latlong.bounding_box[1]) < 0.8, # noqa: PLR2004
abs(locality_latlong.bounding_box[2] - locality_latlong.bounding_box[3]) < 0.8, # noqa: PLR2004
)
check2 = (
# The center point of the feature is within 0.4 degrees latitude and 0.4
# degrees longitude"
(
(query_latlong.latitude - 8)
<= locality_latlong.latitude
<= (query_latlong.latitude + 8)
),
(
(query_latlong.longitude - 8)
<= locality_latlong.longitude
<= (query_latlong.longitude + 8)
),
((query_latlong.latitude - 8) <= locality_latlong.latitude <= (query_latlong.latitude + 8)),
((query_latlong.longitude - 8) <= locality_latlong.longitude <= (query_latlong.longitude + 8)),
# The bounding box of the feature is less than 0.8 degrees high and wide.
abs(locality_latlong.bounding_box[0] - locality_latlong.bounding_box[1])
< 16,
abs(locality_latlong.bounding_box[2] - locality_latlong.bounding_box[3])
< 16,
abs(locality_latlong.bounding_box[0] - locality_latlong.bounding_box[1]) < 16, # noqa: PLR2004
abs(locality_latlong.bounding_box[2] - locality_latlong.bounding_box[3]) < 16, # noqa: PLR2004
)
if check1:
return Result[str](f"{plus_code[4:]} {portion_locality}")
elif check2:
if check2:
return Result[str](f"{plus_code[2:]} {portion_locality}")
print(
@ -1739,9 +1648,7 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
return Result[str](str(latlong_result.get()))
case _:
return Result[str](
"", error=f"unknown conversion result type '{behaviour.convert_to_type}'"
)
return Result[str]("", error=f"unknown conversion result type '{behaviour.convert_to_type}'")
# command-line entry
@ -1755,12 +1662,9 @@ def cli() -> int:
# handle arguments and print version header
print(
f"surplus version {'.'.join([str(v) for v in VERSION])}{VERSION_SUFFIX}"
+ (f", debug mode" if behaviour.debug else "")
+ (", debug mode" if behaviour.debug else "")
+ (
(
f" ({BUILD_COMMIT[:10]}@{BUILD_BRANCH}, "
f'{BUILD_DATETIME.strftime("%a %d %b %Y %H:%M:%S %z")})'
)
(f" ({BUILD_COMMIT[:10]}@{BUILD_BRANCH}, " f'{BUILD_DATETIME.strftime("%a %d %b %Y %H:%M:%S %z")})')
if behaviour.debug or behaviour.version_header
else ""
),
@ -1768,7 +1672,7 @@ def cli() -> int:
)
if behaviour.version_header:
exit(0)
sysexit(0)
# parse query and handle result
query = parse_query(behaviour=behaviour)
@ -1796,4 +1700,4 @@ def cli() -> int:
if __name__ == "__main__":
exit(cli())
sysexit(cli())