Matthew Proctor Postcodes
Typed Python 3.12+ lookup API for Matthew Proctor Australian and New Zealand postcode CSV datasets.
Quick Start
Install the package:
pip install matthewproctor-postcodes
Look up a postcode:
from matthewproctor_postcodes import lookup_postcode
entries = lookup_postcode("3004", "AUS")
for entry in entries:
print(entry["locality"], entry.get("RA_2021_NAME"))
Install development dependencies:
uv sync --refresh
Run local checks:
make lint
make test
Format code:
make format
Behaviour
lookup_postcode("3004", "AUS")returns a read-only sequence ofAUSMatthewProctorPostcodeInforows.lookup_postcode("110", "NZL")returns a read-only sequence ofNZLMatthewProctorPostcodeInforows.- Country codes are normalized to uppercase alpha-3 values.
- A lookup returns every locality for a postcode.
- Unknown but well-formed postcodes return an empty sequence.
- Postcodes are normalized to four decimal digits, so
"110"is looked up as"0110". - Invalid postcodes raise
InvalidPostcodeError; values must be one to four decimal digits. - Unsupported countries raise
UnsupportedCountryError. - Failed downloads from every configured source raise
DatasetDownloadError, preserving the original per-source exceptions forexcept*handling. - A local CSV is preferred; a missing CSV is downloaded and saved atomically.
- Each country database is loaded lazily once, then reused as an in-memory index.
- Row models are lightweight
TypedDicttypes that use the known source CSV headers.
Installation
pip install matthewproctor-postcodes
For local development from a checkout:
uv sync --refresh
Storage
Set MATTHEWPROCTOR_POSTCODES to control where files are read and downloaded:
export MATTHEWPROCTOR_POSTCODES=data/matthewproctor
This produces:
data/matthewproctor/australian_postcodes.csv
data/matthewproctor/newzealand_postcodes.csv
If the environment variable is absent, the default is data/matthewproctor relative to the
current working directory.
For an enterprise image, bake either CSV into that path and pass download_if_missing=False.
Usage
from matthewproctor_postcodes import lookup_postcode
aus_entries = lookup_postcode("3004", "AUS")
nz_entries = lookup_postcode("110", "NZL")
print([entry["locality"] for entry in aus_entries])
print([entry["locality"] for entry in nz_entries])
lookup_postcode() is the top-level public API and returns a collections.abc.Sequence so callers
can safely consume country-specific row types through the shared MatthewProctorPostcodeInfo union.
Convert it with list(...) if your code needs to mutate or serialize a concrete list object:
entries = list(lookup_postcode("3004", "AUS"))
Lookup Options
lookup_postcode() accepts these keyword arguments:
request_timeout_seconds: HTTP timeout used when a missing CSV must be downloaded. Defaults to30.0.download_if_missing: whether to download the source CSV when it is not already present locally. Defaults toTrue.
Storage is configured with MATTHEWPROCTOR_POSTCODES:
import os
from matthewproctor_postcodes import lookup_postcode
os.environ["MATTHEWPROCTOR_POSTCODES"] = "/app/data/matthewproctor"
entries = lookup_postcode(
"3004",
"AUS",
request_timeout_seconds=10.0,
download_if_missing=False,
)
Lifecycle options only affect an attempt to load an unloaded database. Once a country database has
loaded, later calls use the same in-memory index and do not make another request. A failed call with
download_if_missing=False does not poison the database; a later call with downloads enabled may
still load it.
Exception classes and lower-level helpers are available from their owning modules:
from matthewproctor_postcodes.exceptions import DatasetDownloadError
from matthewproctor_postcodes.normalization import normalize_postcode
Database classes are available from matthewproctor_postcodes.databases for advanced use,
and MatthewProctorDatabaseType is available from matthewproctor_postcodes.models.
DatasetDownloadError is an ExceptionGroup, so callers can either handle the whole download
failure or selectively handle grouped source failures:
import httpx
try:
lookup_postcode("3000", "AUS")
except* httpx.TimeoutException as errors:
for error in errors.exceptions:
print(error)
Source Schemas
The Australian CSV is australian_postcodes.csv. It includes the prescribed Australia Post postcode
ranges for NSW, ACT, VIC, QLD, SA, WA, TAS, and NT, including LVR and PO Box ranges.
Common Australian fields include:
id,postcode,locality,state,long,lat,dc,type,status,sa3,sa3name,sa4,sa4name,region,
Lat_precise,Long_precise,SA1_CODE_2021,SA1_NAME_2021,SA2_CODE_2021,SA2_NAME_2021,
SA3_CODE_2021,SA3_NAME_2021,SA4_CODE_2021,SA4_NAME_2021,RA_2011,RA_2016,RA_2021,
RA_2021_NAME,MMM_2015,MMM_2019,ced,altitude,chargezone,phn_code,phn_name,
lgaregion,lgacode,electorate,electoraterating,sed_code,sed_name
The New Zealand CSV is newzealand_postcodes.csv and currently uses:
postcode,locality,region,long,lat,territory,island
The source datasets may add fields over time. Unknown extra CSV fields are preserved in returned
row dictionaries, while the exported TypedDict models document the fields known by this package.
Returned rows also include a database field injected by this package with the source
MatthewProctorDatabaseType.
Development
This package uses uv, ruff, pytest, and hatchling. It targets Python 3.12 or newer.
CI/CD
Package CI runs on pull requests and pushes to main with:
uv run ruff format --check .
uv run ruff check .
uv run pytest -vv
Package publishing is handled by .github/workflows/package-cd.yaml. Run it manually or publish a
GitHub Release.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file matthewproctor_postcodes-2.0.0.tar.gz.
File metadata
- Download URL: matthewproctor_postcodes-2.0.0.tar.gz
- Upload date:
- Size: 10.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5265a7379574866f4c61f8c567a8beed28dd1e90ae94dc8850eb1f3081449d2
|
|
| MD5 |
f5e6da26c520cf69d0491934b99aeed2
|
|
| BLAKE2b-256 |
98782c241c63c487377a9f996a5862c25504c1702c421641c82ab10c3c8dc72a
|
File details
Details for the file matthewproctor_postcodes-2.0.0-py3-none-any.whl.
File metadata
- Download URL: matthewproctor_postcodes-2.0.0-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4de52984d348ef38d6e081877632061e77addf4780acd51f0cd7acf0c406e0ca
|
|
| MD5 |
d13136de3d157f5f0db31ac4cbb51e1c
|
|
| BLAKE2b-256 |
c0396424ba550e0e253ef48b6e027352e24cd4cc408119dd6d83a772b58555ea
|