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)
| File | Size | Uploaded | |
|---|---|---|---|
| locio-0.2.0.tar.gz | 14.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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