Geocoding

The geocoding module provides utilities for geographic data processing, address geocoding, and coordinate manipulation.

Module Overview

exception siege_utilities.geo.geocoding.GeocodingError[source]

Bases: RuntimeError

Raised when Nominatim geocoding fails for reasons other than ‘no match’.

Covers network timeouts (after retries exhausted), service errors, parse errors, and other unexpected failures from the geocoder. Distinct from a legitimate “no result found” outcome, which still returns None. Use __cause__ to inspect the underlying exception.

Mirrors siege_utilities.geo.providers.census_geocoder.CensusGeocodeError.

siege_utilities.geo.geocoding.get_country_name(country_code)[source]

Get the full country name from a country code.

Parameters:

country_code – Two-letter country code (e.g., ‘us’, ‘gb’, ‘ca’)

Returns:

Full country name or the code if not found

Return type:

str

siege_utilities.geo.geocoding.get_country_code(country_name)[source]

Get the country code from a country name.

Parameters:

country_name – Full country name (e.g., ‘United States’, ‘Canada’)

Returns:

Two-letter country code, or None if not found.

Return type:

str | None

siege_utilities.geo.geocoding.list_countries()[source]

Get a list of all available countries with their codes.

Returns:

Dictionary mapping country codes to country names

Return type:

dict

siege_utilities.geo.geocoding.concatenate_addresses(street=None, city=None, state_province_area=None, postal_code=None, country=None)[source]

Concatenate address components into a single string suitable for geocoding. Returns a properly formatted address string.

siege_utilities.geo.geocoding.get_coordinates(query_address, country_codes=None, max_retries=3, server_url=None)[source]

Get coordinates (latitude, longitude) for an address using Nominatim.

Parameters:
  • query_address – The address to geocode

  • country_codes – Optional country code filter (defaults to US)

  • max_retries – Maximum number of retry attempts

  • server_url – Optional custom Nominatim server URL (e.g., “http://nominatim.nominatim.svc.cluster.local” for self-hosted). Defaults to None (public OSM Nominatim).

Returns:

(latitude, longitude), or None when Nominatim returned no match for the address (a legitimate non-error outcome).

Return type:

tuple

Raises:
  • ValueError – If query_address is empty or None.

  • GeocodingError – If geocoding failed due to a network, service, or parse error — i.e., the geocoder could not even attempt to match. Wraps the underlying exception via __cause__.

siege_utilities.geo.geocoding.use_nominatim_geocoder(query_address, id=None, country_codes=None, max_retries=3, server_url=None)[source]

Geocode an address using Nominatim with proper rate limiting and error handling. Returns the result as a JSON string for Spark UDF compatibility.

Parameters:
  • query_address – The address to geocode

  • id – An identifier for tracking

  • country_codes – Optional country code filter (defaults to US)

  • max_retries – Number of retry attempts for transient errors

  • server_url – Optional custom Nominatim server URL (e.g., “http://nominatim.nominatim.svc.cluster.local” for self-hosted). Defaults to None (public OSM Nominatim with rate limiting). When set, rate limiting is skipped (self-hosted servers don’t require it).

Returns:

JSON string of the geocoding result, or None when Nominatim returned no match for the address (a legitimate non-error outcome).

Raises:
  • ValueError – If query_address is empty or None.

  • GeocodingError – If geocoding failed due to a network, service, or parse error after retries (i.e., the geocoder could not even attempt to match). Wraps the underlying geopy exception via __cause__.

siege_utilities.geo.geocoding.geocode_with_nominatim_public(address, country_codes=None)[source]

Geocode a single address using the public Nominatim service.

Thin wrapper around get_coordinates() that forces the public endpoint (no custom server_url).

Parameters:
  • address – Address string to geocode.

  • country_codes – Optional country code filter (defaults to US).

Returns:

(lat, lon) tuple, or None if no match found.

Raises:
siege_utilities.geo.geocoding.geocode_addresses_with_nominatim(addresses, country_codes=None, max_retries=3, server_url=None)[source]

Batch-geocode a list of addresses using Nominatim.

Calls get_coordinates() for each address sequentially with Nominatim’s built-in rate limiting (1 s for public, 50 ms for self-hosted).

Parameters:
  • addresses – Iterable of address strings.

  • country_codes – Optional country code filter (defaults to US).

  • max_retries – Retry attempts per address.

  • server_url – Optional custom Nominatim server URL.

Returns:

List of {"address": str, "lat": float, "lon": float} dicts. Addresses that returned no match have lat and lon set to None. Addresses that raised GeocodingError are logged and included with None coordinates.

class siege_utilities.geo.geocoding.NominatimGeoClassifier[source]

Bases: object

A classifier for geocoding results using Nominatim. Provides methods to categorize and analyze geocoding results.

__init__()[source]
get_place_ranks_by_label(label)[source]

Reverse lookup on place_rank_dict: label → matching rank IDs.

Nominatim returns an integer place_rank per result (0=country … 10=building). This helper goes the other direction so callers can write filter(rank=cls.get_place_ranks_by_label("City")) without hard-coding the integer.

Returns [] (not None) when the label is unknown so the caller can in / iterate without a None-check.

get_importance_threshold_by_label(label)[source]

Reverse lookup on importance_dict: label → importance threshold.

Nominatim’s importance field is a float in [0, 1] that mixes Wikipedia hit-count, place type, and population. We bucket those floats into ordinal labels (Country / State / …) and this method returns the float threshold that corresponds to a label — useful when filtering a Nominatim result set programmatically.

Returns None when no label matches; callers should treat that as “don’t filter on importance.”

to_json()[source]

Serialize the classifier’s lookup tables to a JSON string.

Used to persist customised rank/importance overrides between runs or to ship a classifier configuration to a worker process. The result round-trips through from_json().

from_json(json_string)[source]

Replace the classifier’s lookup tables from a JSON string.

Parameters:

json_string – JSON produced by to_json().

Inverse of to_json() — overwrites place_rank_dict and importance_dict in place. Unknown top-level keys are ignored; missing keys leave the corresponding table empty rather than raising, so a partial payload doesn’t poison the classifier.

siege_utilities.geo.geocoding.validate_geocode_data_pandas(df, lat_col, lon_col, crs=None)[source]

Filter rows with invalid geographic coordinates.

Pandas equivalent of spark_utils.validate_geocode_data().

Parameters:
  • df (pandas.DataFrame) – Input DataFrame.

  • lat_col (str) – Name of the latitude column.

  • lon_col (str) – Name of the longitude column.

  • crs – Optional CRS (pyproj CRS, EPSG int, or string). When supplied, the valid coordinate bounds are derived from the CRS area of use. Defaults to WGS84 (-90..90, -180..180).

Returns:

DataFrame with only rows whose coordinates fall within the valid range.

Return type:

pandas.DataFrame

siege_utilities.geo.geocoding.mark_valid_geocode_data_pandas(df, lat_col, lon_col, output_col='is_valid', crs=None)[source]

Add a boolean validity column without removing rows.

Pandas equivalent of spark_utils.mark_valid_geocode_data().

Parameters:
  • df (pandas.DataFrame) – Input DataFrame.

  • lat_col (str) – Name of the latitude column.

  • lon_col (str) – Name of the longitude column.

  • output_col (str) – Name of the boolean column to add.

  • crs – Optional CRS (pyproj CRS, EPSG int, or string). When supplied, the valid coordinate bounds are derived from the CRS area of use. Defaults to WGS84 (-90..90, -180..180).

Returns:

Copy of df with output_col appended.

Return type:

pandas.DataFrame

class siege_utilities.geo.geocoding.SpatiaLiteCache[source]

Bases: object

SpatiaLite-backed local cache for geocoding results and boundary lookups.

Stores: - geocode results: address_hash → (lat, lon, WKT point, source, timestamp) - boundary lookups: geoid → (point WKT, boundary WKT, vintage_year) - crosswalk mappings: (source_geoid, target_geoid) → weight

Spatial index on point geometry enables bounding-box queries. The database file is portable across machines.

Usage:

cache = SpatiaLiteCache()
cache.put_geocode("123 Main St, Springfield, IL 62701", 39.7817, -89.6501, source="nominatim")
result = cache.get_geocode("123 Main St, Springfield, IL 62701")
__init__(db_path=None)[source]
Parameters:

db_path (str | None)

put_geocode(address, latitude, longitude, source='nominatim', raw_response=None)[source]

Store a geocoding result. Returns the address hash.

Parameters:
Return type:

str

get_geocode(address)[source]

Look up a cached geocoding result by address string.

Parameters:

address (str)

Return type:

Dict | None

get_geocode_or_fetch(address, country_codes=None, server_url=None)[source]

Look up cache, falling back to Nominatim if not cached.

Returns None when the cache misses AND Nominatim has no match for the address. Raises GeocodingError when Nominatim fails (network/service/parse) — callers that want fail-open behavior must catch it explicitly. Raises ValueError for an empty/None address.

Parameters:
  • address (str)

  • country_codes (str | None)

  • server_url (str | None)

Return type:

Dict | None

get_geocodes_in_bbox(lat_min, lat_max, lon_min, lon_max)[source]

Return all cached geocodes within a bounding box.

Parameters:
Return type:

List[Dict]

put_boundary(geoid, vintage_year, point_wkt=None, boundary_wkt=None, source='tiger')[source]

Cache a boundary lookup result.

Parameters:
  • geoid (str)

  • vintage_year (int)

  • point_wkt (str | None)

  • boundary_wkt (str | None)

  • source (str)

get_boundary(geoid, vintage_year)[source]

Look up a cached boundary by GEOID and vintage year.

Parameters:
  • geoid (str)

  • vintage_year (int)

Return type:

Dict | None

put_crosswalk(source_geoid, target_geoid, weight=1.0, source='census')[source]

Cache a crosswalk mapping.

Parameters:
get_crosswalk(source_geoid)[source]

Get all crosswalk targets for a source GEOID.

Parameters:

source_geoid (str)

Return type:

List[Dict]

stats()[source]

Return row counts for all cache tables.

Return type:

Dict[str, int]

clear(table=None)[source]

Clear cache tables. If table is None, clear all.

Parameters:

table (str | None)

close()[source]

Close the database connection.

Functions

Usage Examples

Basic geocoding:

Distance calculations:

Coordinate validation:

Batch geocoding:

Unit Tests

The geocoding module has comprehensive test coverage:

Test Results: All geocoding tests pass successfully with comprehensive coverage.