Skip to content

Core API Reference

Yoro Codec — Geographic addressing via 2D Hilbert curves.

Bijection between GPS coordinates and compact alphanumeric codes. Pure Python, zero external dependencies.

Theory: Paul Guindo, Altius Academy SNC.

encode(lat, lon, precision=12, domain='CI', clamp=False, check=False)

Encode GPS coordinates to an Yoro string.

Parameters:

Name Type Description Default
lat float

Latitude (WGS 84).

required
lon float

Longitude (WGS 84).

required
precision int

Hilbert order (higher = finer grid). Default 12.

12
domain str

ISO country code or "XX" for global.

'CI'
clamp bool

Project a point outside the domain onto its edge instead of raising. Off by default: a silently moved address is worse than a refused one.

False
check bool

Append a check character (see :func:check_char). Decode the result with check=True.

False

Returns:

Type Description
str

Code string, e.g. "CI-4H7A3B".

Raises:

Type Description
ValueError

If domain is unknown, or if the coordinates fall outside the domain's bounding box and clamp is false.

Source code in src/yoro/codec.py
def encode(
    lat: float,
    lon: float,
    precision: int = 12,
    domain: str = "CI",
    clamp: bool = False,
    check: bool = False,
) -> str:
    """Encode GPS coordinates to an Yoro string.

    Args:
        lat: Latitude (WGS 84).
        lon: Longitude (WGS 84).
        precision: Hilbert order (higher = finer grid). Default 12.
        domain: ISO country code or "XX" for global.
        clamp: Project a point outside the domain onto its edge instead of
            raising. Off by default: a silently moved address is worse than a
            refused one.
        check: Append a check character (see :func:`check_char`). Decode the
            result with ``check=True``.

    Returns:
        Code string, e.g. ``"CI-4H7A3B"``.

    Raises:
        ValueError: If *domain* is unknown, or if the coordinates fall outside
            the domain's bounding box and *clamp* is false.
    """
    if domain not in DOMAINS:
        raise ValueError(f"Unknown domain: '{domain}'. Available: {list(DOMAINS.keys())}")

    dom = DOMAINS[domain]
    in_lat = dom["lat_min"] <= lat <= dom["lat_max"]
    in_lon = dom["lon_min"] <= lon <= dom["lon_max"]
    if not (in_lat and in_lon) and not clamp:
        raise ValueError(
            f"Coordinates ({lat}, {lon}) are outside domain '{domain}' "
            f"(lat {dom['lat_min']}..{dom['lat_max']}, "
            f"lon {dom['lon_min']}..{dom['lon_max']}). Use domain='XX' for "
            f"worldwide coverage, or clamp=True to snap to the edge."
        )

    k = _code_length(precision)
    p = _canonical_precision(k)
    m = 1 << p

    # Clamp keeps both the exact-upper-bound edge (lat == lat_max maps to cell
    # m-1) and, when asked, points beyond the box entirely.
    x = min(m - 1, max(0, int((lon - dom["lon_min"]) / (dom["lon_max"] - dom["lon_min"]) * m)))
    y = min(m - 1, max(0, int((lat - dom["lat_min"]) / (dom["lat_max"] - dom["lat_min"]) * m)))

    d = _xy2d(p, x, y)
    code = _int_to_base29(d, k)
    if check:
        code += check_char(code)

    return f"{domain}-{code}"

encode_for_country(lat, lon, country_code, precision=12)

Encode a point using its country's domain, falling back worldwide.

The country-specific domains are bounding boxes, so a point can be legitimately in a country and outside its box: border areas, enclaves, offshore points, and countries covered by a combined extract. A country may also have no domain at all. Either way the point stays addressable — this falls back to the planet-wide "XX" domain instead of raising.

Prefer this over encode(lat, lon, domain=domain_for_country(cc)) whenever the coordinates are not known to sit inside the box: that form raises, and every caller ends up reimplementing the same fallback.

Parameters:

Name Type Description Default
lat float

Latitude in degrees.

required
lon float

Longitude in degrees.

required
country_code str | None

ISO 3166-1 alpha-2 code, e.g. "CI". None or an unknown code goes straight to the worldwide domain.

required
precision int

Hilbert order; see :func:precision_levels.

12

Returns:

Type Description
str

Code string, in the country's domain when it fits, "XX-…" otherwise.

Example::

>>> encode_for_country(6.8, -5.3, "CI")     # inside the box
'CI-NW64D'
>>> encode_for_country(64.1, -21.9, "CI")   # Reykjavik is not
'XX-...'
Source code in src/yoro/codec.py
def encode_for_country(
    lat: float,
    lon: float,
    country_code: str | None,
    precision: int = 12,
) -> str:
    """Encode a point using its country's domain, falling back worldwide.

    The country-specific domains are bounding boxes, so a point can be
    legitimately *in* a country and *outside* its box: border areas, enclaves,
    offshore points, and countries covered by a combined extract. A country may
    also have no domain at all. Either way the point stays addressable — this
    falls back to the planet-wide ``"XX"`` domain instead of raising.

    Prefer this over ``encode(lat, lon, domain=domain_for_country(cc))``
    whenever the coordinates are not known to sit inside the box: that form
    raises, and every caller ends up reimplementing the same fallback.

    Args:
        lat: Latitude in degrees.
        lon: Longitude in degrees.
        country_code: ISO 3166-1 alpha-2 code, e.g. ``"CI"``. ``None`` or an
            unknown code goes straight to the worldwide domain.
        precision: Hilbert order; see :func:`precision_levels`.

    Returns:
        Code string, in the country's domain when it fits, ``"XX-…"`` otherwise.

    Example::

        >>> encode_for_country(6.8, -5.3, "CI")     # inside the box
        'CI-NW64D'
        >>> encode_for_country(64.1, -21.9, "CI")   # Reykjavik is not
        'XX-...'
    """
    domain = domain_for_country(country_code)
    try:
        return encode(lat, lon, precision=precision, domain=domain)
    except ValueError:
        if domain == "XX":
            raise
        return encode(lat, lon, precision=precision, domain="XX")

decode(code, check=False)

Decode an Yoro string to GPS coordinates and cell bounds.

Parameters:

Name Type Description Default
code str

Yoro string, e.g. "CI-4H7A3B". Case- and whitespace-tolerant.

required
check bool

The last character of the body is a check character: verify it and strip it before decoding. Use on codes produced by encode(..., check=True).

False

Returns:

Type Description
DecodedCode

Dict with keys: lat, lon, precision, domain, bounds.

Raises:

Type Description
ValueError

If the code format, length, or domain is invalid, if the check character does not match, or if the code addresses a cell outside the grid its length defines.

Source code in src/yoro/codec.py
def decode(code: str, check: bool = False) -> DecodedCode:
    """Decode an Yoro string to GPS coordinates and cell bounds.

    Args:
        code: Yoro string, e.g. ``"CI-4H7A3B"``. Case- and whitespace-tolerant.
        check: The last character of the body is a check character: verify it
            and strip it before decoding. Use on codes produced by
            ``encode(..., check=True)``.

    Returns:
        Dict with keys: ``lat``, ``lon``, ``precision``, ``domain``, ``bounds``.

    Raises:
        ValueError: If the code format, length, or domain is invalid, if the
            check character does not match, or if the code addresses a cell
            outside the grid its length defines.
    """
    prefix, base29_code = _parse_code(code)
    if check:
        base29_code = _strip_check(base29_code)

    dom = DOMAINS[prefix]
    k = len(base29_code)
    p = _canonical_precision(k)
    m = 1 << p

    d = _hilbert_index(base29_code, p)
    x, y = _d2xy(p, d)

    lon = dom["lon_min"] + (x + 0.5) * (dom["lon_max"] - dom["lon_min"]) / m
    lat = dom["lat_min"] + (y + 0.5) * (dom["lat_max"] - dom["lat_min"]) / m

    bounds = _cell_bounds(x, y, p, dom)

    return {
        "lat": round(lat, 8),
        "lon": round(lon, 8),
        "precision": p,
        "domain": prefix,
        "bounds": bounds,
    }

neighbors(code, check=False)

Return up to 8 neighboring cell codes (edge/corner adjacency).

Codes on the domain boundary may return fewer than 8 neighbors.

Parameters:

Name Type Description Default
code str

Yoro string.

required
check bool

The input carries a check character; verify it, and give every returned neighbour its own. Without this a checked code yields unchecked neighbours, which then fail to decode the same way.

False
Source code in src/yoro/codec.py
def neighbors(code: str, check: bool = False) -> list[str]:
    """Return up to 8 neighboring cell codes (edge/corner adjacency).

    Codes on the domain boundary may return fewer than 8 neighbors.

    Args:
        code: Yoro string.
        check: The input carries a check character; verify it, and give every
            returned neighbour its own. Without this a checked code yields
            unchecked neighbours, which then fail to decode the same way.
    """
    prefix, base29_code = _parse_code(code)
    if check:
        base29_code = _strip_check(base29_code)

    k = len(base29_code)
    p = _canonical_precision(k)
    m = 1 << p

    d = _hilbert_index(base29_code, p)
    cx, cy = _d2xy(p, d)

    result: list[str] = []
    for dx, dy in [
        (-1, -1),
        (-1, 0),
        (-1, 1),
        (0, -1),
        (0, 1),
        (1, -1),
        (1, 0),
        (1, 1),
    ]:
        nx, ny = cx + dx, cy + dy
        if 0 <= nx < m and 0 <= ny < m:
            nd = _xy2d(p, nx, ny)
            ncode = _int_to_base29(nd, k)
            if check:
                ncode += check_char(ncode)
            result.append(f"{prefix}-{ncode}")

    return result

resolution(p, domain='CI')

Approximate spatial resolution in meters for Hilbert order p in domain.

Source code in src/yoro/codec.py
def resolution(p: int, domain: str = "CI") -> float:
    """Approximate spatial resolution in meters for Hilbert order *p* in *domain*."""
    dom = DOMAINS[domain]
    lat_range = dom["lat_max"] - dom["lat_min"]
    lon_range = dom["lon_max"] - dom["lon_min"]
    m = 1 << p
    dlat = lat_range / m
    dlon = lon_range / m
    lat_m = dlat * 111_000
    lon_m = dlon * 111_000 * math.cos(math.radians((dom["lat_min"] + dom["lat_max"]) / 2))
    return max(lat_m, lon_m)

get_bounds(code, check=False)

Return only the cell bounding box for code.

Source code in src/yoro/codec.py
def get_bounds(code: str, check: bool = False) -> CellBounds:
    """Return only the cell bounding box for *code*."""
    return decode(code, check=check)["bounds"]

cells_in_bounds(lat_min, lat_max, lon_min, lon_max, precision=12, domain='CI', max_cells=2000)

Return all Hilbert cells that intersect a geographic bounding box.

Each item is {"code": "CI-...", "bounds": {...}}.

Raises:

Type Description
ValueError

If domain is unknown, or if the requested area would produce more than max_cells cells (lower the precision or shrink the bounding box).

Source code in src/yoro/codec.py
def cells_in_bounds(
    lat_min: float,
    lat_max: float,
    lon_min: float,
    lon_max: float,
    precision: int = 12,
    domain: str = "CI",
    max_cells: int = 2000,
) -> list[Cell]:
    """Return all Hilbert cells that intersect a geographic bounding box.

    Each item is ``{"code": "CI-...", "bounds": {...}}``.

    Raises:
        ValueError: If *domain* is unknown, or if the requested area would
            produce more than *max_cells* cells (lower the precision or
            shrink the bounding box).
    """
    domain = domain.upper()
    dom = DOMAINS.get(domain)
    if not dom:
        raise ValueError(f"Unknown domain: '{domain}'. Available: {list(DOMAINS.keys())}")

    k = _code_length(precision)
    p = _canonical_precision(k)
    m = 1 << p

    lat_range = dom["lat_max"] - dom["lat_min"]
    lon_range = dom["lon_max"] - dom["lon_min"]
    lat_step = lat_range / m
    lon_step = lon_range / m

    y_min = max(0, int((lat_min - dom["lat_min"]) / lat_step))
    y_max = min(m - 1, int((lat_max - dom["lat_min"]) / lat_step))
    x_min = max(0, int((lon_min - dom["lon_min"]) / lon_step))
    x_max = min(m - 1, int((lon_max - dom["lon_min"]) / lon_step))

    count = (x_max - x_min + 1) * (y_max - y_min + 1)
    if count <= 0:
        return []
    if count > max_cells:
        raise ValueError(
            f"Bounding box would produce {count} cells (max_cells={max_cells}). "
            f"Lower the precision or shrink the box."
        )

    cells: list[Cell] = []
    for y in range(y_min, y_max + 1):
        for x in range(x_min, x_max + 1):
            d = _xy2d(p, x, y)
            cells.append(
                {
                    "code": f"{domain}-{_int_to_base29(d, k)}",
                    "bounds": {
                        "lat_min": dom["lat_min"] + y * lat_step,
                        "lat_max": dom["lat_min"] + (y + 1) * lat_step,
                        "lon_min": dom["lon_min"] + x * lon_step,
                        "lon_max": dom["lon_min"] + (x + 1) * lon_step,
                    },
                }
            )
    return cells

ranges(lat_min, lat_max, lon_min, lon_max, precision=12, domain='CI', max_ranges=None)

Decompose a bounding box into code intervals for B-tree queries.

Where :func:cells_in_bounds enumerates every cell — and refuses past max_cells — this returns the handful of intervals that contain them, whatever the area.

Parameters:

Name Type Description Default
lat_min float

Southern edge of the box, in degrees.

required
lat_max float

Northern edge of the box, in degrees.

required
lon_min float

Western edge of the box, in degrees.

required
lon_max float

Eastern edge of the box, in degrees.

required
precision int

Hilbert order; snapped to the canonical precision.

12
domain str

ISO country code or "XX".

'CI'
max_ranges int | None

Coalesce until at most this many intervals remain, merging the closest pairs first. The result then covers some cells outside the box — filter on exact coordinates afterwards if that matters.

None

Returns:

Type Description
list[tuple[str, str]]

List of (code_min, code_max) pairs, both bounds inclusive, ready

list[tuple[str, str]]

for code BETWEEN code_min AND code_max.

Example::

>>> for lo, hi in ranges(12.60, 12.66, -8.03, -7.97, domain="ML"):
...     cur.execute("SELECT * FROM pois WHERE code BETWEEN ? AND ?", (lo, hi))
Source code in src/yoro/codec.py
def ranges(
    lat_min: float,
    lat_max: float,
    lon_min: float,
    lon_max: float,
    precision: int = 12,
    domain: str = "CI",
    max_ranges: int | None = None,
) -> list[tuple[str, str]]:
    """Decompose a bounding box into code intervals for B-tree queries.

    Where :func:`cells_in_bounds` enumerates every cell — and refuses past
    ``max_cells`` — this returns the handful of intervals that contain them,
    whatever the area.

    Args:
        lat_min: Southern edge of the box, in degrees.
        lat_max: Northern edge of the box, in degrees.
        lon_min: Western edge of the box, in degrees.
        lon_max: Eastern edge of the box, in degrees.
        precision: Hilbert order; snapped to the canonical precision.
        domain: ISO country code or ``"XX"``.
        max_ranges: Coalesce until at most this many intervals remain, merging
            the closest pairs first. The result then covers some cells outside
            the box — filter on exact coordinates afterwards if that matters.

    Returns:
        List of ``(code_min, code_max)`` pairs, both bounds **inclusive**, ready
        for ``code BETWEEN code_min AND code_max``.

    Example::

        >>> for lo, hi in ranges(12.60, 12.66, -8.03, -7.97, domain="ML"):
        ...     cur.execute("SELECT * FROM pois WHERE code BETWEEN ? AND ?", (lo, hi))
    """
    if domain not in DOMAINS:
        raise ValueError(f"Unknown domain: '{domain}'. Available: {list(DOMAINS.keys())}")
    if lat_min > lat_max or lon_min > lon_max:
        raise ValueError("Invalid bounding box: min greater than max")
    if max_ranges is not None and max_ranges < 1:
        raise ValueError(f"max_ranges must be at least 1, got {max_ranges}")

    dom = DOMAINS[domain]
    k = _code_length(precision)
    p = _canonical_precision(k)
    m = 1 << p

    def cell(value: float, low: float, high: float) -> int:
        return max(0, min(m - 1, int((value - low) / (high - low) * m)))

    x0 = cell(lon_min, dom["lon_min"], dom["lon_max"])
    x1 = cell(lon_max, dom["lon_min"], dom["lon_max"])
    y0 = cell(lat_min, dom["lat_min"], dom["lat_max"])
    y1 = cell(lat_max, dom["lat_min"], dom["lat_max"])

    intervals = _index_ranges(p, x0, x1, y0, y1)
    if max_ranges is not None:
        intervals = _coalesce(intervals, max_ranges)
    if len(intervals) > MAX_RANGE_INTERVALS:
        raise ValueError(
            f"Bounding box decomposes into {len(intervals)} intervals "
            f"(max {MAX_RANGE_INTERVALS}). Lower the precision, shrink the box, "
            f"or pass max_ranges to coalesce them."
        )

    return [
        (f"{domain}-{_int_to_base29(lo, k)}", f"{domain}-{_int_to_base29(hi - 1, k)}")
        for lo, hi in intervals
    ]

prefix_range(prefix_code, full_length)

Return the full-code interval a truncated code covers.

Truncation has two possible readings, and they are not the same thing:

a. the index interval [d * 29^t, (d+1) * 29^t) — a connected segment of the curve, exactly what LIKE 'prefix%' matches; b. decoding the prefix as a short code — a cell at the canonical precision of k - t, whose edges do not align with the finer grid.

This function implements (a).

Parameters:

Name Type Description Default
prefix_code str

Truncated code, e.g. "CI-4H7".

required
full_length int

Body length k of the complete codes being matched.

required

Returns:

Type Description
str

(code_min, code_max), both inclusive, clipped to the valid index

str

range so it never spans codes :func:decode would reject.

Source code in src/yoro/codec.py
def prefix_range(prefix_code: str, full_length: int) -> tuple[str, str]:
    """Return the full-code interval a truncated code covers.

    Truncation has two possible readings, and they are not the same thing:

    a. the index interval ``[d * 29^t, (d+1) * 29^t)`` — a *connected* segment
       of the curve, exactly what ``LIKE 'prefix%'`` matches;
    b. decoding the prefix as a short code — a cell at the canonical precision
       of ``k - t``, whose edges do **not** align with the finer grid.

    This function implements (a).

    Args:
        prefix_code: Truncated code, e.g. ``"CI-4H7"``.
        full_length: Body length *k* of the complete codes being matched.

    Returns:
        ``(code_min, code_max)``, both inclusive, clipped to the valid index
        range so it never spans codes :func:`decode` would reject.
    """
    if not 1 <= full_length <= MAX_CODE_LENGTH:
        raise ValueError(f"full_length must be between 1 and {MAX_CODE_LENGTH}, got {full_length}")

    prefix, body = _parse_code(prefix_code)
    t = full_length - len(body)
    if t < 0:
        raise ValueError("Prefix is longer than the target code length")

    p = _canonical_precision(full_length)
    lo = _base29_to_int(body) * (BASE**t)
    hi = (_base29_to_int(body) + 1) * (BASE**t)

    limit = 1 << (2 * p)
    if lo >= limit:
        raise ValueError("Prefix falls outside the valid index range")
    hi = min(hi, limit)

    return (
        f"{prefix}-{_int_to_base29(lo, full_length)}",
        f"{prefix}-{_int_to_base29(hi - 1, full_length)}",
    )

check_char(body)

Return the check character for a base-29 code body.

c = (sum_i w_i * v_i) mod 29 with distinct non-zero weights. Catches every single-symbol substitution and every adjacent transposition.

Parameters:

Name Type Description Default
body str

Code body without the domain prefix and without a check character, e.g. "4H7A3B".

required

Example::

>>> check_char("4H7A3B")
'R'
Source code in src/yoro/codec.py
def check_char(body: str) -> str:
    """Return the check character for a base-29 code *body*.

    ``c = (sum_i w_i * v_i) mod 29`` with distinct non-zero weights. Catches
    every single-symbol substitution and every adjacent transposition.

    Args:
        body: Code body without the domain prefix and without a check
            character, e.g. ``"4H7A3B"``.

    Example::

        >>> check_char("4H7A3B")
        'R'
    """
    if len(body) > len(_CHECK_WEIGHTS):
        raise ValueError(f"Body too long to check: {len(body)} > {len(_CHECK_WEIGHTS)}")
    total = 0
    # strict=False on purpose: there are more weights than a body needs, and the
    # length was already checked above.
    for weight, char in zip(_CHECK_WEIGHTS, body.upper(), strict=False):
        if char not in CHAR_TO_VAL:
            raise ValueError(f"Invalid character in code: '{char}'")
        total += weight * CHAR_TO_VAL[char]
    return ALPHABET[total % BASE]

precision_levels(domain='CI', max_code_length=10)

Return all canonical precision levels for a domain.

A canonical precision is a Hilbert order p that produces a distinct code length k. Because codes use base-29, the mapping from p to k is k = ceil(2p * log2 / log29). Several consecutive values of p map to the same k — only the highest p for each k is canonical, i.e. the one that fully exploits the address space of k characters.

Parameters:

Name Type Description Default
domain str

ISO country code (affects resolution in meters).

'CI'
max_code_length int

Stop after this many characters (default 10 → ~4 cm).

10

Returns:

Type Description
list[PrecisionLevelInfo]

List of dicts with keys: precision, code_length, grid_size,

list[PrecisionLevelInfo]

total_cells, resolution_m.

Source code in src/yoro/codec.py
def precision_levels(domain: str = "CI", max_code_length: int = 10) -> list[PrecisionLevelInfo]:
    """Return all canonical precision levels for a domain.

    A canonical precision is a Hilbert order *p* that produces a distinct
    code length *k*.  Because codes use base-29, the mapping from *p* to *k*
    is ``k = ceil(2p * log2 / log29)``.  Several consecutive values of *p*
    map to the same *k* — only the highest *p* for each *k* is canonical,
    i.e. the one that fully exploits the address space of *k* characters.

    Args:
        domain: ISO country code (affects resolution in meters).
        max_code_length: Stop after this many characters (default 10 → ~4 cm).

    Returns:
        List of dicts with keys: ``precision``, ``code_length``, ``grid_size``,
        ``total_cells``, ``resolution_m``.
    """
    if domain not in DOMAINS:
        raise ValueError(f"Unknown domain: '{domain}'")

    levels: list[PrecisionLevelInfo] = []
    for k in range(1, max_code_length + 1):
        p = _canonical_precision(k)
        grid = 1 << p
        res = resolution(p, domain=domain)
        levels.append(
            {
                "precision": p,
                "code_length": k,
                "grid_size": grid,
                "total_cells": grid * grid,
                "resolution_m": round(res, 4),
            }
        )
    return levels

snap_precision(p)

Return the canonical precision that p actually resolves to.

Because the code length is quantized to whole base-29 characters, several values of p produce the same grid. This function shows which canonical precision is effectively used.

Example::

>>> snap_precision(18)
19          # p=18 and p=19 both use 8-character codes
>>> snap_precision(15)
17          # p=15 and p=16 both snap up to canonical p=17
Source code in src/yoro/codec.py
def snap_precision(p: int) -> int:
    """Return the canonical precision that *p* actually resolves to.

    Because the code length is quantized to whole base-29 characters,
    several values of *p* produce the same grid.  This function shows
    which canonical precision is effectively used.

    Example::

        >>> snap_precision(18)
        19          # p=18 and p=19 both use 8-character codes
        >>> snap_precision(15)
        17          # p=15 and p=16 both snap up to canonical p=17
    """
    k = _code_length(p)
    return _canonical_precision(k)

domain_for_country(country_code)

Map an ISO country code to an Yoro domain. Falls back to "XX".

Source code in src/yoro/codec.py
def domain_for_country(country_code: str | None) -> str:
    """Map an ISO country code to an Yoro domain. Falls back to ``"XX"``."""
    if not country_code:
        return "XX"
    code = country_code.upper()
    return code if code in DOMAINS else "XX"

domains_for(lat, lon)

Return every country domain whose box contains a point, tightest first.

Deliberately plural. Domains are bounding boxes, and in West Africa they overlap heavily: Bamako (12.63, -8.00) sits inside Mali's box and inside Guinea's, and Guinea's is the smaller of the two — so "the smallest box containing the point" answers Guinea for Mali's capital. No rule over rectangles fixes that; only real borders would, and this package does not carry them.

So this hands back the candidates and lets the caller decide with whatever it knows that boxes do not — a reverse geocode, a country column, the user's own answer. When you already know the country, use :func:encode_for_country instead.

Parameters:

Name Type Description Default
lat float

Latitude in degrees.

required
lon float

Longitude in degrees.

required

Returns:

Type Description
list[str]

Domain prefixes ordered by increasing box area, empty when no country

list[str]

box fits. "XX" is never included — it contains everything, which

list[str]

makes it useless as a candidate and correct only as a fallback.

Example::

>>> domains_for(12.63, -8.00)
['GN', 'ML']
Source code in src/yoro/codec.py
def domains_for(lat: float, lon: float) -> list[str]:
    """Return every country domain whose box contains a point, tightest first.

    Deliberately plural. Domains are bounding boxes, and in West Africa they
    overlap heavily: Bamako (12.63, -8.00) sits inside Mali's box *and* inside
    Guinea's, and Guinea's is the smaller of the two — so "the smallest box
    containing the point" answers Guinea for Mali's capital. No rule over
    rectangles fixes that; only real borders would, and this package does not
    carry them.

    So this hands back the candidates and lets the caller decide with whatever
    it knows that boxes do not — a reverse geocode, a country column, the user's
    own answer. When you already know the country, use
    :func:`encode_for_country` instead.

    Args:
        lat: Latitude in degrees.
        lon: Longitude in degrees.

    Returns:
        Domain prefixes ordered by increasing box area, empty when no country
        box fits. ``"XX"`` is never included — it contains everything, which
        makes it useless as a candidate and correct only as a fallback.

    Example::

        >>> domains_for(12.63, -8.00)
        ['GN', 'ML']
    """
    if not -90.0 <= lat <= 90.0:
        raise ValueError(f"Latitude out of range: {lat}")
    if not -180.0 <= lon <= 180.0:
        raise ValueError(f"Longitude out of range: {lon}")

    hits: list[tuple[float, str]] = []
    for name, dom in DOMAINS.items():
        if name == "XX":
            continue
        in_lat = dom["lat_min"] <= lat <= dom["lat_max"]
        in_lon = dom["lon_min"] <= lon <= dom["lon_max"]
        if not (in_lat and in_lon):
            continue
        area = (dom["lat_max"] - dom["lat_min"]) * (dom["lon_max"] - dom["lon_min"])
        hits.append((area, name))
    return [name for _, name in sorted(hits)]

domain_of(code)

Return the domain a code belongs to, without decoding it.

Cheaper than :func:decode when all you need is the domain — reading the prefix costs a string split, while decoding walks the whole Hilbert curve.

Parameters:

Name Type Description Default
code str

A Yoro code, e.g. "CI-4H7A3B". Case-insensitive.

required

Returns:

Type Description
str

The domain prefix, e.g. "CI".

Raises:

Type Description
ValueError

If the format is invalid or the domain is unknown.

Example::

>>> domain_of("ci-4h7a3b")
'CI'
Source code in src/yoro/codec.py
def domain_of(code: str) -> str:
    """Return the domain a code belongs to, without decoding it.

    Cheaper than :func:`decode` when all you need is the domain — reading the
    prefix costs a string split, while decoding walks the whole Hilbert curve.

    Args:
        code: A Yoro code, e.g. ``"CI-4H7A3B"``. Case-insensitive.

    Returns:
        The domain prefix, e.g. ``"CI"``.

    Raises:
        ValueError: If the format is invalid or the domain is unknown.

    Example::

        >>> domain_of("ci-4h7a3b")
        'CI'
    """
    prefix, _ = _parse_code(code)
    return prefix

anisotropy(domain='CI')

Width-to-height ratio of a domain's cells on the ground (1.0 = square).

The curve's locality guarantees are stated in normalized distance; they only carry over to metres when cells are roughly square. A domain drifting far from 1.0 means "nearby code" and "nearby place" have started to come apart along one axis — pick boxes such that lat_range ~= lon_range * cos(mid_latitude).

Returns:

Type Description
float

Ratio above 1.0 when cells are wider than tall.

Source code in src/yoro/codec.py
def anisotropy(domain: str = "CI") -> float:
    """Width-to-height ratio of a domain's cells on the ground (1.0 = square).

    The curve's locality guarantees are stated in normalized distance; they only
    carry over to metres when cells are roughly square. A domain drifting far
    from 1.0 means "nearby code" and "nearby place" have started to come apart
    along one axis — pick boxes such that
    ``lat_range ~= lon_range * cos(mid_latitude)``.

    Returns:
        Ratio above 1.0 when cells are wider than tall.
    """
    if domain not in DOMAINS:
        raise ValueError(f"Unknown domain: '{domain}'")
    dom = DOMAINS[domain]
    lat_range = dom["lat_max"] - dom["lat_min"]
    lon_range = dom["lon_max"] - dom["lon_min"]
    mid = math.radians((dom["lat_min"] + dom["lat_max"]) / 2)
    return (lon_range * math.cos(mid)) / lat_range