262588213843476 · Gist

# /// script
# requires-python = ">=3.12"
# dependencies = [
# "pyobjc-core",
# "pyobjc-framework-CoreLocation",
# "click"
# ]
# ///
"""Basic geocoding using CoreLocation on macOS."""
import click
import objc
from CoreLocation import CLGeocoder
from Foundation import NSRunLoop, NSDate
def forward_geocode(address: str) -> list[dict]:
with objc.autorelease_pool():
geocoder = CLGeocoder.alloc().init()
results = {"placemarks": [], "error": None}
completed = False
def completion(placemarks, error):
nonlocal completed
if error:
results["error"] = error.localizedDescription()
elif placemarks:
results["placemarks"] = placemarks
completed = True
geocoder.geocodeAddressString_completionHandler_(address, completion)
while not completed:
NSRunLoop.currentRunLoop().runMode_beforeDate_(
"NSDefaultRunLoopMode",
NSDate.dateWithTimeIntervalSinceNow_(0.1)
)
if results["error"]:
raise Exception(f"Geocoding error: {results['error']}")
return [{
"latitude": pm.location().coordinate().latitude,
"longitude": pm.location().coordinate().longitude,
"name": pm.name(),
"locality": pm.locality(),
"country": pm.country()
} for pm in results["placemarks"]]
@click.command()
@click.argument('address')
def main(address):
try:
locations = forward_geocode(address)
for loc in locations:
click.echo("\nLocation found:")
for key, value in loc.items():
if value:
click.echo(f"{key}: {value}")
except Exception as e:
click.echo(f"Error: {e}", err=True)
raise click.Abort()
if __name__ == "__main__":
main()

Read the original on gist.github.com ↗