Skip to content

Core

Deployment settings, FastAPI dependencies, domain errors and their handlers.

app.core.settings

Compass platform settings (deployment), not use-case configuration.

Settings

Bases: BaseSettings

Process-wide Compass knobs loaded from the environment at startup.

cors_origins property

Origins allowed to call the API cross-origin; empty for same-origin only.

Returns:

Type Description
list[str]

Stripped origin strings from compass_cors_origins.

ontology_dir property

Root directory for shared ontology files (shapes, templates).

Returns:

Type Description
Path

Explicit compass_ontology_dir or the package-relative default.

use_case_dir property

Directory holding this deployment's compass.ttl and vocab.ttl.

Returns:

Type Description
Path

ontology_dir / compass_use_case.

_empty_ontology_dir_is_none(value) classmethod

Treat an empty string env override as unset.

Parameters:

Name Type Description Default
value object

Raw field value before validation.

required

Returns:

Type Description
object

None for empty input, otherwise value unchanged.

Source code in src/backend/app/core/settings.py
56
57
58
59
60
61
62
63
64
65
66
67
@field_validator("compass_ontology_dir", mode="before")
@classmethod
def _empty_ontology_dir_is_none(cls, value: object) -> object:
    """Treat an empty string env override as unset.

    Args:
        value: Raw field value before validation.

    Returns:
        ``None`` for empty input, otherwise *value* unchanged.
    """
    return None if value == "" else value

_strip_use_case(value) classmethod

Reject empty use-case names and strip whitespace.

Parameters:

Name Type Description Default
value object

Raw field value before validation.

required

Returns:

Type Description
object

Stripped string, or value unchanged when not a string.

Source code in src/backend/app/core/settings.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@field_validator("compass_use_case", mode="before")
@classmethod
def _strip_use_case(cls, value: object) -> object:
    """Reject empty use-case names and strip whitespace.

    Args:
        value: Raw field value before validation.

    Returns:
        Stripped string, or *value* unchanged when not a string.
    """
    if isinstance(value, str):
        stripped = value.strip()
        if not stripped:
            raise ValueError("COMPASS_USE_CASE must be a non-empty directory name")
        return stripped
    return value

_default_ontology_dir()

Return src/ontology of the checkout this package lives in.

Source code in src/backend/app/core/settings.py
11
12
13
14
def _default_ontology_dir() -> Path:
    """Return ``src/ontology`` of the checkout this package lives in."""
    # parents[3] of src/backend/app/core/settings.py is src/
    return Path(__file__).resolve().parents[3] / "ontology"

root_env_file()

Return the project-root .env file, or None when absent (e.g. under Compose).

Source code in src/backend/app/core/settings.py
17
18
19
20
21
def root_env_file() -> Path | None:
    """Return the project-root .env file, or ``None`` when absent (e.g. under Compose)."""
    # parents[4] of src/backend/app/core/settings.py is the repository root
    env_file = Path(__file__).resolve().parents[4] / ".env"
    return env_file if env_file.exists() else None

app.core.deps

Shared FastAPI dependencies.

get_settings()

Provide the process-wide deployment settings.

Returns:

Type Description
Settings

Singleton Settings instance.

Source code in src/backend/app/core/deps.py
15
16
17
18
19
20
21
def get_settings() -> Settings:
    """Provide the process-wide deployment settings.

    Returns:
        Singleton ``Settings`` instance.
    """
    return settings

get_config()

Provide the use-case configuration.

Returns:

Type Description
Config

Singleton Config instance.

Source code in src/backend/app/core/deps.py
24
25
26
27
28
29
30
def get_config() -> Config:
    """Provide the use-case configuration.

    Returns:
        Singleton ``Config`` instance.
    """
    return config

get_lang(cfg, lang='en')

Validate and return the lang query parameter.

Parameters:

Name Type Description Default
cfg Annotated[Config, Depends(get_config)]

Use-case config (defines supported_langs).

required
lang Annotated[str, Query(description='UI language code')]

Requested language code.

'en'

Returns:

Type Description
str

Validated language code.

Raises:

Type Description
UnsupportedLangError

When lang is not in cfg.supported_langs.

Source code in src/backend/app/core/deps.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def get_lang(
    cfg: Annotated[Config, Depends(get_config)],
    lang: Annotated[str, Query(description="UI language code")] = "en",
) -> str:
    """Validate and return the ``lang`` query parameter.

    Args:
        cfg: Use-case config (defines ``supported_langs``).
        lang: Requested language code.

    Returns:
        Validated language code.

    Raises:
        UnsupportedLangError: When *lang* is not in ``cfg.supported_langs``.
    """
    if lang not in cfg.supported_langs:
        raise UnsupportedLangError(
            f"Unsupported lang {lang!r}; supported: {', '.join(cfg.supported_langs)}"
        )
    return lang

app.core.exceptions

Domain errors raised by the API and mapped to HTTP in handlers.

AppError(detail)

Bases: Exception

Base for application errors that become a consistent JSON response.

Attributes:

Name Type Description
detail

Human-readable error message returned to the client.

Store detail and pass it to Exception.

Parameters:

Name Type Description Default
detail str

Error message.

required
Source code in src/backend/app/core/exceptions.py
11
12
13
14
15
16
17
18
def __init__(self, detail: str):
    """Store *detail* and pass it to ``Exception``.

    Args:
        detail: Error message.
    """
    self.detail = detail
    super().__init__(detail)

ReloadNotConfiguredError(detail)

Bases: AppError

Reload was requested but no token is configured on the server.

Source code in src/backend/app/core/exceptions.py
11
12
13
14
15
16
17
18
def __init__(self, detail: str):
    """Store *detail* and pass it to ``Exception``.

    Args:
        detail: Error message.
    """
    self.detail = detail
    super().__init__(detail)

UnauthorizedError(detail)

Bases: AppError

The caller failed an authentication check.

Source code in src/backend/app/core/exceptions.py
11
12
13
14
15
16
17
18
def __init__(self, detail: str):
    """Store *detail* and pass it to ``Exception``.

    Args:
        detail: Error message.
    """
    self.detail = detail
    super().__init__(detail)

UnsupportedLangError(detail)

Bases: AppError

The lang query parameter is not in the use-case Config.

Source code in src/backend/app/core/exceptions.py
11
12
13
14
15
16
17
18
def __init__(self, detail: str):
    """Store *detail* and pass it to ``Exception``.

    Args:
        detail: Error message.
    """
    self.detail = detail
    super().__init__(detail)

ReloadError(detail)

Bases: AppError

The files on disk are not usable. The store already serving is untouched.

Source code in src/backend/app/core/exceptions.py
11
12
13
14
15
16
17
18
def __init__(self, detail: str):
    """Store *detail* and pass it to ``Exception``.

    Args:
        detail: Error message.
    """
    self.detail = detail
    super().__init__(detail)

QueryError(detail)

Bases: AppError

A SPARQL query could not be executed.

Source code in src/backend/app/core/exceptions.py
11
12
13
14
15
16
17
18
def __init__(self, detail: str):
    """Store *detail* and pass it to ``Exception``.

    Args:
        detail: Error message.
    """
    self.detail = detail
    super().__init__(detail)

app.core.handlers

Register exception handlers that emit one JSON error shape.

register_exception_handlers(app)

Attach domain-error handlers that return a uniform JSON detail body.

Parameters:

Name Type Description Default
app FastAPI

FastAPI application to mutate in place.

required
Source code in src/backend/app/core/handlers.py
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def register_exception_handlers(app: FastAPI) -> None:
    """Attach domain-error handlers that return a uniform JSON ``detail`` body.

    Args:
        app: FastAPI application to mutate in place.
    """
    for error_type, status_code in _STATUS_BY_ERROR.items():
        app.add_exception_handler(error_type, _detail_handler(status_code))

    @app.exception_handler(InvalidTerm)
    async def invalid_term(_request: Request, exc: InvalidTerm) -> JSONResponse:
        return JSONResponse(status_code=400, content={"detail": str(exc)})

    @app.exception_handler(ReloadError)
    async def reload_error(_request: Request, exc: ReloadError) -> JSONResponse:
        logger.warning("ontology reload rejected: %s", exc)
        return JSONResponse(
            status_code=409,
            content={
                "detail": {
                    "reloaded": False,
                    "reason": str(exc),
                    "serving": "the previously loaded ontology is still being served",
                }
            },
        )

    @app.exception_handler(QueryError)
    async def query_error(_request: Request, _exc: QueryError) -> JSONResponse:
        # RDFStore.query has already logged the failing query; keep it out of
        # the response.
        return JSONResponse(status_code=500, content={"detail": "SPARQL query failed"})

app.core.cors

CORS for widgets served from another origin.

configure_cors(app)

Allow COMPASS_CORS_ORIGINS to call the API cross-origin.

Parameters:

Name Type Description Default
app FastAPI

The FastAPI application to configure.

required
Source code in src/backend/app/core/cors.py
 9
10
11
12
13
14
15
16
17
18
19
20
def configure_cors(app: FastAPI) -> None:
    """Allow ``COMPASS_CORS_ORIGINS`` to call the API cross-origin.

    Args:
        app: The FastAPI application to configure.
    """
    app.add_middleware(
        CORSMiddleware,
        allow_origins=settings.cors_origins,
        allow_methods=["GET", "POST"],
        allow_headers=["*"],
    )