Source code for geodetic_engine.osdudb.build

"""Orchestration for a proj.db build from an OSDU catalogue.

The catalogue is read concept by concept, in the order proj.db's foreign keys
require: CRSs before the operations between them, and bound CRSs last because
each one embeds a transformation. Everything a record implies is staged as it
is read and written in one transaction at the end; see
:mod:`geodetic_engine.osdudb.context`.
"""

from __future__ import annotations

import logging

from geodetic_engine.osdudb import bound, crs, operation
from geodetic_engine.osdudb.catalog import OsduCatalog
from geodetic_engine.osdudb.config import OsduBuildConfig
from geodetic_engine.osdudb.context import OsduBuildContext, write_staged
from geodetic_engine.osdudb.definition import UnitResolver
from geodetic_engine.projdb import common
from geodetic_engine.projdb.alias import AliasCollector
from geodetic_engine.projdb.records import UsageAccumulator
from geodetic_engine.projdb.report import BuildReport, log_summary
from geodetic_engine.projdb.writer import ProjDbWriter

__all__ = ["BuildReport", "build", "log_summary"]

logger = logging.getLogger(__name__)


[docs] def build( config: OsduBuildConfig, *, catalog: OsduCatalog | None = None, dry_run: bool = False, skip_validation: bool = False, ) -> BuildReport: """Build an enriched proj.db from an OSDU coordinate reference catalogue. The official database is copied and added to; it is never modified in place and no row belonging to another authority is ever overwritten. Args: config: Resolved build configuration. catalog: Pre-read catalogue, mainly for testing. Read from ``config.catalog`` when omitted. dry_run: Perform the whole build, including every constraint and collision check, then discard it instead of committing. Nothing is left on disk. This exercises the same code as a real build rather than approximating it, so a dry run that succeeds means a real build would too. skip_validation: Explicitly skip PROJ validation before publication. False by default; the choice is recorded in the build history. Returns: The build report. Raises: ProjDbBuildError: On a build or validation failure. Staging is discarded and any previously published database is preserved. Example: >>> report = build(load_config(catalog=Path("CRS_CT.json"))) # doctest: +SKIP >>> report.rows_by_table["projected_crs"] # doctest: +SKIP 998 """ catalog = catalog or OsduCatalog.from_file(config.catalog) with ProjDbWriter(config) as writer: context = OsduBuildContext( config=config, catalog=catalog, writer=writer, usage=UsageAccumulator(), alias=AliasCollector(config.naming_systems), units=UnitResolver(writer.connection), ) crs.collect_geodetic(context) crs.collect_vertical(context) crs.collect_engineering(context) crs.collect_projected(context) crs.collect_compound(context) operation.collect_transformations(context) operation.collect_concatenated(context) # Last of the objects: a bound CRS embeds a transformation, so it can # only be assembled once the transformations have been read. bound.collect_bound(context) write_staged(context) common.write_annotations(context, source_described="The catalogue") preferences = common.write_authority_preferences(context) report = _report(config, context, catalog) report.authority_preferences = preferences report.rows_by_table = dict(sorted(writer.inserted.items())) report.appended = writer.appended report.overwrite_rows = config.overwrite_rows report.dry_run = dry_run common.finish_build( context, report, source="osdudb", skip_validation=skip_validation ) return report
def _report( config: OsduBuildConfig, context: OsduBuildContext, catalog: OsduCatalog ) -> BuildReport: return common.base_report( context, source=str(catalog.path or config.catalog), source_version=config.catalog_version, include_deprecated=config.include_deprecated, )