isocodes
isocodes gives you the ISO standards — countries, subdivisions, languages, currencies and scripts — as plain Python data, with no runtime dependencies.
- Loads on demand. Importing the package is cheap; each standard is parsed the first time you actually touch it.
- Dict and attribute access. Every record is a real
dictand also supportsrecord.name. - Translated names in 163 languages, all included, with a command to drop the ones you do not need.
- A command line interface, with table, JSON and CSV output, and optional tolerance for misspellings.
- Works inside frozen applications — a PyInstaller hook is included.
- Covers ISO 639-2, alongside 639-3 and 639-5.
The data comes from https://salsa.debian.org/iso-codes-team/iso-codes, many thanks to them.
Installation
pip install isocodes
Everything is included: all eight standards and translations in 163 languages.
If package size matters — a container image, a Lambda bundle — you can drop the languages you do not use:
isocodes locales # list what is installed
isocodes locales --keep fr,en # preview the removal
isocodes locales --keep fr,en --yes # apply it
| Size on disk | |
|---|---|
| as installed | ~19 MB |
after --keep fr,en |
~750 KB |
In a Dockerfile, prune in the same layer as the install, or the files stay in the image:
RUN pip install isocodes && isocodes locales --keep fr,en --yes
The removal is not permanent: pip install --upgrade isocodes restores every
language, as does pip install --force-reinstall isocodes.
Usage
Countries (ISO 3166)
Dot Notation Access
>>> from isocodes import countries
>>> usa = countries.get(alpha_2="US")
# Dot notation:
>>> usa.name
'United States'
>>> usa.flag
'🇺🇸'
>>> usa.alpha_3
'USA'
>>> usa.official_name
'United States of America'
# Dictionary access:
>>> usa["name"]
'United States'
>>> usa.get("alpha_3")
'USA'
>>> isinstance(usa, dict)
True
Enhanced Search Methods
Fast Exact Lookup with find()
>>> # O(1) performance for common lookups
>>> germany = countries.find(alpha_2="DE")
>>> germany.name
'Germany'
>>> germany.flag
'🇩🇪'
Flexible Search with search()
>>> # Find all countries with "Island" in the name
>>> island_countries = countries.search(name="Island")
>>> for country in island_countries[:3]:
... print(f"{country.name} - {country.flag}")
Cook Islands - 🇨🇰
Bouvet Island - 🇧🇻
Faroe Islands - 🇫🇴
Word order does not matter, which matters because ISO stores many names in inverted form. Results are ranked, so the closest match comes first:
>>> [c.name for c in countries.search(name="Republic of Korea")]
['Korea, Republic of', "Korea, Democratic People's Republic of"]
Misspellings with search_fuzzy()
search() never guesses. When you want tolerance for typos, ask for it:
>>> [c.name for c in countries.search_fuzzy("Germny")]
['Germany', 'Guernsey']
>>> [c.name for c in countries.search_fuzzy("Untied Kingdom")]
['United Kingdom']
>>> countries.search_fuzzy("xyzzy not a place")
[]
A correctly spelled query is answered by search() and never reaches the
approximate matching, so reaching for this by default is safe:
>>> [c.name for c in countries.search_fuzzy("Kingdom")]
['United Kingdom']
cutoff controls how close a match has to be, and limit caps the results.
On the command line the same behaviour sits behind --fuzzy:
isocodes countries --name Germny --fuzzy
Fast Dictionary Access
>>> by_code = countries.by_alpha_2_dict
>>> canada = by_code["CA"]
>>> canada.name
'Canada'
>>> canada.flag
'🇨🇦'
Get method
You can access one country by using the method get with the parameters being the json keys of the .json files in the share/iso-codes/json folder
Example
>>> from isocodes import countries
>>> countries.get(name="Germany")
{'alpha_2': 'DE', 'alpha_3': 'DEU', 'flag': '🇩🇪', 'name': 'Germany', 'numeric': '276', 'official_name': 'Federal Republic of Germany'}
Items property
You can get a list from the .json files in the share/iso-codes/json folder with the items property. Each item supports both dictionary and dot notation access:
Example
>>> from isocodes import countries
>>> for country in countries.items:
... print(f"{country.name} - {country.flag}")
... print(country["alpha_2"])
...
Aruba - 🇦🇼
AW
Afghanistan - 🇦�
AF
Angola - 🇦�
AO
...
by_xxx property
You can get a list with sorted data by one of the property with the by_xxx property, xxx being one of the data key (alpha_2, name, numeric, etc.).
Example
>>> countries.by_numeric[0]
('004', <Country: Afghanistan>)
>>> country = countries.by_numeric[0][1]
>>> country.name
'Afghanistan'
>>> country.flag
'🇦🇫'
Former country names lookup
You can look up countries by their former names using the get_by_former_name method.
Example
>>> from isocodes import countries
>>> eswatini = countries.get_by_former_name("Swaziland")
>>> eswatini.name
'Eswatini'
>>> eswatini.flag
'🇸🇿'
>>> f"{eswatini.name} ({eswatini.alpha_2})"
'Eswatini (SZ)'
>>> myanmar = countries.get_by_former_name("Burma")
>>> f"{myanmar.name} - {myanmar.flag}"
'Myanmar - 🇲🇲'
>>> countries.get_former_names_info("Czechoslovakia")
{'alpha_2': None, 'alpha_3': None, 'current_name': None, 'change_date': '1993-01-01', 'comment': 'Split into Czech Republic (CZ/CZE) and Slovakia (SK/SVK)'}
>>> countries.former_names[:5]
['Swaziland', 'Burma', 'Zaire', 'Czechoslovakia', 'Yugoslavia']
Other ISO Standards
Languages (ISO 639-2)
>>> from isocodes import languages
>>> english = languages.get(alpha_3="eng")
>>> english.name
'English'
>>> romance_langs = languages.search(name="French")
Currencies (ISO 4217)
>>> from isocodes import currencies
>>> usd = currencies.find(alpha_3="USD")
>>> usd.name
'US Dollar'
>>> usd.numeric
'840'
Countries and Subdivisions (ISO 3166-2)
>>> from isocodes import subdivisions_countries
>>> california = subdivisions_countries.find(code="US-CA")
>>> california.name
'California'
Former countries (ISO 3166-3)
>>> from isocodes import former_countries
>>> yugoslavia = former_countries.get(alpha_3="YUG")
>>> yugoslavia.name
'Yugoslavia'
Extended languages (ISO 639-3)
>>> from isocodes import extended_languages
>>> mandarin = extended_languages.find(alpha_3="cmn")
>>> mandarin.name
'Mandarin Chinese'
Language families (ISO 639-5)
>>> from isocodes import language_families
>>> indo_european = language_families.find(alpha_3="ine")
>>> indo_european.name
'Indo-European languages'
Script names (ISO 15924)
>>> from isocodes import script_names
>>> latin = script_names.find(alpha_4="Latn")
>>> latin.name
'Latin'
Command Line Interface
isocodes includes a powerful command-line interface for quick ISO data lookups and searches.
Installation
After installing isocodes, the CLI is available as the isocodes command:
pip install isocodes
isocodes --help
Basic Usage
Countries
# Find country by code
isocodes countries --code US
isocodes countries --code DEU
# Search by name
isocodes countries --name Germany --exact
isocodes countries --name Island
# Find by former name
isocodes countries --former-name Burma
# List all countries
isocodes countries --list-all
Languages
# Find language by code
isocodes languages --code en
isocodes languages --code deu
# Search by name
isocodes languages --name French
Currencies
# Find currency by code
isocodes currencies --code USD
# Search by name
isocodes currencies --name Euro
# Find by numeric code
isocodes currencies --numeric 840
Country Subdivisions
# Find subdivision by code
isocodes subdivisions --code US-CA
# List subdivisions for a country
isocodes subdivisions --country US
Former Countries
# Find former country
isocodes former-countries --code YUG
isocodes former-countries --name Yugoslavia
Script Names
# Find script by code
isocodes scripts --code Latn
# Find by numeric code
isocodes scripts --numeric 215
Output Formats
Table Format (Default)
isocodes countries --code US
# Output:
# alpha_2 | alpha_3 | flag | name | numeric | official_name
# -----------------------------------------------------------------------------
# US | USA | 🇺🇸 | United States | 840 | United States of America
JSON Format
isocodes --format json countries --code US
# Output:
# [
# {
# "alpha_2": "US",
# "alpha_3": "USA",
# "flag": "🇺🇸",
# "name": "United States",
# "numeric": "840",
# "official_name": "United States of America"
# }
# ]
CSV Format
isocodes --format csv countries --code US
# Output:
# alpha_2,alpha_3,flag,name,numeric,official_name
# US,USA,🇺🇸,United States,840,United States of America
Advanced Options
Limit Results
# Show only first 5 results
isocodes --limit 5 countries --name Island
Select Specific Fields
# Show only name and flag
isocodes --fields name,flag countries --code US
# Output:
# name | flag
# --------------------
# United States | 🇺🇸
Combining Options
# JSON output with specific fields and limit
isocodes --format json --fields name,flag --limit 3 countries --name Island
CLI Examples
# Quick country lookup
isocodes countries --code FR
# Find countries with "United" in name
isocodes countries --name United
# Get all US states in CSV format
isocodes --format csv subdivisions --country US > us_states.csv
# Find all currencies in JSON
isocodes --format json currencies --list-all > currencies.json
# Search for Romance languages
isocodes languages --name French
# Look up former country by modern name reference
isocodes countries --former-name "Soviet Union"
Translations
Names are available in 163 languages, all shipped with the package. translate() takes a record or a plain
name and returns the translated name, falling back to the original when no
catalogue exists for that language:
>>> from isocodes import countries, currencies
>>> germany = countries.find(alpha_2="DE")
>>> countries.translate(germany, "fr")
'Allemagne'
>>> countries.translate(germany, "ja")
'ドイツ'
>>> countries.translate("France", "de")
'Frankreich'
>>> currencies.translate(currencies.find(alpha_3="EUR"), "fr")
'Euro'
Use translator() when translating many names into the same language — it
returns a reusable callable:
>>> to_spanish = countries.translator("es")
>>> [to_spanish(c.name) for c in countries.search(name="Island")[:2]]
['Islas Cook', 'Isla Bouvet']
available_languages() lists the languages currently installed, which is all
163 unless you have pruned them:
>>> from isocodes import available_languages
>>> len(available_languages())
163
The underlying gettext catalogues remain available directly. The domain names are listed at https://salsa.debian.org/iso-codes-team/iso-codes
>>> import gettext
>>> import isocodes
>>> french = gettext.translation('iso_639-2', isocodes.LOCALE_PATH, languages=['fr'])
>>> french.install()
>>> _("French")
'Français'
Develop
Tests and coverage
uv run --group test pytest
The suite is held at 100% by fail_under in pyproject.toml:
COVERAGE_PROCESS_START=pyproject.toml \
uv run --group test --with coverage coverage run -m pytest -q
uv run --with coverage coverage combine
uv run --with coverage coverage report
COVERAGE_PROCESS_START is what lets the CLI tests that shell out be measured.
Update iso-codes version
Upstream dropped autotools in 4.19.0 and builds with meson now, so refreshing
the bundled data needs git, meson and ninja:
./update.sh # the version pinned in the script
./update.sh v4.20.1 # or an explicit tag
The script clones upstream into a temporary directory, builds it, replaces
isocodes/share, then prunes the JSON schemas, the pkg-config file and the
deprecated XML files, which the Python package does not ship.
Upstream installs every catalogue twice, under a current and an obsolete
filename (iso_3166.mo alongside iso_3166-1.mo). Those are symlinks in the
source tree but a wheel materialises them into full copies, so update.sh
deletes them. The obsolete domain names are mapped onto the current ones in
isocodes/__init__.py instead, so nothing that used them breaks.
bash update.sh
Metadata
Release files for isocodes 2026.9.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| isocodes-2026.9.2.tar.gz | 8.1 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| isocodes-2026.9.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 16.7 MB
Release files / isocodes-2026.9.2.tar.gz
| Download URL | isocodes-2026.9.2.tar.gz |
|---|---|
| Size | 8.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
22c2d98b64b586780f3c3f2037e7afc0adfda677cdd59f73cd05a655f295d43f
|
|
BLAKE2b-256 checksum How to use checksums |
3814abf2db881682011a25373dcb82749e01d6d111e84e5a0f65f751152688f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","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}
|
Release files / isocodes-2026.9.2-py3-none-any.whl
| Download URL | isocodes-2026.9.2-py3-none-any.whl |
|---|---|
| Size | 8.5 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7b776dfad3873666db5629fd4cbbea3271747d31d45f0cd547ab83930734bc78
|
|
BLAKE2b-256 checksum How to use checksums |
e00a37355b7ed4a2f8853d7a7b56a79f8d046e435d135bc4a3cd24b3419388d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","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}
|