From 7329a4fb41f41726cf97fc9fcd69d9487c8120d0 Mon Sep 17 00:00:00 2001 From: Christophe Haen Date: Mon, 1 Jun 2026 14:43:02 +0200 Subject: [PATCH 1/5] start --- diracx-core/src/diracx/core/settings.py | 81 ++++++++++++++++++++ diracx-routers/src/diracx/routers/factory.py | 10 +-- docs/admin/reference/env-variables.md | 41 ++++++++++ docs/admin/reference/env-variables.md.j2 | 3 + 4 files changed, 130 insertions(+), 5 deletions(-) diff --git a/diracx-core/src/diracx/core/settings.py b/diracx-core/src/diracx/core/settings.py index dd55a88a8..837c78f2c 100644 --- a/diracx-core/src/diracx/core/settings.py +++ b/diracx-core/src/diracx/core/settings.py @@ -32,6 +32,7 @@ SecretStr, TypeAdapter, UrlConstraints, + create_model, model_validator, ) from pydantic_settings import BaseSettings, SettingsConfigDict @@ -358,3 +359,83 @@ def s3_client(self) -> S3Client: if self._client is None: raise RuntimeError("S3 client accessed before lifetime function") return self._client + + +# def make_factory_settings(model_cls: type[StaticFactorySettings]): +# new_fields = {} +# for var, val in os.environ.items(): +# if var.startswith("XDG_"): +# new_fields[var] = (str, val) +# return create_model("FactorySettings", __base__=model_cls, **new_fields) + + +# FactorySettings = make_factory_settings(StaticFactorySettings) + + +from pydantic import Field + +# Could come from code, YAML, DB, plugin system, etc. +FIELD_SPECS = { + "state_key": { + "type": str, + "default": ..., + "env": "DIRACX_SERVICE_AUTH_STATE_KEY", + "description": "Fernet key used to encrypt/decrypt OAuth2 state.", + }, + "token_issuer": { + "type": str, + "default": ..., + "env": "DIRACX_SERVICE_AUTH_TOKEN_ISSUER", + "description": "JWT issuer value ('iss' claim).", + }, + "access_token_expire_minutes": { + "type": int, + "default": 20, + "env": "DIRACX_SERVICE_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES", + "description": "Access token lifetime in minutes.", + }, +} + +from .extensions import DiracEntryPoint, select_from_extension + + +def _build_factory_settings_model() -> type[ServiceSettingsBase]: + class _BaseFactorySettings(ServiceSettingsBase): + """Factory settings. + + Settings which do not fit into dedicated classes, + or are dynamically generated + """ + + diracx_legacy_exchange_hashed_api_key: str = "" + enabled_services: dict[str, bool] + + fields: dict[str, tuple[Any, Any]] = {} + + for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): + if "well-known" in entry_point.name: + continue + fields[f"diracx_service_{entry_point.name}_enabled"] = ( + bool, + Field( + default=True, + description=f"Enable the {entry_point.name.upper()} router", + ), + ) + + new_mod = create_model( + "FactorySettings", + __doc__=_BaseFactorySettings.__doc__, + __base__=_BaseFactorySettings, + # __config__=SettingsConfigDict( + # frozen=True, + # extra="ignore", + # use_attribute_docstrings=True, + # ), + **fields, + ) + + return new_mod + + +FactorySettings = _build_factory_settings_model() diff --git a/diracx-routers/src/diracx/routers/factory.py b/diracx-routers/src/diracx/routers/factory.py index 342e6d5cd..18e051b94 100644 --- a/diracx-routers/src/diracx/routers/factory.py +++ b/diracx-routers/src/diracx/routers/factory.py @@ -6,7 +6,6 @@ import inspect import logging -import os from collections.abc import AsyncGenerator, Awaitable, Callable, Iterable, Sequence from functools import partial from http import HTTPStatus @@ -24,14 +23,13 @@ from fastapi.responses import JSONResponse, Response from fastapi.routing import APIRoute from packaging.version import InvalidVersion, parse -from pydantic import TypeAdapter from starlette.middleware.base import BaseHTTPMiddleware from uvicorn.logging import AccessFormatter, DefaultFormatter from diracx.core.config import ConfigSource from diracx.core.exceptions import DiracError, DiracHttpResponseError, NotReadyError from diracx.core.extensions import DiracEntryPoint, select_from_extension -from diracx.core.settings import ServiceSettingsBase +from diracx.core.settings import FactorySettings, ServiceSettingsBase from diracx.core.utils import dotenv_files_from_environment from diracx.db.exceptions import DBUnavailableError from diracx.db.os.utils import BaseOSDB @@ -354,9 +352,11 @@ def create_app() -> DiracFastAPI: # Load all available routers enabled_systems = set() settings_classes = set() + factory_settings = FactorySettings() for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): - env_var = f"DIRACX_SERVICE_{entry_point.name.upper()}_ENABLED" - enabled = TypeAdapter(bool).validate_json(os.environ.get(env_var, "true")) + enabled = getattr( + factory_settings, f"diracx_service_{entry_point.name}_enabled", True + ) logger.debug("Found service %r: enabled=%s", entry_point, enabled) if not enabled: continue diff --git a/docs/admin/reference/env-variables.md b/docs/admin/reference/env-variables.md index ea9a04a49..0d96db09b 100644 --- a/docs/admin/reference/env-variables.md +++ b/docs/admin/reference/env-variables.md @@ -17,6 +17,47 @@ The variable points to .env files where configuration may be placed. There could Determines whether the jobs service is enabled. +## FactorySettings + +Factory settings. + +``` + Settings which do not fit into dedicated classes, + or are dynamically generated +``` + +### `DIRACX_LEGACY_EXCHANGE_HASHED_API_KEY` + +*Optional*, default value: \`\` + +### `ENABLED_SERVICES` + +**Required** + +### `DIRACX_SERVICE_AUTH_ENABLED` + +*Optional*, default value: `True` + +Enable the AUTH router + +### `DIRACX_SERVICE_CONFIG_ENABLED` + +*Optional*, default value: `True` + +Enable the CONFIG router + +### `DIRACX_SERVICE_HEALTH_ENABLED` + +*Optional*, default value: `True` + +Enable the HEALTH router + +### `DIRACX_SERVICE_JOBS_ENABLED` + +*Optional*, default value: `True` + +Enable the JOBS router + ## AuthSettings Settings for the authentication service. diff --git a/docs/admin/reference/env-variables.md.j2 b/docs/admin/reference/env-variables.md.j2 index 29cb4f078..385abca45 100644 --- a/docs/admin/reference/env-variables.md.j2 +++ b/docs/admin/reference/env-variables.md.j2 @@ -15,6 +15,9 @@ _X, where X is a number. The files will be loaded in order. ### `DIRACX_SERVICE_JOBS_ENABLED` Determines whether the jobs service is enabled. +{{ render_class('FactorySettings') }} + + {{ render_class('AuthSettings') }} ### `DIRACX_LEGACY_EXCHANGE_HASHED_API_KEY` From f7b489cb3cddff547bc0d042f3a59925ead28349 Mon Sep 17 00:00:00 2001 From: Christophe Haen Date: Mon, 1 Jun 2026 15:57:06 +0200 Subject: [PATCH 2/5] progress --- diracx-core/src/diracx/core/settings.py | 108 +++++++++++++++---- diracx-routers/src/diracx/routers/factory.py | 1 + docs/admin/reference/env-variables.md | 44 ++++++-- docs/admin/reference/env-variables.md.j2 | 7 +- 4 files changed, 134 insertions(+), 26 deletions(-) diff --git a/diracx-core/src/diracx/core/settings.py b/diracx-core/src/diracx/core/settings.py index 837c78f2c..80efbe316 100644 --- a/diracx-core/src/diracx/core/settings.py +++ b/diracx-core/src/diracx/core/settings.py @@ -16,7 +16,7 @@ import json from collections.abc import AsyncIterator from pathlib import Path -from typing import TYPE_CHECKING, Annotated, Any, Self, TypeVar, cast +from typing import TYPE_CHECKING, Annotated, Any, Self, TypeVar, cast, MutableMapping from aiobotocore.session import get_session from botocore.config import Config @@ -400,42 +400,114 @@ def s3_client(self) -> S3Client: def _build_factory_settings_model() -> type[ServiceSettingsBase]: - class _BaseFactorySettings(ServiceSettingsBase): - """Factory settings. - - Settings which do not fit into dedicated classes, - or are dynamically generated - """ - - diracx_legacy_exchange_hashed_api_key: str = "" - enabled_services: dict[str, bool] - fields: dict[str, tuple[Any, Any]] = {} + enabled_services_field: dict[str, tuple[Any, Any]] = {} for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): if "well-known" in entry_point.name: continue - fields[f"diracx_service_{entry_point.name}_enabled"] = ( + enabled_services_field[f"{entry_point.name}"] = ( bool, Field( default=True, + validation_alias=f"DIRACX_SERVICE_{entry_point.name.upper()}_ENABLED", description=f"Enable the {entry_point.name.upper()} router", ), ) + EnabledServices = create_model( + "EnabledServices", + __doc__="Enabled services", + __base__=ServiceSettingsBase, + __config__=SettingsConfigDict( + frozen=True, + use_attribute_docstrings=True, + ), + **enabled_services_field, + ) + + class _BaseFactorySettings(ServiceSettingsBase): + """Factory settings. + + Settings which do not fit into dedicated classes, + or are dynamically generated. + """ + + model_config = SettingsConfigDict(use_attribute_docstrings=True) + + diracx_legacy_exchange_hashed_api_key: str = "" + """Maximum legacy prout. + + Higher values allow more parallel S3 requests (e.g. during bulk sandbox + deletion). + """ + + enabled_services: EnabledServices = Field(default_factory=EnabledServices) + """ + The enabled servicsdsdsds + """ + + fields: dict[str, tuple[Any, Any]] = {} + new_mod = create_model( "FactorySettings", __doc__=_BaseFactorySettings.__doc__, __base__=_BaseFactorySettings, - # __config__=SettingsConfigDict( - # frozen=True, - # extra="ignore", - # use_attribute_docstrings=True, - # ), **fields, ) - + breakpoint() return new_mod FactorySettings = _build_factory_settings_model() + + +# class FactorySettings(ServiceSettingsBase): +# """Factory settings. + +# Settings which do not fit into dedicated classes, +# or are dynamically generated +# """ + +# diracx_legacy_exchange_hashed_api_key: str = "" + +# enabled_services: MutableMapping[str, bool] + + +# @model_validator(mode="before") +# @classmethod +# def check_enabled_services(cls, v): +# for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): + +# if "well-known" in entry_point.name: +# continue +# fields[f"diracx_service_{entry_point.name}_enabled"] = ( +# bool, +# Field( +# default=True, +# description=f"Enable the {entry_point.name.upper()} router", +# ), +# ) + + +class ChildSettings(ServiceSettingsBase): + """The actuall child impl""" + + model_config = SettingsConfigDict(env_prefix="YOYO_", use_attribute_docstrings=True) + + bim: str + """Name of the S3 bucket used for storing job sandboxes. + + This bucket will contain input and output sandbox files for DIRAC jobs. + The bucket must exist or auto_create_bucket must be enabled. + """ + + +class ParentSettings(ServiceSettingsBase): + """It's hard to be a parent""" + + model_config = SettingsConfigDict(env_prefix="TATA_", use_attribute_docstrings=True) + + bucket_name: ChildSettings + """The child. + """ diff --git a/diracx-routers/src/diracx/routers/factory.py b/diracx-routers/src/diracx/routers/factory.py index 18e051b94..7d6273618 100644 --- a/diracx-routers/src/diracx/routers/factory.py +++ b/diracx-routers/src/diracx/routers/factory.py @@ -354,6 +354,7 @@ def create_app() -> DiracFastAPI: settings_classes = set() factory_settings = FactorySettings() for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): + factory_settings.enabled_services enabled = getattr( factory_settings, f"diracx_service_{entry_point.name}_enabled", True ) diff --git a/docs/admin/reference/env-variables.md b/docs/admin/reference/env-variables.md index 0d96db09b..de842107b 100644 --- a/docs/admin/reference/env-variables.md +++ b/docs/admin/reference/env-variables.md @@ -13,7 +13,7 @@ The URL of the configuration backend. The variable points to .env files where configuration may be placed. There could be more than one file, with suffixes \_X, where X is a number. The files will be loaded in order. -### `DIRACX_SERVICE_JOBS_ENABLED` +### `DIRACX_SERVICE_JOBSjinga_ENABLED` Determines whether the jobs service is enabled. @@ -23,36 +23,43 @@ Factory settings. ``` Settings which do not fit into dedicated classes, - or are dynamically generated + or are dynamically generated. ``` ### `DIRACX_LEGACY_EXCHANGE_HASHED_API_KEY` *Optional*, default value: \`\` +Maximum legacy prout. + +Higher values allow more parallel S3 requests (e.g. during bulk sandbox +deletion). + ### `ENABLED_SERVICES` -**Required** +*Optional* -### `DIRACX_SERVICE_AUTH_ENABLED` +The enabled servicsdsdsds + +### `DIRACX_SERVICE_AUTH_ENABLED_PROUT` *Optional*, default value: `True` Enable the AUTH router -### `DIRACX_SERVICE_CONFIG_ENABLED` +### `DIRACX_SERVICE_CONFIG_ENABLED_PROUT` *Optional*, default value: `True` Enable the CONFIG router -### `DIRACX_SERVICE_HEALTH_ENABLED` +### `DIRACX_SERVICE_HEALTH_ENABLED_PROUT` *Optional*, default value: `True` Enable the HEALTH router -### `DIRACX_SERVICE_JOBS_ENABLED` +### `DIRACX_SERVICE_JOBS_ENABLED_PROUT` *Optional*, default value: `True` @@ -302,3 +309,26 @@ Whether to use an insecure gRPC connection for the OpenTelemetry collector. *Optional*, default value: `None` A JSON-encoded dictionary of headers to pass to the OpenTelemetry collector, e.g. {"tenant_id": "lhcbdiracx-cert"}. + +## ParentSettings + +It's hard to be a parent + +### `TATA_BUCKET_NAME` + +**Required** + +The child. + +## ChildSettings + +The actuall child impl + +### `YOYO_BIM` + +**Required** + +Name of the S3 bucket used for storing job sandboxes. + +This bucket will contain input and output sandbox files for DIRAC jobs. +The bucket must exist or auto_create_bucket must be enabled. diff --git a/docs/admin/reference/env-variables.md.j2 b/docs/admin/reference/env-variables.md.j2 index 385abca45..c5da98849 100644 --- a/docs/admin/reference/env-variables.md.j2 +++ b/docs/admin/reference/env-variables.md.j2 @@ -12,7 +12,7 @@ The URL of the configuration backend. The variable points to .env files where configuration may be placed. There could be more than one file, with suffixes _X, where X is a number. The files will be loaded in order. -### `DIRACX_SERVICE_JOBS_ENABLED` +### `DIRACX_SERVICE_JOBSjinga_ENABLED` Determines whether the jobs service is enabled. {{ render_class('FactorySettings') }} @@ -36,3 +36,8 @@ The URL for the SQL database ``. A JSON-encoded dictionary of connection keyword arguments for the OpenSearch database ``. {{ render_class('OTELSettings') }} + + + +{{ render_class('ParentSettings') }} +{{ render_class('ChildSettings') }} From 3c9f3e1d90d4b49efba734136063b528c1abf438 Mon Sep 17 00:00:00 2001 From: Christophe Haen Date: Mon, 1 Jun 2026 17:15:18 +0200 Subject: [PATCH 3/5] cont --- diracx-core/src/diracx/core/settings.py | 40 +++----------- diracx-routers/src/diracx/routers/factory.py | 7 ++- docs/admin/reference/env-variables.md | 58 +------------------- docs/admin/reference/env-variables.md.j2 | 8 --- 4 files changed, 14 insertions(+), 99 deletions(-) diff --git a/diracx-core/src/diracx/core/settings.py b/diracx-core/src/diracx/core/settings.py index 80efbe316..6f5a8a0d4 100644 --- a/diracx-core/src/diracx/core/settings.py +++ b/diracx-core/src/diracx/core/settings.py @@ -16,7 +16,7 @@ import json from collections.abc import AsyncIterator from pathlib import Path -from typing import TYPE_CHECKING, Annotated, Any, Self, TypeVar, cast, MutableMapping +from typing import TYPE_CHECKING, Annotated, Any, Self, TypeVar, cast from aiobotocore.session import get_session from botocore.config import Config @@ -436,16 +436,14 @@ class _BaseFactorySettings(ServiceSettingsBase): model_config = SettingsConfigDict(use_attribute_docstrings=True) diracx_legacy_exchange_hashed_api_key: str = "" - """Maximum legacy prout. - - Higher values allow more parallel S3 requests (e.g. during bulk sandbox - deletion). + """The hashed API key for the legacy exchange endpoint. """ - enabled_services: EnabledServices = Field(default_factory=EnabledServices) - """ - The enabled servicsdsdsds - """ + enabled_services: EnabledServices = Field( + default_factory=EnabledServices, + # TODO fix the variable doc generation + description=str(EnabledServices.schema_json()), + ) fields: dict[str, tuple[Any, Any]] = {} @@ -455,7 +453,6 @@ class _BaseFactorySettings(ServiceSettingsBase): __base__=_BaseFactorySettings, **fields, ) - breakpoint() return new_mod @@ -488,26 +485,3 @@ class _BaseFactorySettings(ServiceSettingsBase): # description=f"Enable the {entry_point.name.upper()} router", # ), # ) - - -class ChildSettings(ServiceSettingsBase): - """The actuall child impl""" - - model_config = SettingsConfigDict(env_prefix="YOYO_", use_attribute_docstrings=True) - - bim: str - """Name of the S3 bucket used for storing job sandboxes. - - This bucket will contain input and output sandbox files for DIRAC jobs. - The bucket must exist or auto_create_bucket must be enabled. - """ - - -class ParentSettings(ServiceSettingsBase): - """It's hard to be a parent""" - - model_config = SettingsConfigDict(env_prefix="TATA_", use_attribute_docstrings=True) - - bucket_name: ChildSettings - """The child. - """ diff --git a/diracx-routers/src/diracx/routers/factory.py b/diracx-routers/src/diracx/routers/factory.py index 7d6273618..d93109721 100644 --- a/diracx-routers/src/diracx/routers/factory.py +++ b/diracx-routers/src/diracx/routers/factory.py @@ -353,11 +353,14 @@ def create_app() -> DiracFastAPI: enabled_systems = set() settings_classes = set() factory_settings = FactorySettings() + print(f"CHRIS {factory_settings}") for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): - factory_settings.enabled_services enabled = getattr( - factory_settings, f"diracx_service_{entry_point.name}_enabled", True + factory_settings.enabled_services, + entry_point.name, + True, ) + print("CHRIS Found service %r: enabled=%s", entry_point, enabled) logger.debug("Found service %r: enabled=%s", entry_point, enabled) if not enabled: continue diff --git a/docs/admin/reference/env-variables.md b/docs/admin/reference/env-variables.md index de842107b..bc486f777 100644 --- a/docs/admin/reference/env-variables.md +++ b/docs/admin/reference/env-variables.md @@ -30,40 +30,13 @@ Factory settings. *Optional*, default value: \`\` -Maximum legacy prout. - -Higher values allow more parallel S3 requests (e.g. during bulk sandbox -deletion). +The hashed API key for the legacy exchange endpoint. ### `ENABLED_SERVICES` *Optional* -The enabled servicsdsdsds - -### `DIRACX_SERVICE_AUTH_ENABLED_PROUT` - -*Optional*, default value: `True` - -Enable the AUTH router - -### `DIRACX_SERVICE_CONFIG_ENABLED_PROUT` - -*Optional*, default value: `True` - -Enable the CONFIG router - -### `DIRACX_SERVICE_HEALTH_ENABLED_PROUT` - -*Optional*, default value: `True` - -Enable the HEALTH router - -### `DIRACX_SERVICE_JOBS_ENABLED_PROUT` - -*Optional*, default value: `True` - -Enable the JOBS router +{"additionalProperties": false, "description": "Enabled services", "properties": {"DIRACX_SERVICE_AUTH_ENABLED": {"default": true, "description": "Enable the AUTH router", "title": "Diracx Service Auth Enabled", "type": "boolean"}, "DIRACX_SERVICE_CONFIG_ENABLED": {"default": true, "description": "Enable the CONFIG router", "title": "Diracx Service Config Enabled", "type": "boolean"}, "DIRACX_SERVICE_HEALTH_ENABLED": {"default": true, "description": "Enable the HEALTH router", "title": "Diracx Service Health Enabled", "type": "boolean"}, "DIRACX_SERVICE_JOBS_ENABLED": {"default": true, "description": "Enable the JOBS router", "title": "Diracx Service Jobs Enabled", "type": "boolean"}}, "title": "EnabledServices", "type": "object"} ## AuthSettings @@ -186,10 +159,6 @@ Set of security properties available in this DIRAC installation. These properties define various authorization capabilities and are used for access control decisions. Defaults to all available security properties. -### `DIRACX_LEGACY_EXCHANGE_HASHED_API_KEY` - -The hashed API key for the legacy exchange endpoint. - ## SandboxStoreSettings Settings for the sandbox store. @@ -309,26 +278,3 @@ Whether to use an insecure gRPC connection for the OpenTelemetry collector. *Optional*, default value: `None` A JSON-encoded dictionary of headers to pass to the OpenTelemetry collector, e.g. {"tenant_id": "lhcbdiracx-cert"}. - -## ParentSettings - -It's hard to be a parent - -### `TATA_BUCKET_NAME` - -**Required** - -The child. - -## ChildSettings - -The actuall child impl - -### `YOYO_BIM` - -**Required** - -Name of the S3 bucket used for storing job sandboxes. - -This bucket will contain input and output sandbox files for DIRAC jobs. -The bucket must exist or auto_create_bucket must be enabled. diff --git a/docs/admin/reference/env-variables.md.j2 b/docs/admin/reference/env-variables.md.j2 index c5da98849..518fd9db2 100644 --- a/docs/admin/reference/env-variables.md.j2 +++ b/docs/admin/reference/env-variables.md.j2 @@ -20,9 +20,6 @@ Determines whether the jobs service is enabled. {{ render_class('AuthSettings') }} -### `DIRACX_LEGACY_EXCHANGE_HASHED_API_KEY` -The hashed API key for the legacy exchange endpoint. - {{ render_class('SandboxStoreSettings') }} ## Databases @@ -36,8 +33,3 @@ The URL for the SQL database ``. A JSON-encoded dictionary of connection keyword arguments for the OpenSearch database ``. {{ render_class('OTELSettings') }} - - - -{{ render_class('ParentSettings') }} -{{ render_class('ChildSettings') }} From 4896a4f6f8d1e8d28764a611133ea369b059f66c Mon Sep 17 00:00:00 2001 From: Christophe Haen Date: Mon, 1 Jun 2026 17:50:23 +0200 Subject: [PATCH 4/5] fix: tmp --- diracx-core/src/diracx/core/settings.py | 26 +++++++++----------- diracx-routers/src/diracx/routers/factory.py | 2 -- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/diracx-core/src/diracx/core/settings.py b/diracx-core/src/diracx/core/settings.py index 6f5a8a0d4..c650fc9a7 100644 --- a/diracx-core/src/diracx/core/settings.py +++ b/diracx-core/src/diracx/core/settings.py @@ -37,6 +37,7 @@ ) from pydantic_settings import BaseSettings, SettingsConfigDict +from .extensions import DiracEntryPoint, select_from_extension from .properties import SecurityProperty from .s3 import s3_bucket_exists @@ -372,8 +373,6 @@ def s3_client(self) -> S3Client: # FactorySettings = make_factory_settings(StaticFactorySettings) -from pydantic import Field - # Could come from code, YAML, DB, plugin system, etc. FIELD_SPECS = { "state_key": { @@ -396,11 +395,15 @@ def s3_client(self) -> S3Client: }, } -from .extensions import DiracEntryPoint, select_from_extension - def _build_factory_settings_model() -> type[ServiceSettingsBase]: + class _EnabledServicesBase(ServiceSettingsBase): + model_config = SettingsConfigDict( + frozen=True, + use_attribute_docstrings=True, + ) + enabled_services_field: dict[str, tuple[Any, Any]] = {} for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): @@ -415,15 +418,11 @@ def _build_factory_settings_model() -> type[ServiceSettingsBase]: ), ) - EnabledServices = create_model( + EnabledServices = create_model( # noqa: N806 "EnabledServices", __doc__="Enabled services", - __base__=ServiceSettingsBase, - __config__=SettingsConfigDict( - frozen=True, - use_attribute_docstrings=True, - ), - **enabled_services_field, + __base__=_EnabledServicesBase, + **cast(dict[str, Any], enabled_services_field), ) class _BaseFactorySettings(ServiceSettingsBase): @@ -438,11 +437,10 @@ class _BaseFactorySettings(ServiceSettingsBase): diracx_legacy_exchange_hashed_api_key: str = "" """The hashed API key for the legacy exchange endpoint. """ - enabled_services: EnabledServices = Field( default_factory=EnabledServices, # TODO fix the variable doc generation - description=str(EnabledServices.schema_json()), + description=str(cast(BaseSettings, EnabledServices).schema_json()), ) fields: dict[str, tuple[Any, Any]] = {} @@ -451,7 +449,7 @@ class _BaseFactorySettings(ServiceSettingsBase): "FactorySettings", __doc__=_BaseFactorySettings.__doc__, __base__=_BaseFactorySettings, - **fields, + **cast(dict[str, Any], fields), ) return new_mod diff --git a/diracx-routers/src/diracx/routers/factory.py b/diracx-routers/src/diracx/routers/factory.py index d93109721..22911bf9c 100644 --- a/diracx-routers/src/diracx/routers/factory.py +++ b/diracx-routers/src/diracx/routers/factory.py @@ -353,14 +353,12 @@ def create_app() -> DiracFastAPI: enabled_systems = set() settings_classes = set() factory_settings = FactorySettings() - print(f"CHRIS {factory_settings}") for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): enabled = getattr( factory_settings.enabled_services, entry_point.name, True, ) - print("CHRIS Found service %r: enabled=%s", entry_point, enabled) logger.debug("Found service %r: enabled=%s", entry_point, enabled) if not enabled: continue From aedbf8a6c004c8c80fb1de1e38079c569c9fb513 Mon Sep 17 00:00:00 2001 From: Christophe Haen Date: Mon, 1 Jun 2026 17:50:59 +0200 Subject: [PATCH 5/5] fix: tmp --- diracx-core/src/diracx/core/settings.py | 62 ------------------------- 1 file changed, 62 deletions(-) diff --git a/diracx-core/src/diracx/core/settings.py b/diracx-core/src/diracx/core/settings.py index c650fc9a7..40cf29294 100644 --- a/diracx-core/src/diracx/core/settings.py +++ b/diracx-core/src/diracx/core/settings.py @@ -362,40 +362,6 @@ def s3_client(self) -> S3Client: return self._client -# def make_factory_settings(model_cls: type[StaticFactorySettings]): -# new_fields = {} -# for var, val in os.environ.items(): -# if var.startswith("XDG_"): -# new_fields[var] = (str, val) -# return create_model("FactorySettings", __base__=model_cls, **new_fields) - - -# FactorySettings = make_factory_settings(StaticFactorySettings) - - -# Could come from code, YAML, DB, plugin system, etc. -FIELD_SPECS = { - "state_key": { - "type": str, - "default": ..., - "env": "DIRACX_SERVICE_AUTH_STATE_KEY", - "description": "Fernet key used to encrypt/decrypt OAuth2 state.", - }, - "token_issuer": { - "type": str, - "default": ..., - "env": "DIRACX_SERVICE_AUTH_TOKEN_ISSUER", - "description": "JWT issuer value ('iss' claim).", - }, - "access_token_expire_minutes": { - "type": int, - "default": 20, - "env": "DIRACX_SERVICE_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES", - "description": "Access token lifetime in minutes.", - }, -} - - def _build_factory_settings_model() -> type[ServiceSettingsBase]: class _EnabledServicesBase(ServiceSettingsBase): @@ -455,31 +421,3 @@ class _BaseFactorySettings(ServiceSettingsBase): FactorySettings = _build_factory_settings_model() - - -# class FactorySettings(ServiceSettingsBase): -# """Factory settings. - -# Settings which do not fit into dedicated classes, -# or are dynamically generated -# """ - -# diracx_legacy_exchange_hashed_api_key: str = "" - -# enabled_services: MutableMapping[str, bool] - - -# @model_validator(mode="before") -# @classmethod -# def check_enabled_services(cls, v): -# for entry_point in select_from_extension(group=DiracEntryPoint.SERVICES): - -# if "well-known" in entry_point.name: -# continue -# fields[f"diracx_service_{entry_point.name}_enabled"] = ( -# bool, -# Field( -# default=True, -# description=f"Enable the {entry_point.name.upper()} router", -# ), -# )