Skip to main content

locio

Australian address validation, address autocomplete and address geocoding in Python, from G-NAF, the national address register.

One call gives you a stable G-NAF id, a coordinate, an ABS mesh block and the address split into fields. Comparable services bill validate, geocode and meshblock separately; here they are fields of one response.

No dependencies. Python 3.9+.

pip install locio

Address validation

resolve takes an address however you hold it and tells you whether it is real, where it is, and what it is made of.

from locio import Locio

locio = Locio("lc_live_...")

result = locio.resolve("1 george st sydenham nsw 2044")

if result.matched:
    a = result.address
    print(a.formatted)               # 1 George Street, Sydenham NSW 2044
    print(a.id)                      # store this, not the text
    print(a.lat, a.lng)              # geocoded
    print(a.mesh_block)              # ABS mesh block
    print(a.components.postcode)     # parsed

matched is False for an address that is not in G-NAF. That is an ordinary answer, not an error, and it is what a validation call is asking. Resolution is falsy when nothing matched, so this reads the way you want:

if not locio.resolve(typed):
    ...  # ask the customer to check it

Cleaning a spreadsheet

The commonest thing this library gets asked to do. to_dict() flattens a record to one level so it goes straight into a DictWriter.

import csv
from locio import Locio

locio = Locio("lc_live_...")

with open("customers.csv") as f, open("clean.csv", "w", newline="") as out:
    rows = list(csv.DictReader(f))
    writer = None

    for row in rows:
        result = locio.resolve(row["address"])
        clean = result.address.to_dict() if result.matched else {}
        record = {**row, **clean, "matched": result.matched}

        if writer is None:
            writer = csv.DictWriter(out, fieldnames=list(record))
            writer.writeheader()
        writer.writerow(record)

resolve_many does the same sequentially, which is deliberate: the quota is per key, and firing a thousand requests at once is how a free tier is spent in a second.

Address autocomplete

for a in locio.search("104/119 turner", limit=8):
    print(a.formatted, a.id)

For a browser autocomplete use @locio-au/react or @locio-au/vue with a public key. This library takes a secret key, and a secret key must never reach a page.

Correcting a typo

if not (result := locio.resolve(typed)):
    for near in locio.similar(typed, limit=5):
        print(near.formatted)

Three units, because it scores rows by similarity rather than seeking an index. Call it once on an address that failed to resolve, never per keystroke.

Reading an id back

from locio import NotFound

try:
    a = locio.get("GAVIC425624910")
except NotFound:
    ...  # G-NAF retires ids between releases; search for it again

Which id to store

id is the address's id in its country's register, and the one attribute every address carries:

Attribute Means
id This address. The one to store.
address_detail_pid The same id, under G-NAF's own column name. Australian addresses only.
gnaf.primary_pid The parcel it sits on, when this row is a unit. Australian addresses only.

address.is_unit reports which you have. Storing the primary pid stores the building rather than the door, and nothing about the value itself says so.

An address outside Australia carries id and country_code and leaves the G-NAF attributes empty: no pid, no mesh_block, no gnaf record. address.australian says which case you have, and to_dict writes only the columns that apply. Ids are unique within a country, so store country_code beside the id.

Which country

Every address call is scoped to one country. A secret key says which, because its requests come from your server and the service cannot tell from that where the address is: a shop in Melbourne hosted in Oregon is still asking about Australian addresses.

locio = Locio("lc_live_...", country="AU")

# or one call at a time
locio.resolve("1 george st sydenham nsw 2044", country="AU")

Unset sends no parameter and the service's own default applies, which is AU, so nothing changes for code that never mentions a country. A country the service holds no addresses for answers with no results rather than an error. Australia is what is covered today.

Errors

from locio import LocioError, NotFound, AuthError

try:
    locio.search("90 bay road")
except AuthError as err:
    print(err.status, err.title, err.detail)

The API writes refusals for a person to read and they are carried through, because the detail is the part that says what to do.

Keys and safety

Secret keys (lc_live_...) belong on a server. Get one at locio.com.au/account/api.

The client refuses a plaintext http:// base URL to any host but loopback: a bearer key sent in the clear is a key given away.

What it costs

search, resolve and get are one unit each, similar is three. See locio.com.au/pricing.

Licence

MIT. Address data is G-NAF, published by Geoscape Australia under CC BY 4.0; attribution belongs wherever you show it.

Metadata

Release files for locio 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for locio 0.2.0
File Size Uploaded
locio-0.2.0.tar.gz 14.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for locio 0.2.0
File Interpreter ABI Platform
locio-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.8 kB

Release files / locio-0.2.0.tar.gz

Download URL locio-0.2.0.tar.gz
Size 14.5 kB
Tags Source
SHA-256 checksum
How to use checksums
44dfb547c625674bdbddecd8791c8d6be7fba16854f8e1474989a35d7736ed5a
BLAKE2b-256 checksum
How to use checksums
1d5f301906a299b48c8dcbb6b2b63fc46f44ccb35f5fb4b1bfff39d280288a04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / locio-0.2.0-py3-none-any.whl

Download URL locio-0.2.0-py3-none-any.whl
Size 13.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bfda8dc6f2ef4342eff346e3651edd2d267427f322125ad3c9c61e2feea10da8
BLAKE2b-256 checksum
How to use checksums
b79bf70d053d7ee809b2d31259161522a3581ae648693f344891c91a09f0d1e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page