Skip to content

Instantly share code, notes, and snippets.

@simonw
Created January 26, 2025 16:49
Show Gist options
  • Save simonw/178ea93ac035293744bde97270d6a7a0 to your computer and use it in GitHub Desktop.
Save simonw/178ea93ac035293744bde97270d6a7a0 to your computer and use it in GitHub Desktop.
Geocode using the API bulit into macOS CoreLocation
# /// 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()
@simonw
Copy link
Author

simonw commented Jan 26, 2025

Run like this:

uv run https://gist.githubusercontent.com/simonw/178ea93ac035293744bde97270d6a7a0/raw/88c817e4103034579ec7523d8591bf60aa11fa67/geocode.py \
  '500 Grove St, San Francisco'

Output:

Location found:
latitude: 37.777717
longitude: -122.42504
name: 500 Grove St
locality: San Francisco
country: United States

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment