Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions apps/backend/src/core/config.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import logging
import os
import secrets
import warnings
from functools import lru_cache
from string import Template
from typing import Annotated, Any, Literal
from urllib.parse import quote

from data_manipulation.logging import configure_logging
from pydantic import (
Expand Down Expand Up @@ -198,8 +198,8 @@ def all_cors_origins(self) -> list[str]:
def POSTGRES_DATAFEEDER_URI(self) -> PostgresDsn:
return PostgresDsn.build(
scheme="postgresql+psycopg",
username=self.POSTGRES_DATAFEEDER_USER,
password=self.POSTGRES_DATAFEEDER_PASSWORD,
username=quote(self.POSTGRES_DATAFEEDER_USER, safe=""),
password=quote(self.POSTGRES_DATAFEEDER_PASSWORD, safe=""),
host=self.POSTGRES_DATAFEEDER_HOST,
port=self.POSTGRES_DATAFEEDER_PORT,
path=self.POSTGRES_DATAFEEDER_DB,
Expand All @@ -208,10 +208,13 @@ def POSTGRES_DATAFEEDER_URI(self) -> PostgresDsn:
@computed_field # type: ignore[prop-decorator]
@property
def POSTGRES_DATA_URI(self) -> PostgresDsn:
# _set_data_db_defaults guarantees these are set by the time this is accessed.
assert self.POSTGRES_DATA_USER is not None
assert self.POSTGRES_DATA_PASSWORD is not None
return PostgresDsn.build(
scheme="postgresql+psycopg",
username=self.POSTGRES_DATA_USER,
password=self.POSTGRES_DATA_PASSWORD,
username=quote(self.POSTGRES_DATA_USER, safe=""),
password=quote(self.POSTGRES_DATA_PASSWORD, safe=""),
host=self.POSTGRES_DATA_HOST,
port=self.POSTGRES_DATA_PORT,
path=self.POSTGRES_DATA_DB,
Expand Down Expand Up @@ -261,11 +264,10 @@ def _enforce_non_default_secrets(self) -> Self:
@field_validator("*", mode="after")
@classmethod
def expand_env_vars(cls, v: Any) -> Any:
# safe_substitute leaves invalid or unresolved placeholders (e.g. a literal
# "$" in a password) untouched instead of raising, unlike substitute().
if isinstance(v, str):
try:
v = Template(v).substitute(os.environ)
except KeyError as e:
logging.error(f"Environment variable {e} not set for value: {v}")
v = Template(v).safe_substitute(os.environ)
return v


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ dev = [
[tool.uv]
# Source of truth for the uv version. Keep in sync with the UV_VERSION ARG
# default in apps/backend/Dockerfile and docker/Dockerfile.airflow.
required-version = "==0.9.15"
required-version = ">=0.9.15"

[tool.uv.sources]
geoservercloud = { git = "https://github.com/camptocamp/python-geoservercloud.git" }
Expand Down
Loading