Skip to main content

ruian-import

Download and parse the Czech ČÚZK (RÚIAN) registries: regions, districts, ORP, POÚ, municipalities, and city districts (městské části / obvody), plus WGS84 boundary geometry for each level.

Installation

pip install ruian-import

Usage

from ruian_import import fetch_regions, fetch_districts, fetch_municipalities

regions = fetch_regions()        # list[Region]
districts = fetch_districts()    # list[District]

for municipality in fetch_municipalities():   # Iterator[Municipality]
    ...

fetch_regions() and fetch_districts() return lists. fetch_municipalities() and fetch_municipalities_with_coordinates() return one-shot iterators so the ~6,200 municipalities don't all sit in memory at once; wrap them in list() if you need more than one pass.

Data classes

@dataclass
class Region:
    code: str              # e.g. "19"
    name: str              # e.g. "Hlavní město Praha"
    nuts_lau: str | None   # e.g. "CZ010"
    abolished: str | None  # abolishment date "YYYY-MM-DD", or None if active

@dataclass
class District:
    code: str
    name: str
    region_code: str
    nuts_lau: str | None
    abolished: str | None

@dataclass
class Municipality:
    code: str              # 6-digit municipality code, e.g. "554979"
    name: str
    district_code: str
    lat: float | None      # WGS84; None unless you fetch coordinates (see below)
    lon: float | None
    abolished: str | None

@dataclass
class CityDistrict:         # městský obvod / městská část (MOMC)
    code: str
    name: str
    municipality_code: str  # parent obec (statutární město)
    abolished: str | None

@dataclass
class Orp:                  # obec s rozšířenou působností (ORP)
    code: str
    name: str
    district_code: str                  # parent okres
    seat_municipality_code: str | None  # obec that is the ORP seat
    abolished: str | None

@dataclass
class Pou:                  # obec s pověřeným obecním úřadem (POÚ)
    code: str
    name: str
    orp_code: str                       # parent ORP
    seat_municipality_code: str | None  # obec that is the POÚ seat
    abolished: str | None

abolished is a date string on historical records and None on active ones.

City districts (MOMC), ORP and POÚ

Statutory cities and Prague are subdivided into MOMC units. Okresy are split into ORP (obce s rozšířenou působností), which are split again into POÚ (obce s pověřeným obecním úřadem). These three come from the ČÚZK ArcGIS layers rather than the CSV registries, so each record already carries its parent code:

from ruian_import import fetch_city_districts, fetch_orps, fetch_pous

for cd in fetch_city_districts():
    print(cd.code, cd.name, "->", cd.municipality_code)

for orp in fetch_orps():
    print(orp.code, orp.name, "-> okres", orp.district_code)

for pou in fetch_pous():
    print(pou.code, pou.name, "-> ORP", pou.orp_code)

Senate electoral districts (senátní volební obvody)

The 81 senate electoral districts are defined by law, not by the RÚIAN territorial registry, so they are not in the ČÚZK CSV registries or ArcGIS. They come instead from the Czech Statistical Office (ČSÚ) elections open data:

from ruian_import import fetch_senate_districts, fetch_municipality_senate_districts

for district in fetch_senate_districts():
    print(district.number, district.name)   # 1..81, e.g. 1 "Karlovy Vary"

for m in fetch_municipality_senate_districts():
    print(m.municipality_code, m.municipality_name, "-> obvod", m.district_number)

municipality_code is the RÚIAN code of the obec / městská část / městský obvod where voting happens — it matches Municipality.code for ordinary obce and a CityDistrict code for the split statutory cities.

A regular Senate election renews only a third of the districts, so no single election covers every municipality. fetch_municipality_senate_districts() therefore returns, for each municipality, its assignment from the most recent election (pass latest_only=False for the full history). A handful of large cities are genuinely divided across several districts (e.g. Praha 4), so a municipality may appear in more than one district.

Both functions download a dated code-list ZIP whose name changes on each ČSÚ republish; the current one is discovered automatically via resolve_senate_codelist_url(). Pass an explicit url= to pin a specific file.

Boundary geometry

Each administrative level has a fetch_*_geometries() function returning the full boundary of every unit as GeoJSON, keyed by RÚIAN code, in WGS84 (lon/lat order):

from ruian_import import fetch_districts, fetch_district_geometries

geoms = fetch_district_geometries()   # {code: {"type": "Polygon"|"MultiPolygon", ...}}

for district in fetch_districts():
    outline = geoms.get(district.code)   # None for abolished units (see below)
    if outline:
        ...

The other levels work the same way: fetch_region_geometries, fetch_orp_geometries, fetch_pou_geometries, fetch_municipality_geometries, fetch_city_district_geometries.

Geometry comes from the ČÚZK ArcGIS REST API with server-side Douglas-Peucker simplification and pagination. Pass a custom tolerance in degrees to trade size for detail (default ~0.001, roughly 110 m):

detailed = fetch_municipality_geometries(simplify=0.0002)

Municipality coordinates

UI_OBEC.csv has no coordinates, so fetch_municipalities() leaves lat/lon as None. fetch_municipalities_with_coordinates() makes a second request to the ArcGIS API and fills them with boundary centroids (accuracy ~100 m):

from ruian_import import fetch_municipalities_with_coordinates

for municipality in fetch_municipalities_with_coordinates():
    print(municipality.name, municipality.lat, municipality.lon)

Or fetch just the centroids as a lookup table:

from ruian_import import fetch_municipality_coordinates

coords = fetch_municipality_coordinates()   # {code: (lat, lon)}

Active vs. abolished units

The registries carry historical records alongside active ones, and the sources don't agree on what they include:

  • fetch_regions(), fetch_districts(), fetch_municipalities(), fetch_city_districts(), fetch_orps() and fetch_pous() include abolished units. Filter on abolished is None if you only want active ones.
  • The geometry functions and fetch_municipality_coordinates() return active units only.

So an abolished unit has a record but no geometry. Look geometry up with geoms.get(code) rather than geoms[code] unless you've already filtered to active units.

Command line

The package installs a ruian-import command (also python -m ruian_import) that writes any level to stdout as JSON:

ruian-import regions
ruian-import municipalities --coordinates > obce.json
ruian-import district-geometries --simplify 0.0002

Datasets: regions, districts, municipalities, city-districts, orps, pous, senate-districts, municipality-senate-districts, and <level>-geometries for each level.

Parsing local files

Every fetch_* for the CSV registries is a download wrapped around a parser you can call directly on bytes you already have:

from pathlib import Path
from ruian_import import parse_municipalities

data = Path("UI_OBEC.zip").read_bytes()
municipalities = list(parse_municipalities(data))

parse_regions and parse_districts work the same way. download(url) is also exported if you want the registry bytes without parsing.

Errors

Downloads retry twice on network failure and then raise requests.RequestException. Nothing is cached, so repeated calls re-download.

Data sources

The ČÚZK registries are updated daily:

  • Regions: https://services.cuzk.cz/sestavy/cis/UI_VUSC.zip
  • Districts: https://services.cuzk.cz/sestavy/cis/UI_OKRES.zip
  • Municipalities: https://services.cuzk.cz/sestavy/cis/UI_OBEC.zip

City districts, ORP, POÚ and all geometry come from the ČÚZK ArcGIS MapServer at https://ags.cuzk.cz/arcgis/rest/services/RUIAN/MapServer.

Senate electoral districts come from the ČSÚ elections open data at https://volby.gov.cz/opendata/senat_vse/ (code lists secobv.csv and secoco.csv inside the dated SENATciselniky…_csv.zip).

License

MIT

Metadata

Release files for ruian-import 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ruian-import 0.7.0
File Size Uploaded
ruian_import-0.7.0.tar.gz 108.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ruian-import 0.7.0
File Interpreter ABI Platform
ruian_import-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 125.1 kB

Release files / ruian_import-0.7.0.tar.gz

Download URL ruian_import-0.7.0.tar.gz
Size 108.0 kB
Tags Source
SHA-256 checksum
How to use checksums
9f193b942c219bab5bf9c3d692032b0ecaaec89ba12f84353a68a36408623126
BLAKE2b-256 checksum
How to use checksums
393820d2a98d376e7e255b1fb0aa4132e4e0fadf2633b415856514b3c1fc55ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release files / ruian_import-0.7.0-py3-none-any.whl

Download URL ruian_import-0.7.0-py3-none-any.whl
Size 17.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ca402eb0a481644909385ef85f5622ac9952c74bc4b25d268fcd3af832e37f09
BLAKE2b-256 checksum
How to use checksums
841c73641c01fceadb1be1396142a4ee03a40ee2fb7d99230e3604837756eeb3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release history Release notifications | RSS feed

0.8.0

2 release files

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page