surplus v2.2.0 (#38)

* build(deps-dev): bump black from 23.7.0 to 23.9.1 (#33)

Bumps [black](https://github.com/psf/black) from 23.7.0 to 23.9.1.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/23.7.0...23.9.1)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* meta: update devbox files

* ctt: type analyse

* ci: update devbox-install-action (#35)

* import protocol from typing straight (#36)

* ctt: update uq and np tests

* s+,docs: add termux-location json support (#37)

docs: update api accordingly

* meta: bump ver

* s+,ctt: fix italian addressing + add test (#34)

* st: fix regression in last commit + add per-line settings dict

* ctt: update modena test

* docs: update api docs for the new st constants

* ci,devbox: fix for ci

* ctt: update modena test

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Mark Joshwel 2023-10-15 04:06:30 +08:00 committed by GitHub
parent 533cdb2ce4
commit fdf3a86d84
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 511 additions and 265 deletions

View file

@ -15,7 +15,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: install devbox - name: install devbox
uses: jetpack-io/devbox-install-action@v0.3.0 uses: jetpack-io/devbox-install-action@v0.7.0
- name: install dependencies - name: install dependencies
run: devbox run poetry install run: devbox run poetry install
@ -28,10 +28,10 @@ jobs:
run: devbox run poetry run mypy . run: devbox run poetry run mypy .
- name: check for black formatting compliance - name: check for black formatting compliance
run: devbox run poetry run "black --check ." run: devbox run poetry run black --check .
- name: analyse isort compliance - name: analyse isort compliance
run: devbox run poetry run "isort --check *.py **/*.py" run: devbox run poetry run isort --check *.py **/*.py
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -40,7 +40,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: install devbox - name: install devbox
uses: jetpack-io/devbox-install-action@v0.3.0 uses: jetpack-io/devbox-install-action@v0.7.0
- name: install dependencies - name: install dependencies
run: devbox run poetry install run: devbox run poetry install

View file

@ -24,7 +24,7 @@ jobs:
uses: tj-actions/branch-names@v7 uses: tj-actions/branch-names@v7
- name: install devbox - name: install devbox
uses: jetpack-io/devbox-install-action@v0.6.1 uses: jetpack-io/devbox-install-action@v0.7.0
- name: install dependencies - name: install dependencies
run: devbox run poetry install run: devbox run poetry install

View file

@ -22,7 +22,7 @@ jobs:
uses: tj-actions/branch-names@v7 uses: tj-actions/branch-names@v7
- name: install devbox - name: install devbox
uses: jetpack-io/devbox-install-action@v0.6.1 uses: jetpack-io/devbox-install-action@v0.7.0
- name: install dependencies - name: install dependencies
run: devbox run poetry install run: devbox run poetry install

View file

@ -20,7 +20,7 @@ to iOS Shortcuts-like shareable text.
```text ```text
$ surplus 9R3J+R9 Singapore $ surplus 9R3J+R9 Singapore
surplus version 2.1.1 surplus version 2.2.0
Thomson Plaza Thomson Plaza
301 Upper Thomson Road 301 Upper Thomson Road
Sin Ming, Bishan Sin Ming, Bishan
@ -57,7 +57,7 @@ see [licence](#licence) for licensing information.
```text ```text
usage: surplus [-h] [-d] [-v] [-c {pluscode,localcode,latlong,sharetext}] usage: surplus [-h] [-d] [-v] [-c {pluscode,localcode,latlong,sharetext}]
[-u USER_AGENT] [-u USER_AGENT] [-t]
[query ...] [query ...]
Google Maps Plus Code to iOS Shortcuts-like shareable text Google Maps Plus Code to iOS Shortcuts-like shareable text
@ -79,6 +79,9 @@ options:
-u USER_AGENT, --user-agent USER_AGENT -u USER_AGENT, --user-agent USER_AGENT
user agent string to use for geocoding service, user agent string to use for geocoding service,
defaults to fingerprinted user agent string defaults to fingerprinted user agent string
-t, --using-termux-location
treats input as a termux-location output json
string, and parses it accordingly
``` ```
### example api usage ### example api usage
@ -260,7 +263,7 @@ of incorrect outputs.
```text ```text
$ s+ --debug 8QJF+RP Singapore $ s+ --debug 8QJF+RP Singapore
surplus version 2.1.1, debug mode (latest@future, Tue 05 Sep 2023 23:38:59 +0800) surplus version 2.2.0, debug mode (latest@future, Tue 05 Sep 2023 23:38:59 +0800)
debug: parse_query: behaviour.query=['8QJF+RP', 'Singapore'] debug: parse_query: behaviour.query=['8QJF+RP', 'Singapore']
debug: _match_plus_code: portion_plus_code='8QJF+RP', portion_locality='Singapore' debug: _match_plus_code: portion_plus_code='8QJF+RP', portion_locality='Singapore'
debug: cli: query=Result(value=LocalCodeQuery(code='8QJF+RP', locality='Singapore'), error=None) debug: cli: query=Result(value=LocalCodeQuery(code='8QJF+RP', locality='Singapore'), error=None)
@ -602,24 +605,62 @@ line breakdown of shareable text output, accompanied by their Nominatim keys:
> this constant only affects the default surplus Nominatim geocoding functions. custom > this constant only affects the default surplus Nominatim geocoding functions. custom
> functions do not read from this, unless deliberately programmed to do so > functions do not read from this, unless deliberately programmed to do so
- `SHAREABLE_TEXT_LINE_0_KEYS: typing.Final[tuple[str, ...]]` - `SHAREABLE_TEXT_LINE_0_KEYS: dict[str, tuple[str, ...]]`
`SHAREABLE_TEXT_LINE_1_KEYS: typing.Final[tuple[str, ...]]` `SHAREABLE_TEXT_LINE_1_KEYS: dict[str, tuple[str, ...]]`
`SHAREABLE_TEXT_LINE_2_KEYS: typing.Final[tuple[str, ...]]` `SHAREABLE_TEXT_LINE_2_KEYS: dict[str, tuple[str, ...]]`
`SHAREABLE_TEXT_LINE_3_KEYS: typing.Final[tuple[str, ...]]` `SHAREABLE_TEXT_LINE_3_KEYS: dict[str, tuple[str, ...]]`
`SHAREABLE_TEXT_LINE_4_KEYS: typing.Final[tuple[str, ...]]` `SHAREABLE_TEXT_LINE_4_KEYS: dict[str, tuple[str, ...]]`
`SHAREABLE_TEXT_LINE_5_KEYS: typing.Final[tuple[str, ...]]` `SHAREABLE_TEXT_LINE_5_KEYS: dict[str, tuple[str, ...]]`
`SHAREABLE_TEXT_LINE_6_KEYS: typing.Final[tuple[str, ...]]` `SHAREABLE_TEXT_LINE_6_KEYS: dict[str, tuple[str, ...]]`
a tuple of strings containing Nominatim keys used in shareable text line 0-6 a dictionary of iso3166-2 country-portion string keys with a tuple of Nominatim keys
used in shareable text line 0-6 as their values
- `SHAREABLE_TEXT_NAMES: typing.Final[tuple[str, ...]]` ```python
{
"default": (...),
"SG": (...,),
...
}
```
- `SHAREABLE_TEXT_LINE_SETTINGS: dict[str, dict[int, tuple[str, bool]]]`
a dictionary of iso3166-2 country-portion string keys with a dictionary as their values
the dictionary values are dictionaries with integers as keys, and a tuple of two strings
the first string is the separator string to use, and the second string is a boolean flag
that if `True` will check the line for seen names
```python
{
"default": {
0: (", ", False),
...
6: (", ", False),
},
"IT": {
0: (", ", False),
...
6: (", ", False),
},
...
}
```
- `SHAREABLE_TEXT_NAMES: dict[str, tuple[str, ...]]`
a dictionary of iso3166-2 country-portion string keys with a tuple of strings as their
values
a tuple of strings containing Nominatim keys used in shareable text line 0-2 and a tuple of strings containing Nominatim keys used in shareable text line 0-2 and
special keys in line 3 special keys in line 3
used for seen name checks
- `SHAREABLE_TEXT_LOCALITY: dict[str, tuple[str, ...]]` - `SHAREABLE_TEXT_LOCALITY: dict[str, tuple[str, ...]]`
a dictionary of iso3166-2 country-portion strings with a tuples of strings as their a dictionary of iso3166-2 country-portion string keys with a tuple of strings as their
values values
used when generating the locality portions of shortened Plus Codes/local codes used when generating the locality portions of shortened Plus Codes/local codes
@ -632,6 +673,9 @@ line breakdown of shareable text output, accompanied by their Nominatim keys:
} }
``` ```
- `SHAREABLE_TEXT_DEFAULT: typing.Final[str]`
constant for what is the "default" key in the `SHAREABLE*` constants
- `EMPTY_LATLONG: typing.Final[Latlong]` - `EMPTY_LATLONG: typing.Final[Latlong]`
a constant for an empty latlong coordinate, with latitude and longitude set to 0.0 a constant for an empty latlong coordinate, with latitude and longitude set to 0.0
@ -793,6 +837,9 @@ attributes
- `convert_to_type: ConversionResultTypeEnum = ConversionResultTypeEnum.SHAREABLE_TEXT` - `convert_to_type: ConversionResultTypeEnum = ConversionResultTypeEnum.SHAREABLE_TEXT`
what type to convert the query to what type to convert the query to
- `using_termux_location: bool = False`
treats query as a termux-location output json string, and parses it accordingly
### `class SurplusDefaultGeocoding` ### `class SurplusDefaultGeocoding`
> [!IMPORTANT] > [!IMPORTANT]
@ -1288,7 +1335,7 @@ it contains the following, in order, alongside an example:
1. `version` - the surplus version alongside a suffix, if any 1. `version` - the surplus version alongside a suffix, if any
```text ```text
2.1.1-local 2.2.0-local
``` ```
2. `system_info` - generic machine and operating system information 2. `system_info` - generic machine and operating system information
@ -1312,7 +1359,7 @@ it contains the following, in order, alongside an example:
after hashing, this string becomes a 12 character hexadecimal string, as shown below: after hashing, this string becomes a 12 character hexadecimal string, as shown below:
```text ```text
surplus/2.1.1-local (1fdbfa0b0cfb) surplus/2.2.0-local (1fdbfa0b0cfb)
^^^^^^^^^^^^ ^^^^^^^^^^^^
this is the hashed result of unique_info this is the hashed result of unique_info
``` ```

View file

@ -1,14 +1,11 @@
{ {
"packages": [ "packages": [
"python311", "python311@latest",
"python311Packages.ipykernel", "python311Packages.ipykernel@latest",
"poetry" "poetry@latest"
], ],
"shell": { "shell": {
"init_hook": [ "init_hook": ["poetry install"]
"poetry env use $(which python)",
"poetry shell"
]
}, },
"nixpkgs": { "nixpkgs": {
"commit": "f80ac848e3d6f0c12c52758c0f25c10c97ca3b62" "commit": "f80ac848e3d6f0c12c52758c0f25c10c97ca3b62"

View file

@ -1,15 +1,67 @@
{ {
"lockfile_version": "1", "lockfile_version": "1",
"packages": { "packages": {
"poetry": { "poetry@latest": {
"resolved": "github:NixOS/nixpkgs/f80ac848e3d6f0c12c52758c0f25c10c97ca3b62#poetry" "last_modified": "2023-10-04T02:19:08Z",
"plugin_version": "0.0.3",
"resolved": "github:NixOS/nixpkgs/d1c9180c6d1f8fce9469436f48c1cb8180d7087d#poetry",
"source": "devbox-search",
"version": "1.6.1",
"systems": {
"aarch64-darwin": {
"store_path": "/nix/store/i7q6kxa3ac7c57zalr4vwa04c1bll3xd-python3.10-poetry-1.6.1"
}, },
"python311": { "aarch64-linux": {
"store_path": "/nix/store/b0gmqd0y5pich25mk5p649g1bbbyxp0v-python3.10-poetry-1.6.1"
},
"x86_64-darwin": {
"store_path": "/nix/store/q5zqqp3k58z46q4imgmj5pxbinmzjyqf-python3.10-poetry-1.6.1"
},
"x86_64-linux": {
"store_path": "/nix/store/6v2zvmag2il359sbd8j1q7b3c20gs6yd-python3.10-poetry-1.6.1"
}
}
},
"python311@latest": {
"last_modified": "2023-09-27T18:02:17Z",
"plugin_version": "0.0.1", "plugin_version": "0.0.1",
"resolved": "github:NixOS/nixpkgs/f80ac848e3d6f0c12c52758c0f25c10c97ca3b62#python311" "resolved": "github:NixOS/nixpkgs/517501bcf14ae6ec47efd6a17dda0ca8e6d866f9#python311",
"source": "devbox-search",
"version": "3.11.4",
"systems": {
"aarch64-darwin": {
"store_path": "/nix/store/rycxjkclx801wrhwrgllak0302xzjdvx-python3-3.11.4"
}, },
"python311Packages.ipykernel": { "aarch64-linux": {
"resolved": "github:NixOS/nixpkgs/f80ac848e3d6f0c12c52758c0f25c10c97ca3b62#python311Packages.ipykernel" "store_path": "/nix/store/h4xi1djsmhk7bjdipz58xkfnf8lc9mpm-python3-3.11.4"
},
"x86_64-darwin": {
"store_path": "/nix/store/yqs2zxkxn61xzimdaz1pbgawk2lnm0d8-python3-3.11.4"
},
"x86_64-linux": {
"store_path": "/nix/store/3k7is7nc2xbav8a48vx7arad522d8czx-python3-3.11.4"
}
}
},
"python311Packages.ipykernel@latest": {
"last_modified": "2023-09-29T09:08:59Z",
"resolved": "github:NixOS/nixpkgs/bd9b686c0168041aea600222be0805a0de6e6ab8#python311Packages.ipykernel",
"source": "devbox-search",
"version": "6.21.2",
"systems": {
"aarch64-darwin": {
"store_path": "/nix/store/78gi0qk9lmrb4rk5ignww29p5j0l79gs-python3.11-ipykernel-6.21.2"
},
"aarch64-linux": {
"store_path": "/nix/store/74m55prblwmsyx1ylv135iqw2wqj4c6a-python3.11-ipykernel-6.21.2"
},
"x86_64-darwin": {
"store_path": "/nix/store/j0wpnwkdcqfp2bmp2b9pgzdngnmxzjj9-python3.11-ipykernel-6.21.2"
},
"x86_64-linux": {
"store_path": "/nix/store/3kqcf56q2q46hj0g5n4rxzzy1c9vdiqa-python3.11-ipykernel-6.21.2"
}
}
} }
} }
} }

83
poetry.lock generated
View file

@ -1,10 +1,9 @@
# This file is automatically @generated by Poetry and should not be changed by hand. # This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
[[package]] [[package]]
name = "appnope" name = "appnope"
version = "0.1.3" version = "0.1.3"
description = "Disable App Nap on macOS >= 10.9" description = "Disable App Nap on macOS >= 10.9"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -16,7 +15,6 @@ files = [
name = "asttokens" name = "asttokens"
version = "2.4.0" version = "2.4.0"
description = "Annotate AST trees with source code positions" description = "Annotate AST trees with source code positions"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -34,7 +32,6 @@ test = ["astroid", "pytest"]
name = "backcall" name = "backcall"
version = "0.2.0" version = "0.2.0"
description = "Specifications for callback functions passed in to an API" description = "Specifications for callback functions passed in to an API"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -44,34 +41,33 @@ files = [
[[package]] [[package]]
name = "black" name = "black"
version = "23.7.0" version = "23.9.1"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
category = "dev"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, {file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"},
{file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, {file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"},
{file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, {file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"},
{file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, {file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"},
{file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, {file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"},
{file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, {file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"},
{file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, {file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"},
{file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, {file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"},
{file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, {file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"},
{file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, {file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"},
{file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, {file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"},
{file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, {file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"},
{file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, {file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"},
{file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, {file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"},
{file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, {file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"},
{file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, {file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"},
{file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, {file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"},
{file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, {file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"},
{file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, {file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"},
{file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, {file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"},
{file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, {file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"},
{file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, {file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"},
] ]
[package.dependencies] [package.dependencies]
@ -93,7 +89,6 @@ uvloop = ["uvloop (>=0.15.2)"]
name = "click" name = "click"
version = "8.1.7" version = "8.1.7"
description = "Composable command line interface toolkit" description = "Composable command line interface toolkit"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -108,7 +103,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
name = "colorama" name = "colorama"
version = "0.4.6" version = "0.4.6"
description = "Cross-platform colored terminal text." description = "Cross-platform colored terminal text."
category = "dev"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [ files = [
@ -120,7 +114,6 @@ files = [
name = "decorator" name = "decorator"
version = "5.1.1" version = "5.1.1"
description = "Decorators for Humans" description = "Decorators for Humans"
category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -132,7 +125,6 @@ files = [
name = "executing" name = "executing"
version = "1.2.0" version = "1.2.0"
description = "Get the currently executing AST node of a frame, and other information" description = "Get the currently executing AST node of a frame, and other information"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -147,7 +139,6 @@ tests = ["asttokens", "littleutils", "pytest", "rich"]
name = "geographiclib" name = "geographiclib"
version = "2.0" version = "2.0"
description = "The geodesic routines from GeographicLib" description = "The geodesic routines from GeographicLib"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -159,7 +150,6 @@ files = [
name = "geopy" name = "geopy"
version = "2.4.0" version = "2.4.0"
description = "Python Geocoding Toolbox" description = "Python Geocoding Toolbox"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -183,7 +173,6 @@ timezone = ["pytz"]
name = "ipython" name = "ipython"
version = "8.15.0" version = "8.15.0"
description = "IPython: Productive Interactive Computing" description = "IPython: Productive Interactive Computing"
category = "dev"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
@ -222,7 +211,6 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa
name = "isort" name = "isort"
version = "5.12.0" version = "5.12.0"
description = "A Python utility / library to sort Python imports." description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false optional = false
python-versions = ">=3.8.0" python-versions = ">=3.8.0"
files = [ files = [
@ -240,7 +228,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"]
name = "jedi" name = "jedi"
version = "0.19.0" version = "0.19.0"
description = "An autocompletion tool for Python that can be used for text editors." description = "An autocompletion tool for Python that can be used for text editors."
category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -260,7 +247,6 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
name = "matplotlib-inline" name = "matplotlib-inline"
version = "0.1.6" version = "0.1.6"
description = "Inline Matplotlib backend for Jupyter" description = "Inline Matplotlib backend for Jupyter"
category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -275,7 +261,6 @@ traitlets = "*"
name = "mypy" name = "mypy"
version = "1.5.1" version = "1.5.1"
description = "Optional static typing for Python" description = "Optional static typing for Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -321,7 +306,6 @@ reports = ["lxml"]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker." description = "Type system extensions for programs checked with the mypy type checker."
category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -333,7 +317,6 @@ files = [
name = "packaging" name = "packaging"
version = "23.1" version = "23.1"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -345,7 +328,6 @@ files = [
name = "parso" name = "parso"
version = "0.8.3" version = "0.8.3"
description = "A Python Parser" description = "A Python Parser"
category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -361,7 +343,6 @@ testing = ["docopt", "pytest (<6.0.0)"]
name = "pathspec" name = "pathspec"
version = "0.11.2" version = "0.11.2"
description = "Utility library for gitignore style pattern matching of file paths." description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -373,7 +354,6 @@ files = [
name = "pexpect" name = "pexpect"
version = "4.8.0" version = "4.8.0"
description = "Pexpect allows easy control of interactive console applications." description = "Pexpect allows easy control of interactive console applications."
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -388,7 +368,6 @@ ptyprocess = ">=0.5"
name = "pickleshare" name = "pickleshare"
version = "0.7.5" version = "0.7.5"
description = "Tiny 'shelve'-like database with concurrency support" description = "Tiny 'shelve'-like database with concurrency support"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -400,7 +379,6 @@ files = [
name = "platformdirs" name = "platformdirs"
version = "3.10.0" version = "3.10.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -416,7 +394,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co
name = "pluscodes" name = "pluscodes"
version = "2022.1.3" version = "2022.1.3"
description = "Compute Plus Codes (Open Location Codes)." description = "Compute Plus Codes (Open Location Codes)."
category = "main"
optional = false optional = false
python-versions = ">=3.10" python-versions = ">=3.10"
files = [ files = [
@ -430,7 +407,6 @@ dev = ["black (==22.3.0)", "build (==0.8.0)", "coverage (==6.4)", "isort (==5.8.
name = "prompt-toolkit" name = "prompt-toolkit"
version = "3.0.39" version = "3.0.39"
description = "Library for building powerful interactive command lines in Python" description = "Library for building powerful interactive command lines in Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.7.0" python-versions = ">=3.7.0"
files = [ files = [
@ -445,7 +421,6 @@ wcwidth = "*"
name = "ptyprocess" name = "ptyprocess"
version = "0.7.0" version = "0.7.0"
description = "Run a subprocess in a pseudo terminal" description = "Run a subprocess in a pseudo terminal"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -457,7 +432,6 @@ files = [
name = "pure-eval" name = "pure-eval"
version = "0.2.2" version = "0.2.2"
description = "Safely evaluate AST nodes without side effects" description = "Safely evaluate AST nodes without side effects"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -472,7 +446,6 @@ tests = ["pytest"]
name = "pygments" name = "pygments"
version = "2.16.1" version = "2.16.1"
description = "Pygments is a syntax highlighting package written in Python." description = "Pygments is a syntax highlighting package written in Python."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -487,7 +460,6 @@ plugins = ["importlib-metadata"]
name = "six" name = "six"
version = "1.16.0" version = "1.16.0"
description = "Python 2 and 3 compatibility utilities" description = "Python 2 and 3 compatibility utilities"
category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
files = [ files = [
@ -499,7 +471,6 @@ files = [
name = "stack-data" name = "stack-data"
version = "0.6.2" version = "0.6.2"
description = "Extract data from python stack frames and tracebacks for informative displays" description = "Extract data from python stack frames and tracebacks for informative displays"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -519,7 +490,6 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
name = "tokenize-rt" name = "tokenize-rt"
version = "5.2.0" version = "5.2.0"
description = "A wrapper around the stdlib `tokenize` which roundtrips." description = "A wrapper around the stdlib `tokenize` which roundtrips."
category = "dev"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -531,7 +501,6 @@ files = [
name = "traitlets" name = "traitlets"
version = "5.9.0" version = "5.9.0"
description = "Traitlets Python configuration system" description = "Traitlets Python configuration system"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -547,7 +516,6 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"]
name = "typing-extensions" name = "typing-extensions"
version = "4.7.1" version = "4.7.1"
description = "Backported and Experimental Type Hints for Python 3.7+" description = "Backported and Experimental Type Hints for Python 3.7+"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -559,7 +527,6 @@ files = [
name = "wcwidth" name = "wcwidth"
version = "0.2.6" version = "0.2.6"
description = "Measures the displayed width of unicode strings in a terminal" description = "Measures the displayed width of unicode strings in a terminal"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -570,4 +537,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "f9270d7fb45c708e923f4afe041b26f77becb8e4adfcd517742e67f6b8f9d6b9" content-hash = "3f2847d76a104121389f12d4f82841153b114d479c8ddba0c5a78994b544d0d6"

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "surplus" name = "surplus"
version = "2.1.1" version = "2.2.0"
description = "Python script to convert Google Maps Plus Codes to iOS Shortcuts-like shareable text." description = "Python script to convert Google Maps Plus Codes to iOS Shortcuts-like shareable text."
authors = ["Mark Joshwel <mark@joshwel.co>"] authors = ["Mark Joshwel <mark@joshwel.co>"]
license = "Unlicense" license = "Unlicense"
@ -17,7 +17,7 @@ pluscodes = "^2022.1.3"
geopy = "^2.3.0" geopy = "^2.3.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
black = {extras = ["jupyter"], version = "^23.7.0"} black = {extras = ["jupyter"], version = "^23.9.1"}
mypy = "^1.5.1" mypy = "^1.5.1"
isort = "^5.12.0" isort = "^5.12.0"

View file

@ -31,11 +31,14 @@ For more information, please refer to <http://unlicense.org/>
from argparse import ArgumentParser from argparse import ArgumentParser
from collections import OrderedDict from collections import OrderedDict
from copy import deepcopy
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from enum import Enum from enum import Enum
from functools import lru_cache from functools import lru_cache
from hashlib import shake_256 from hashlib import shake_256
from json import loads as json_loads
from json.decoder import JSONDecodeError
from platform import platform from platform import platform
from socket import gethostname from socket import gethostname
from sys import stderr, stdin, stdout from sys import stderr, stdin, stdout
@ -45,6 +48,7 @@ from typing import (
Final, Final,
Generic, Generic,
NamedTuple, NamedTuple,
Protocol,
Sequence, Sequence,
TextIO, TextIO,
TypeAlias, TypeAlias,
@ -55,12 +59,9 @@ from uuid import getnode
from geopy import Location as _geopy_Location # type: ignore from geopy import Location as _geopy_Location # type: ignore
from geopy.extra.rate_limiter import RateLimiter as _geopy_RateLimiter # 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 geopy.geocoders import Nominatim as _geopy_Nominatim # type: ignore
from pluscodes import Area as _PlusCode_Area # type: ignore
from pluscodes import PlusCode as _PlusCode # type: ignore from pluscodes import PlusCode as _PlusCode # type: ignore
from pluscodes import decode as _PlusCode_decode # type: ignore
from pluscodes import encode as _PlusCode_encode # type: ignore from pluscodes import encode as _PlusCode_encode # type: ignore
from pluscodes.validator import Validator as _PlusCode_Validator # type: ignore from pluscodes.validator import Validator as _PlusCode_Validator # type: ignore
from typing_extensions import Protocol
from pluscodes.openlocationcode import ( # type: ignore # isort: skip from pluscodes.openlocationcode import ( # type: ignore # isort: skip
recoverNearest as _PlusCode_recoverNearest, recoverNearest as _PlusCode_recoverNearest,
@ -68,14 +69,19 @@ from pluscodes.openlocationcode import ( # type: ignore # isort: skip
# constants # constants
VERSION: Final[tuple[int, int, int]] = (2, 1, 1) VERSION: Final[tuple[int, int, int]] = (2, 2, 0)
VERSION_SUFFIX: Final[str] = "-local" VERSION_SUFFIX: Final[str] = "-local"
BUILD_BRANCH: Final[str] = "future" BUILD_BRANCH: Final[str] = "future"
BUILD_COMMIT: Final[str] = "latest" BUILD_COMMIT: Final[str] = "latest"
BUILD_DATETIME: Final[datetime] = datetime.now(timezone(timedelta(hours=8))) # using SGT BUILD_DATETIME: Final[datetime] = datetime.now(timezone(timedelta(hours=8))) # using SGT
CONNECTION_MAX_RETRIES: int = 9 CONNECTION_MAX_RETRIES: int = 9
CONNECTION_WAIT_SECONDS: int = 10 CONNECTION_WAIT_SECONDS: int = 10
SHAREABLE_TEXT_LINE_0_KEYS: Final[tuple[str, ...]] = ( LOCALITY_GEOCODER_LEVEL: int = 13 # adjusts geocoder zoom level when
# geocoding latlong into an address
# default shareable text line keys
SHAREABLE_TEXT_LINE_0_KEYS: dict[str, tuple[str, ...]] = {
"default": (
"emergency", "emergency",
"historic", "historic",
"military", "military",
@ -98,23 +104,23 @@ SHAREABLE_TEXT_LINE_0_KEYS: Final[tuple[str, ...]] = (
"bridge", "bridge",
"tunnel", "tunnel",
"waterway", "waterway",
) ),
SHAREABLE_TEXT_LINE_1_KEYS: Final[tuple[str, ...]] = ("building",) }
SHAREABLE_TEXT_LINE_2_KEYS: Final[tuple[str, ...]] = ("highway",) SHAREABLE_TEXT_LINE_1_KEYS: dict[str, tuple[str, ...]] = {
"default": ("building",),
SHAREABLE_TEXT_LINE_3_KEYS: Final[tuple[str, ...]] = ( }
SHAREABLE_TEXT_LINE_2_KEYS: dict[str, tuple[str, ...]] = {
"default": ("highway",),
}
SHAREABLE_TEXT_LINE_3_KEYS: dict[str, tuple[str, ...]] = {
"default": (
"house_number", "house_number",
"house_name", "house_name",
"road", "road",
) ),
# special line 3 keys for Italian addresses (IT) }
SHAREABLE_TEXT_LINE_3_KEYS_IT: Final[tuple[str, ...]] = ( SHAREABLE_TEXT_LINE_4_KEYS: dict[str, tuple[str, ...]] = {
"road", "default": (
"house_number",
"house_name",
)
SHAREABLE_TEXT_LINE_4_KEYS: Final[tuple[str, ...]] = (
"residential", "residential",
"neighbourhood", "neighbourhood",
"allotments", "allotments",
@ -128,29 +134,112 @@ SHAREABLE_TEXT_LINE_4_KEYS: Final[tuple[str, ...]] = (
"city", "city",
"town", "town",
"village", "village",
) ),
SHAREABLE_TEXT_LINE_5_KEYS: Final[tuple[str, ...]] = ("postcode",) }
SHAREABLE_TEXT_LINE_6_KEYS: Final[tuple[str, ...]] = ( SHAREABLE_TEXT_LINE_5_KEYS: dict[str, tuple[str, ...]] = {
"default": ("postcode",),
}
SHAREABLE_TEXT_LINE_6_KEYS: dict[str, tuple[str, ...]] = {
"default": (
"region", "region",
"county", "county",
"state", "state",
"state_district", "state_district",
"country", "country",
"continent", "continent",
) ),
SHAREABLE_TEXT_NAMES: Final[tuple[str, ...]] = ( }
SHAREABLE_TEXT_LINE_0_KEYS SHAREABLE_TEXT_LINE_SETTINGS: dict[str, dict[int, tuple[str, bool]]] = {
+ SHAREABLE_TEXT_LINE_1_KEYS # line number: (string separator to use, whether to check for seen names)
+ SHAREABLE_TEXT_LINE_2_KEYS "default": {
0: (", ", False),
1: (", ", False),
2: (", ", False),
3: (" ", False),
4: (", ", True),
5: (", ", False),
6: (", ", False),
},
}
SHAREABLE_TEXT_NAMES: dict[str, tuple[str, ...]] = {
"default": (
SHAREABLE_TEXT_LINE_0_KEYS["default"]
+ SHAREABLE_TEXT_LINE_1_KEYS["default"]
+ SHAREABLE_TEXT_LINE_2_KEYS["default"]
+ ("house_name", "road") + ("house_name", "road")
) ),
}
SHAREABLE_TEXT_LOCALITY: dict[str, tuple[str, ...]] = { SHAREABLE_TEXT_LOCALITY: dict[str, tuple[str, ...]] = {
"default": ("city_district", "district", "city", *SHAREABLE_TEXT_LINE_6_KEYS), "default": (
"city_district",
"district",
"city",
*SHAREABLE_TEXT_LINE_6_KEYS["default"],
),
}
SHAREABLE_TEXT_DEFAULT: Final[str] = "default"
# special per-country key arrangements for SG/Singapore
SHAREABLE_TEXT_LOCALITY.update(
{
"SG": ("country",), "SG": ("country",),
} }
)
# special per-country key arrangements for IT/Italy
SHAREABLE_TEXT_LINE_3_KEYS.update(
{
"IT": (
"road",
"house_number",
"house_name",
),
}
)
SHAREABLE_TEXT_LINE_5_KEYS.update(
{
"IT": (
"postcode",
"region",
"county",
"state",
"state_district",
),
},
)
SHAREABLE_TEXT_LINE_6_KEYS.update(
{
"IT": (
"country",
"continent",
),
}
)
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(),
},
)
SHAREABLE_TEXT_LINE_5_KEYS.update(
{
"MY": (
"postcode",
*SHAREABLE_TEXT_LINE_4_KEYS["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)
# adjusts geocoder zoom level when geocoding latlong into an address
LOCALITY_GEOCODER_LEVEL: int = 13
# exceptions # exceptions
@ -819,6 +908,8 @@ class Behaviour(NamedTuple):
whether to print version information and exit whether to print version information and exit
convert_to_type: ConversionResultTypeEnum = ConversionResultTypeEnum.SHAREABLE_TEXT convert_to_type: ConversionResultTypeEnum = ConversionResultTypeEnum.SHAREABLE_TEXT
what type to convert query to what type to convert query to
using_termux_location: bool = False
treats query as a termux-location output json string, and parses it accordingly
""" """
query: str | list[str] = "" query: str | list[str] = ""
@ -829,6 +920,7 @@ class Behaviour(NamedTuple):
debug: bool = False debug: bool = False
version_header: bool = False version_header: bool = False
convert_to_type: ConversionResultTypeEnum = ConversionResultTypeEnum.SHAREABLE_TEXT convert_to_type: ConversionResultTypeEnum = ConversionResultTypeEnum.SHAREABLE_TEXT
using_termux_location: bool = False
# functions # functions
@ -967,7 +1059,46 @@ def parse_query(behaviour: Behaviour) -> Result[Query]:
file=behaviour.stderr, file=behaviour.stderr,
) )
# not a plus/local code, try to match for latlong or string query # check if termux-location json
if behaviour.using_termux_location:
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")
return Result[Query](
LatlongQuery(
Latlong(
latitude=termux_location_json["latitude"],
longitude=termux_location_json["longitude"],
)
)
)
except (JSONDecodeError, TypeError) as exc:
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=ValueError("could not parse termux-location json"),
)
except KeyError as exc:
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=ValueError(
"could not get 'latitude' or 'longitude' keys from termux-location json"
),
)
except Exception as exc:
return Result[Query](
LatlongQuery(EMPTY_LATLONG),
error=exc,
)
# unreachable
# not a plus/local code/termux-location json,
# try to match for latlong or string query
match split_query: match split_query:
case [single]: case [single]:
# possibly a: # possibly a:
@ -1081,11 +1212,19 @@ def handle_args() -> Behaviour:
help=f"user agent string to use for geocoding service, defaults to fingerprinted user agent string", help=f"user agent string to use for geocoding service, defaults to fingerprinted user agent string",
default=default_fingerprint, default=default_fingerprint,
) )
parser.add_argument(
"-t",
"--using-termux-location",
action="store_true",
default=False,
help="treats input as a termux-location output json string, and parses it accordingly",
)
# initialisation
args = parser.parse_args() args = parser.parse_args()
query: str | list[str] = "" query: str | list[str] = ""
# "-" stdin check
if args.query == ["-"]: if args.query == ["-"]:
stdin_query: list[str] = [] stdin_query: list[str] = []
@ -1097,8 +1236,8 @@ def handle_args() -> Behaviour:
else: else:
query = args.query query = args.query
# setup structures and return
geocoding = SurplusDefaultGeocoding(args.user_agent) geocoding = SurplusDefaultGeocoding(args.user_agent)
behaviour = Behaviour( behaviour = Behaviour(
query=query, query=query,
geocoder=geocoding.geocoder, geocoder=geocoding.geocoder,
@ -1108,8 +1247,8 @@ def handle_args() -> Behaviour:
debug=args.debug, debug=args.debug,
version_header=args.version, version_header=args.version,
convert_to_type=ConversionResultTypeEnum(args.convert_to), convert_to_type=ConversionResultTypeEnum(args.convert_to),
using_termux_location=args.using_termux_location,
) )
return behaviour return behaviour
@ -1147,7 +1286,7 @@ def _generate_text(
def _generate_text_line( def _generate_text_line(
line_number: int, line_number: int,
line_keys: Sequence[str], line_keys: Sequence[str],
seperator: str = ", ", separator: str = ", ",
filter: Callable[[str], list[bool]] = lambda e: [True], filter: Callable[[str], list[bool]] = lambda e: [True],
) -> str: ) -> str:
""" """
@ -1158,8 +1297,8 @@ def _generate_text(
line number to prefix with line number to prefix with
line_keys: Sequence[str] line_keys: Sequence[str]
list of keys to .get() from location dict list of keys to .get() from location dict
seperator: str = ", " separator: str = ", "
seperator to join elements with separator to join elements with
filter: Callable[[str], list[bool]] = lambda e: True filter: Callable[[str], list[bool]] = lambda e: True
function that takes in a string and returns a list of bools, used to 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 filter elements from line_keys. list will be passed to all(). if all
@ -1199,9 +1338,37 @@ def _generate_text(
) )
continue continue
line = line_prefix + seperator.join(basket) line = line_prefix + separator.join(basket)
return (line + "\n") if (line != "") else "" return (line + "\n") if (line != "") else ""
C = TypeVar("C")
def stget(split_iso3166_2: list[str], line_keys: dict[str, C]) -> tuple[bool, C]:
"""
(internal function)
arguments:
split_iso3166_2: list[str]
the dash-split iso 3166-2 country code
line_keys:
the shareable text line keys dict to use
returns tuple[bool, C]
bool: whether the a special key arrangement was used
C: dict content
"""
DEFAULT = "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]
# iso3166-2 handling: this allows surplus to have special key arrangements for a # iso3166-2 handling: this allows surplus to have special key arrangements for a
# specific iso3166-2 code for edge cases # specific iso3166-2 code for edge cases
# (https://en.wikipedia.org/wiki/ISO_3166-2) # (https://en.wikipedia.org/wiki/ISO_3166-2)
@ -1220,49 +1387,46 @@ def _generate_text(
file=behaviour.stderr, file=behaviour.stderr,
) )
# skeleton code to allow for changing keys based on iso3166-2 code n_used_special: int = 0 # number of special key arrangements used
st_line0_keys = SHAREABLE_TEXT_LINE_0_KEYS
st_line1_keys = SHAREABLE_TEXT_LINE_1_KEYS
st_line2_keys = SHAREABLE_TEXT_LINE_2_KEYS
st_line3_keys = SHAREABLE_TEXT_LINE_3_KEYS
st_line4_keys = SHAREABLE_TEXT_LINE_4_KEYS
st_line5_keys = SHAREABLE_TEXT_LINE_5_KEYS
st_line6_keys = SHAREABLE_TEXT_LINE_6_KEYS
st_names = SHAREABLE_TEXT_NAMES
st_locality: tuple[str, ...] = ()
# special key arrangements for edge cases in local/regional address formats # skeleton code to allow for changing keys based on iso3166-2 code
match split_iso3166_2: used_special, st_line0_keys = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_0_KEYS)
case ["SG", *_]: # Singapore n_used_special += used_special
if debug:
used_special, st_line1_keys = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_1_KEYS)
n_used_special += used_special
used_special, st_line2_keys = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_2_KEYS)
n_used_special += used_special
used_special, st_line3_keys = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_3_KEYS)
n_used_special += used_special
used_special, st_line4_keys = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_4_KEYS)
n_used_special += used_special
used_special, st_line5_keys = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_5_KEYS)
n_used_special += used_special
used_special, st_line6_keys = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_6_KEYS)
n_used_special += used_special
used_special, st_names = stget(split_iso3166_2, SHAREABLE_TEXT_NAMES)
n_used_special += used_special
used_special, st_locality = stget(split_iso3166_2, SHAREABLE_TEXT_LOCALITY)
n_used_special += used_special
used_special, st_line_settings = stget(split_iso3166_2, SHAREABLE_TEXT_LINE_SETTINGS)
n_used_special += used_special
if n_used_special and debug:
print( print(
"debug: _generate_text: " "debug: _generate_text: "
f"using special key arrangements for '{iso3166_2}' (Singapore)", f"using special key arrangements for '{iso3166_2}' (Singapore)",
file=behaviour.stderr, file=behaviour.stderr,
) )
st_locality = SHAREABLE_TEXT_LOCALITY[split_iso3166_2[0]]
case ["IT", *_]: # Italy
if debug:
print(
"debug: _generate_text: "
f"using special key arrangements for '{iso3166_2}' (Italy)",
file=behaviour.stderr,
)
st_line3_keys = SHAREABLE_TEXT_LINE_3_KEYS_IT
case _: # default
if debug:
print(
"debug: _generate_text: "
f"using default key arrangements for '{iso3166_2}'",
file=behaviour.stderr,
)
st_locality = SHAREABLE_TEXT_LOCALITY["default"]
# start generating text # start generating text
match mode: match mode:
case TextGenerationEnum.SHAREABLE_TEXT: case TextGenerationEnum.SHAREABLE_TEXT:
@ -1283,52 +1447,37 @@ def _generate_text(
str(location.get(detail, "")) for detail in st_line6_keys str(location.get(detail, "")) for detail in st_line6_keys
] ]
text.append( for (
_generate_text_line( line_number,
line_number=0, line_keys,
line_keys=st_line0_keys, ) in enumerate(
) [
) st_line0_keys,
text.append( st_line1_keys,
_generate_text_line( st_line2_keys,
line_number=1, st_line3_keys,
line_keys=st_line1_keys, st_line4_keys,
) st_line5_keys,
) st_line6_keys,
text.append( ]
_generate_text_line( ):
line_number=2, line_separator, line_filter = st_line_settings[line_number]
line_keys=st_line2_keys,
) # filter: everything here should be True if the element is to be kept
) if line_filter is False:
text.append( _filter = lambda e: [True]
_generate_text_line( else:
line_number=3, _filter = lambda ak: [
line_keys=st_line3_keys,
seperator=" ",
)
)
text.append(
_generate_text_line(
line_number=4,
line_keys=st_line4_keys,
filter=lambda ak: [
# everything here should be True if the element is to be kept
ak not in general_global_info, ak not in general_global_info,
not any(True if (ak in sn) else False for sn in seen_names), not any(True if (ak in sn) else False for sn in seen_names),
], ]
)
)
text.append( text.append(
_generate_text_line( _generate_text_line(
line_number=5, line_number=line_number,
line_keys=st_line5_keys, line_keys=line_keys,
) separator=line_separator,
) filter=_filter,
text.append(
_generate_text_line(
line_number=6,
line_keys=st_line6_keys,
) )
) )
@ -1602,9 +1751,9 @@ def surplus(query: Query | str, behaviour: Behaviour) -> Result[str]:
def cli() -> int: def cli() -> int:
"""command-line entry point, returns an exit code int""" """command-line entry point, returns an exit code int"""
# handle arguments and print version header
behaviour = handle_args() behaviour = handle_args()
# handle arguments and print version header
print( print(
f"surplus version {'.'.join([str(v) for v in VERSION])}{VERSION_SUFFIX}" f"surplus version {'.'.join([str(v) for v in VERSION])}{VERSION_SUFFIX}"
+ (f", debug mode" if behaviour.debug else "") + (f", debug mode" if behaviour.debug else "")

42
test.py
View file

@ -1,5 +1,3 @@
# type: ignore
""" """
surplus test runner surplus test runner
------------------- -------------------
@ -58,7 +56,7 @@ class TestFailure(NamedTuple):
tests: list[ContinuityTest] = [ tests: list[ContinuityTest] = [
ContinuityTest( ContinuityTest(
query="8R3M+F8 Singapore", query="8R3M+F8 Singapore",
expected=("Wisma Atria\n" "435 Orchard Road\n" "238877\n" "Central, Singapore"), expected=[("Wisma Atria\n" "435 Orchard Road\n" "238877\n" "Central, Singapore")],
), ),
ContinuityTest( ContinuityTest(
query="9R3J+R9 Singapore", query="9R3J+R9 Singapore",
@ -96,6 +94,13 @@ tests: list[ContinuityTest] = [
"4072\n" "4072\n"
"Queensland, Australia" "Queensland, Australia"
), ),
(
"The University of Queensland\n"
"Hawken Drive\n"
"St Lucia, Greater Brisbane\n"
"4072\n"
"Queensland, Australia"
),
], ],
), ),
ContinuityTest( ContinuityTest(
@ -107,7 +112,14 @@ tests: list[ContinuityTest] = [
"Bukit Timah\n" "Bukit Timah\n"
"599489\n" "599489\n"
"Northwest, Singapore" "Northwest, Singapore"
) ),
(
"Ngee Ann Polytechnic\n"
"535 Clementi Road\n"
"Ewart Park, Bukit Timah\n"
"599489\n"
"Northwest, Singapore"
),
], ],
), ),
ContinuityTest( ContinuityTest(
@ -139,6 +151,28 @@ tests: list[ContinuityTest] = [
), ),
], ],
), ),
ContinuityTest(
query="J286+WV San Cesario sul Panaro, Modena, Italy",
expected=[
(
"Via Emilia 1193a\n"
"Unione dei comuni del Sorbara, Sant'Anna\n"
"41018 Modena Emilia-Romagna\n"
"Italia"
),
],
),
ContinuityTest(
query="GQ2G+GX Johor Bahru, Johor, Malaysia",
expected=[
(
"The Mall, Mid Valley Southkey\n"
"Jalan Bakar Batu\n"
"81100 Taman Sentosa Johor Bahru\n"
"Iskandar Malaysia, Johor, Malaysia"
),
],
),
] ]