from __future__ import annotations from typing import Literal from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): # Which graph engine executes SPARQL queries. # - rdflib: parse TTL locally and query in-memory # - anzograph: query a remote AnzoGraph SPARQL endpoint (optionally LOAD on startup) graph_backend: Literal["rdflib", "anzograph"] = Field(default="rdflib", alias="GRAPH_BACKEND") ttl_path: str = Field(default="/data/o3po.ttl", alias="TTL_PATH") include_bnodes: bool = Field(default=False, alias="INCLUDE_BNODES") max_triples: int | None = Field(default=None, alias="MAX_TRIPLES") # AnzoGraph / SPARQL endpoint configuration sparql_host: str = Field(default="http://anzograph:8080", alias="SPARQL_HOST") # If not set, the backend uses `${SPARQL_HOST}/sparql`. sparql_endpoint: str | None = Field(default=None, alias="SPARQL_ENDPOINT") sparql_user: str | None = Field(default=None, alias="SPARQL_USER") sparql_pass: str | None = Field(default=None, alias="SPARQL_PASS") # File URI as seen by the AnzoGraph container (used with SPARQL `LOAD`). # Example: file:///opt/shared-files/o3po.ttl sparql_data_file: str | None = Field(default=None, alias="SPARQL_DATA_FILE") sparql_graph_iri: str | None = Field(default=None, alias="SPARQL_GRAPH_IRI") sparql_load_on_start: bool = Field(default=False, alias="SPARQL_LOAD_ON_START") sparql_clear_on_start: bool = Field(default=False, alias="SPARQL_CLEAR_ON_START") sparql_timeout_s: float = Field(default=300.0, alias="SPARQL_TIMEOUT_S") sparql_ready_retries: int = Field(default=30, alias="SPARQL_READY_RETRIES") sparql_ready_delay_s: float = Field(default=4.0, alias="SPARQL_READY_DELAY_S") # Comma-separated, or "*" (default). cors_origins: str = Field(default="*", alias="CORS_ORIGINS") model_config = SettingsConfigDict(env_file=".env", extra="ignore") def cors_origin_list(self) -> list[str]: if self.cors_origins.strip() == "*": return ["*"] return [o.strip() for o in self.cors_origins.split(",") if o.strip()] def effective_sparql_endpoint(self) -> str: if self.sparql_endpoint and self.sparql_endpoint.strip(): return self.sparql_endpoint.strip() return self.sparql_host.rstrip("/") + "/sparql"