Offline country profiles, coordinate tools, and geography learning utilities
Project description
PyWorldAtlas
A compact, source-aware world atlas for Python that works completely offline.
PyWorldAtlas makes real geographic data feel like ordinary Python. Look up a country by name or code, inspect immutable country and capital objects, explore major cities, calculate geographic relationships, and build reproducible learning material—without an API key, runtime download, database server, or third-party dependency.
from pyworldatlas import Atlas
with Atlas() as atlas:
japan = atlas.country("Japan")
print(japan.capital.name) # Tokyo
print(japan.capital.coordinates.as_tuple())
print(atlas["DO"].name) # Dominican Republic
print("France" in atlas) # True
Dataset coverage
The bundled dataset contains every country and area in the captured UN M49 scope, cross-checked against GeoNames country metadata. Version 0.2.1 adds core profile metadata and coordinate calculations to the identity, region, capital, and populated-place records established for 0.1.0.
| Current dataset | Coverage |
|---|---|
| Countries and areas | 248 |
| Primary capitals | 241 / 248 |
| Capital coordinates | 241 / 241 |
| Populated-place records | 6,265, including retained capitals |
| Runtime dependencies | 0 |
| Bundled databases | 1 SQLite file |
The 0.2.1 checkout adds richer country profiles, dependency-free coordinate calculations, flag emoji, discovery cards, reproducible sampling, and structured flashcards. Borders, boundary geometry, historical statistics, national leaders, interactive learning applications, and exports remain later work.
Installation
Install the latest published release:
python -m pip install --upgrade pyworldatlas
Install the current source checkout and its separate data builder when contributing:
python -m pip install -e . -e pipeline
You can also test the exact local wheel after running the release build:
python -m pip install --no-index --no-deps dist/pyworldatlas-0.2.1-py3-none-any.whl
The package runtime supports Python 3.10 through 3.14 during the 0.x release series. Python versions are only claimed as release-supported after CI passes.
What works in this checkout
| Capability | Example |
|---|---|
| Exact lookup | atlas.country("Japan") |
| Standard identifiers | atlas.country("JP"), atlas.country("JPN"), atlas.country("392") |
| Familiar aliases | atlas.country("USA"), atlas.country("Holy See") |
| Collection behavior | atlas["DO"], "France" in atlas, len(atlas) |
| Ranked search | atlas.search_countries("united") |
| Geographic filtering | atlas.countries(continent="Americas") |
| Capital records | country.capital, .coordinates, .timezone_id |
| Major cities | atlas.major_cities("Japan", limit=5) |
| Rich profile | country.population, .currency, .languages, .calling_codes |
| Flags and calculated facts | country.flag_emoji, .population_density |
| Discovery cards | country.discovery_card() |
| Stable country samples | atlas.sample_countries(count=5, seed=42) |
| Structured flashcards | atlas.flashcards(topic="capitals", count=10, seed=42) |
| City coordinates | atlas.coordinates("Tokyo", country="JP") |
| Distance | atlas.distance_between("Tokyo", "Paris", first_country="JP", second_country="FR") |
| Bearing and midpoint | coordinate.bearing_to(other), .midpoint_to(other) |
| Source inspection | country.sources |
| Official local names | country.local_names, country.name_in("pt") |
| Serialization | country.to_dict(), country.to_json() |
| Version inspection | atlas.dataset_info() |
Typed country profiles
Public results are frozen typed dataclasses rather than loosely structured dictionaries:
from pyworldatlas import Atlas
with Atlas() as atlas:
country = atlas.country("Dominican Republic")
print(country.name)
print(country.official_name)
print(country.flag)
print(country.flag_emoji)
print(country.codes.alpha2)
print(country.codes.alpha3)
print(country.codes.numeric)
print(country.continent)
print(country.region)
print(country.subregion)
print(country.area_km2)
print(country.population)
print(country.population_density)
print(country.currency)
print(country.languages)
print(country.calling_codes)
print(country.top_level_domain)
print(country.observed_timezones)
if country.capital is not None:
print(country.capital.name)
print(country.capital.coordinates.as_tuple())
print(country.capital.population)
print(country.capital.timezone_id)
Country discovery and education
from pyworldatlas import Atlas
with Atlas() as atlas:
japan = atlas.country("Japan")
card = japan.discovery_card()
print(card.flag_emoji, card.capital, card.population_density)
for country in atlas.sample_countries(count=5, continent="Africa", seed=42):
print(country.flag_emoji, country.name)
for flashcard in atlas.flashcards(topic="capitals", count=3, seed=42):
print(flashcard.prompt)
print(flashcard.answer)
Sampling uses a versioned SHA-256 ranking over stable M49 identifiers, so the same dataset, filters, and seed produce the same ordered lesson across supported Python versions. Flashcards are immutable structured values rather than an interactive game. Supported topics cover capitals, flags, country codes, currencies, calling codes, domains, language codes, regions, local names, population, area, and calculated density.
Latitude, longitude, and distance
from pyworldatlas import Atlas, Coordinate
with Atlas() as atlas:
tokyo = atlas.city("Tokyo", country="Japan")
paris = atlas.city("Paris", country="France")
print(tokyo.coordinates.latitude, tokyo.coordinates.longitude)
print(atlas.distance_between(tokyo, paris)) # kilometres
print(atlas.distance_between(tokyo, paris, unit="mi")) # miles
print(tokyo.coordinates.bearing_to(paris.coordinates))
print(tokyo.coordinates.midpoint_to(paris.coordinates))
london = Coordinate(51.5074, -0.1278)
paris_center = Coordinate(48.8566, 2.3522)
print(london.distance_to(paris_center))
Distances use the haversine formula and WGS84 mean Earth radius. They are surface great-circle distances, not road or flight-routing distances.
Search and filter
with Atlas() as atlas:
for match in atlas.search_countries("united"):
print(match.country.name, match.matched_name, match.score)
for country in atlas.countries(continent="Europe"):
capital = country.capital.name if country.capital else "not available"
print(country.name, capital)
Search is case- and accent-insensitive. Exact country lookup accepts common names, reviewed aliases, alpha-2, alpha-3, and M49 numeric codes.
Test every current record
The repository includes playground.py, which checks every current country, capital, and city record before demonstrating the public API.
Run from the repository root:
python playground.py
Focused modes:
python playground.py --audit-only
python playground.py --country Japan
python playground.py --json "Dominican Republic"
python playground.py --country "United States" --all-cities
The playground runs directly from a repository checkout even before an editable installation. Normal applications should install the package.
Small by design
The installed wheel contains only:
- Python source files.
- One generated, read-only SQLite database.
- Standard package metadata.
At runtime PyWorldAtlas does not:
- Contact the internet.
- Require an API key.
- Download or decompress data after installation.
- Write into
site-packages. - Load the complete database during
Atlas()initialization. - Depend on pandas, NumPy, an ORM, a GIS engine, or SQLite extensions.
Data you can trace
The 0.2.1 checkout uses:
- United Nations M49 for canonical identities, standard codes, regions, and subregions.
- GeoNames for capitals, populated places, WGS84 coordinates, population snapshots, currencies, language and calling codes, country-code domains, timezone identifiers, and GeoNames IDs.
The reviewed local-name records use the UNGEGN List of Country Names
(E/CONF.105/13/CRP.13) for national official short and formal names. Current
coverage is five records across Brazil and Switzerland. The captured source
artifact and reviewed rows include checksums and exact entry/page locators.
Raw snapshots are preserved with SHA-256 manifests. The separate builder emits inspectable normalized JSON Lines before generating SQLite. Missing values stay missing; unsourced assumptions are never substituted for country facts.
Flag emoji are derived from alpha-2 codes, population density is a transparent ratio of sourced values, and discovery/learning tools only rearrange existing profile data. They introduce no additional country claims or third-party data.
Seven areas have no usable primary-capital record in the current snapshot.
Their country.capital value is None. GeoNames-only country rows that do
not have a matching identity in the captured UN M49 scope are excluded rather
than inferred.
See DATA_SOURCES.md, DATA_QUALITY.md, and THIRD_PARTY_NOTICES.md.
Three different versions
with Atlas() as atlas:
print(atlas.dataset_info())
- Library version describes Python behavior and the public API.
- Schema version describes compatibility with the bundled SQLite structure.
- Dataset version identifies the captured source snapshot.
For this development checkout they are 0.2.1, 2, and 2026.07.20.1.
Documentation and roadmap
- Documentation source for this checkout: docs/source
- Published documentation (updated by the release workflow): https://jcari-dev.github.io/pyworldatlas-documentation/
- Current implementation status: ROADMAP_STATUS.md
- Milestone evidence: MILESTONE_0_1_REPORT.md
- 0.2.1 execution status: RELEASE_0_2_STATUS.md
- Maintainer release process: RELEASING.md
Version 0.2.1 is the country-profile, coordinate, and discovery release. After it is published, 0.3.0 will add reviewed border relationships, neighbors, shared neighbors, and border paths. Later releases extend boundary geometry, historical statistics, institutions, culture, and exports.
License and attribution
PyWorldAtlas code is available under the MIT License. GeoNames data is provided under CC BY 4.0. Other source terms and required notices are recorded in THIRD_PARTY_NOTICES.md.
Project details
Release history Release notifications | RSS feed
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 pyworldatlas-0.2.1.tar.gz.
File metadata
- Download URL: pyworldatlas-0.2.1.tar.gz
- Upload date:
- Size: 379.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c750b5b093bfebcd33c9de51afbe2688a4f1587ec404fa37f31203883624162
|
|
| MD5 |
f815bc821335139b75e28d9631efa816
|
|
| BLAKE2b-256 |
c28352e1702ce0463a830d17ae1a40ba5260afd38a801096cf0f0f702eb6a72c
|
Provenance
The following attestation bundles were made for pyworldatlas-0.2.1.tar.gz:
Publisher:
release.yml on jcari-dev/pyworldatlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyworldatlas-0.2.1.tar.gz -
Subject digest:
3c750b5b093bfebcd33c9de51afbe2688a4f1587ec404fa37f31203883624162 - Sigstore transparency entry: 2214945209
- Sigstore integration time:
-
Permalink:
jcari-dev/pyworldatlas@dac275521ffe8648bd7a91956b7497b8f60d5f59 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/jcari-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dac275521ffe8648bd7a91956b7497b8f60d5f59 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyworldatlas-0.2.1-py3-none-any.whl.
File metadata
- Download URL: pyworldatlas-0.2.1-py3-none-any.whl
- Upload date:
- Size: 372.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d7aab07652035078b68623140a0d7432faa482bc5d4acba30d7548ca882a4022
|
|
| MD5 |
20e85a0a341620c4e55a8d818d4457e6
|
|
| BLAKE2b-256 |
21c2e0d860e8254f5a9b002987fece1a747e5f0c1cb3c4485b1240034f65d90e
|
Provenance
The following attestation bundles were made for pyworldatlas-0.2.1-py3-none-any.whl:
Publisher:
release.yml on jcari-dev/pyworldatlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyworldatlas-0.2.1-py3-none-any.whl -
Subject digest:
d7aab07652035078b68623140a0d7432faa482bc5d4acba30d7548ca882a4022 - Sigstore transparency entry: 2214945221
- Sigstore integration time:
-
Permalink:
jcari-dev/pyworldatlas@dac275521ffe8648bd7a91956b7497b8f60d5f59 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/jcari-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dac275521ffe8648bd7a91956b7497b8f60d5f59 -
Trigger Event:
push
-
Statement type: