Skip to content

Util

General purpose or cross-package utility modules.

geom

Geometry, WKT and SRS helpers.

Everything in this package that talks to GDAL. A geometry reaches xmas_core as a WKT string beside an SRS reference, and these are the three things every reader and writer needs from that pair: what kind of geometry it is, how to move between a single geometry and its multi variant, and what the SRS reference actually says about the coordinates - which is an EPSG code and an axis order, because CRS84 and EPSG:4326 differ in exactly the latter while sharing the former.

SRS

Bases: NamedTuple

What an SRS reference says about a geometry's coordinates.

cast_geom_to_multi

cast_geom_to_multi(geom: str) -> str

Cast a single geometry to its multi variant.

Source code in xmas_core/util/geom.py
def cast_geom_to_multi(geom: str) -> str:
    """Cast a single geometry to its multi variant."""
    ogr_geom = ogr.CreateGeometryFromWkt(geom)
    geom_type_name = ogr.GeometryTypeToName(ogr_geom.GetGeometryType())
    match geom_type_name:
        case "Polygon" | "Curve Polygon":
            ogr_geom = ogr.ForceToMultiPolygon(ogr_geom)
        case "Line String" | "Circular String" | "Compound Curve":
            ogr_geom = ogr.ForceToMultiLineString(ogr_geom)
        case "Point":
            ogr_geom = ogr.ForceToMultiPoint(ogr_geom)
    wkt: str = ogr_geom.ExportToWkt()
    return wkt

cast_geom_to_single

cast_geom_to_single(geom: str) -> str

Cast a multi geometry to its single variant.

Source code in xmas_core/util/geom.py
def cast_geom_to_single(geom: str) -> str:
    """Cast a multi geometry to its single variant."""
    ogr_geom = ogr.CreateGeometryFromWkt(geom)
    geom_type_name = ogr.GeometryTypeToName(ogr_geom.GetGeometryType())
    match geom_type_name:
        case "Multi Polygon" | "Multi Surface":
            ogr_geom = ogr.ForceToPolygon(ogr_geom)
        case "Multi Line String" | "Multi Curve":
            ogr_geom = ogr.ForceToLineString(ogr_geom)
        case "Multi Point":
            if ogr_geom.GetGeometryCount() == 1:
                ogr_geom = ogr_geom.GetGeometryRef(0)
    wkt: str = ogr_geom.ExportToWkt()
    return wkt

format_srs

format_srs(srid: int, fmt: Literal['short', 'url'] = 'url') -> str

Formats an EPSG SRID as an SRS string.

Parameters:

Name Type Description Default
srid int

The EPSG SRID.

required
fmt Literal['short', 'url']

"short" for EPSG:<code> or "url" for the OGC URL form.

'url'

Returns:

Type Description
str

The formatted SRS string.

Source code in xmas_core/util/geom.py
def format_srs(srid: int, fmt: Literal["short", "url"] = "url") -> str:
    """Formats an EPSG SRID as an SRS string.

    Args:
        srid: The EPSG SRID.
        fmt: ``"short"`` for ``EPSG:<code>`` or ``"url"`` for the OGC URL form.

    Returns:
        The formatted SRS string.
    """
    sr = osr.SpatialReference()
    sr.ImportFromEPSG(int(srid))
    auth, code = sr.GetAuthorityName(None), sr.GetAuthorityCode(None)
    match fmt:
        case "short":
            return f"{auth}:{code}"
        case "url":
            return f"http://www.opengis.net/def/crs/{auth}/0/{code}"

get_envelope

get_envelope(geoms: list[str]) -> tuple[float, float, float, float]

Return a BBOX for a list of geometries.

Parameters:

Name Type Description Default
geoms list[str]

A list of WKT strings.

required

Returns:

Name Type Description
tuple tuple[float, float, float, float]

The BBOX coordinates in the format min_X, max_X, min_Y, max_Y.

Source code in xmas_core/util/geom.py
def get_envelope(geoms: list[str]) -> tuple[float, float, float, float]:
    """Return a BBOX for a list of geometries.

    Args:
        geoms: A list of WKT strings.

    Returns:
        tuple: The BBOX coordinates in the format min_X, max_X, min_Y, max_Y.
    """
    ogr_geom = ogr.CreateGeometryFromWkt(geoms.pop(0))
    for geom in geoms:
        ogr_geom = ogr_geom.Union(ogr.CreateGeometryFromWkt(geom))
    bbox: tuple[float, float, float, float] = ogr_geom.GetEnvelope()
    return bbox

get_geometry_type_from_wkt

get_geometry_type_from_wkt(geom: str) -> type[GeometryType] | None

Derives the geometry type from a WKT string.

Source code in xmas_core/util/geom.py
def get_geometry_type_from_wkt(geom: str) -> type[GeometryType] | None:
    """Derives the geometry type from a WKT string."""
    # Imported lazily: this module is reached during the model package init,
    # so a module-level import of definitions would be circular.
    from xmas_core.model.appschema.definitions import (
        Line,
        MultiLine,
        MultiPoint,
        MultiPolygon,
        Point,
        Polygon,
    )

    for geom_model in (Line, MultiLine, MultiPoint, Point, Polygon, MultiPolygon):
        if re.match(geom_model.model_fields["wkt"].metadata[0].pattern, geom):
            return geom_model
    return None

parse_srs

parse_srs(srs: str | dict[str, Any] | None) -> SRS

Resolves an SRS reference to an EPSG SRID and an axis order.

Accepts any notation OGR's SetFromUserInput understands (EPSG:25832, urn:ogc:def:crs:EPSG::25832, the OGC URL form, WKT) as well as the JSON-FG coordRefSys object form ({"type": "Reference", "href": ...}). CRS84 and its OGC URI/URN aliases resolve to 4326. The JSON-FG array (compound CRS) form is not supported.

swap_axes says whether the reference orders latitude or northing first, so a geometry read under it has to be swapped to reach the x/y a Geometry field stores - and swapped back on the way out. Two things decide it: EPSG defines 4326 and 4258 latitude-first and the Gauß-Krüger zones 31466-31469 northing-first, where the UTM zones and CRS84 are x/y already; and only the URN and OGC URL notations carry that order at all. CRS84 and EPSG:4326 differ in exactly this while sharing an SRID, which is why the answer cannot come from srid alone.

Parameters:

Name Type Description Default
srs str | dict[str, Any] | None

The SRS reference, as a string, a JSON-FG coordRefSys object, or None.

required

Returns:

Type Description
SRS

The EPSG SRID, or None if it could not be determined, and whether coordinates read

SRS

under this reference need swapping to reach x/y.

Source code in xmas_core/util/geom.py
def parse_srs(srs: str | dict[str, Any] | None) -> SRS:
    """Resolves an SRS reference to an EPSG SRID and an axis order.

    Accepts any notation OGR's ``SetFromUserInput`` understands (``EPSG:25832``,
    ``urn:ogc:def:crs:EPSG::25832``, the OGC URL form, WKT) as well as the JSON-FG
    ``coordRefSys`` object form (``{"type": "Reference", "href": ...}``). CRS84 and
    its OGC URI/URN aliases resolve to 4326. The JSON-FG array (compound CRS) form
    is not supported.

    ``swap_axes`` says whether the reference orders latitude or northing first, so a geometry
    read under it has to be swapped to reach the x/y a ``Geometry`` field stores - and
    swapped back on the way out. Two things decide it: EPSG defines 4326 and 4258
    latitude-first and the Gauß-Krüger zones 31466-31469 northing-first, where the UTM zones
    and CRS84 are x/y already; and only the URN and OGC URL notations carry that order at
    all. CRS84 and EPSG:4326 differ in exactly this while sharing an SRID, which is why the
    answer cannot come from ``srid`` alone.

    Args:
        srs: The SRS reference, as a string, a JSON-FG ``coordRefSys`` object, or None.

    Returns:
        The EPSG SRID, or None if it could not be determined, and whether coordinates read
        under this reference need swapping to reach x/y.
    """
    if isinstance(srs, dict):
        href = srs.get("href")
        srs = href if isinstance(href, str) else None
    if not srs:
        return SRS(None, False)
    srs = srs.strip()
    # OGC WGS 84 lon/lat alias (bare "CRS84", "OGC:CRS84", urn/URL forms): not
    # resolvable to an EPSG code via OGR, but equivalent to EPSG:4326.
    if "CRS84" in srs:
        return SRS(4326, False)
    sr = osr.SpatialReference()
    try:
        sr.SetFromUserInput(srs)
        code = sr.GetAuthorityCode(None)
        if not (code and code.isdigit()):
            sr.AutoIdentifyEPSG()
            code = sr.GetAuthorityCode(None)
    except RuntimeError:
        return SRS(None, False)
    swap_axes = bool(_AUTHORITY_ORDER_SRS.match(srs)) and bool(
        sr.EPSGTreatsAsLatLong() or sr.EPSGTreatsAsNorthingEasting()
    )
    return SRS(int(code) if code and code.isdigit() else None, swap_axes)

identifier

UUID parsing and serialization.

is_uuid

is_uuid(value: str | None, exact: bool = False) -> bool

Check whether a given string is - or, unless exact, contains - a valid UUID.

Source code in xmas_core/util/identifier.py
def is_uuid(value: str | None, exact: bool = False) -> bool:
    """Check whether a given string is - or, unless `exact`, contains - a valid UUID."""
    lookup = _UUID_RE.fullmatch if exact else _UUID_RE.search
    return lookup(value or "") is not None

parse_uuid

parse_uuid(value: str | None, exact: bool = False) -> UUID | None

Return the UUID a given string is - or, unless exact, contains - or None.

Source code in xmas_core/util/identifier.py
def parse_uuid(value: str | None, exact: bool = False) -> UUID | None:
    """Return the UUID a given string is - or, unless `exact`, contains - or None."""
    lookup = _UUID_RE.fullmatch if exact else _UUID_RE.search
    match = lookup(value or "")
    return UUID(match.group()) if match else None