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.address_detail_pid) # 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.address_detail_pid)
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
Two ids, and which to store
A record can carry two pids and they mean different things:
| Attribute | Means |
|---|---|
address_detail_pid |
This address. The one to store. |
gnaf.primary_pid |
The parcel it sits on, when this row is a unit. |
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.
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.
Release files for locio 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| locio-0.1.0.tar.gz | 11.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| locio-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.6 kB
Release files / locio-0.1.0.tar.gz
| Download URL | locio-0.1.0.tar.gz |
|---|---|
| Size | 11.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
41c172164948ab9b8850174e7a11cefd7fbabf5355020b3983ea89c5afd6ec5f
|
|
BLAKE2b-256 checksum How to use checksums |
923894f87a403da26b50c26a6bac7cff3e598baf610ad26c9ed6f59a63e65f44
|
| 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 19, 2026.
Transparency logRelease files / locio-0.1.0-py3-none-any.whl
| Download URL | locio-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
10c506420c498b463a5c8f1bd6187be46aca864c8510463e6531a8ebc84acf0b
|
|
BLAKE2b-256 checksum How to use checksums |
cf566faa634ef5047c8a3b259e48008cab4b804ca063edeb3a86bc9f8fdd400a
|
| 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 19, 2026.
Transparency log