flip.core.standard ================== .. py:module:: flip.core.standard .. autoapi-nested-parse:: Standard FLIP Implementation. This module contains the production and development implementations of FLIP for the standard, evaluation, and fed_opt job types. Attributes ---------- .. autoapisummary:: flip.core.standard._HUB_POST_TIMEOUT_SECONDS Classes ------- .. autoapisummary:: flip.core.standard.FLIPStandardProd flip.core.standard.FLIPStandardDev Functions --------- .. autoapisummary:: flip.core.standard._trust_internal_headers flip.core.standard._join_url flip.core.standard._hub_internal_headers Module Contents --------------- .. py:data:: _HUB_POST_TIMEOUT_SECONDS :type: tuple[int, int] :value: (5, 30) .. py:function:: _trust_internal_headers() -> dict[str, str] Return the auth header sent on every trust-internal call. Used on outbound calls to imaging-api and data-access-api. The receiver (in the FLIP repo) compares the value with a constant-time compare against its own copy of the same per-trust key. :returns: Single-entry dict mapping the configured header name to the trust-internal service key. :rtype: dict[str, str] .. py:function:: _join_url(base: object, path: str) -> str Join a base URL with a path, tolerating a trailing slash on the base. Pydantic v2 serializes a host-only ``HttpUrl`` with a trailing slash (e.g. ``http://data-access-api:8000/``), so naive f-string concatenation with ``/cohort/dataframe`` yields a double slash (``//cohort/dataframe``) that Starlette does not route — producing a spurious ``404 Not Found``. Normalising the base before joining keeps every trust-internal and hub-internal call working regardless of whether the configured URL carries a trailing slash. See FLIP#652. :param base: The base URL (``str`` or pydantic ``HttpUrl``). :param path: The path to append (a leading slash is optional). :returns: ``/``. :rtype: str .. py:function:: _hub_internal_headers() -> dict[str, str] Return the auth header sent on every hub-internal call. Used by fl-server on the Central Hub for outbound calls to flip-api (update_status, send_metrics, send_handled_exception). The receiver (flip-api) compares the value with a constant-time compare against its own copy. Distinct boundary from the trust-internal key — a leak in one trust never affects this hub-side path and vice versa. :returns: Single-entry dict mapping the configured header name to the hub internal-service key. :rtype: dict[str, str] .. py:class:: FLIPStandardProd Bases: :py:obj:`flip.core.base.FLIPBase` Production implementation of FLIP for standard job types. Method usage by FL role: **Server-only** (fl-server on Central Hub → calls flip-api): - ``update_status()`` — update model training status - ``send_metrics()`` — forward per-client training/evaluation metrics - ``send_handled_exception()`` — forward client exception logs - ``upload_results_to_s3()`` — upload trained model to S3 **Client-only** (fl-client on trust side → calls local trust APIs): - ``get_dataframe()`` — fetch cohort data from data-access-api - ``get_images()`` — download images from imaging-api - ``download_data_from_s3()`` — download federated data from S3 .. py:attribute:: _name :value: 'FLIPStandardProd' .. py:attribute:: logger .. py:method:: get_dataframe(project_id: str, query: str) -> pandas.DataFrame Retrieves the dataframe from the trust OMOP using the SQL query. Calls the FLIP data-access-api. :param project_id: Project identifier :type project_id: str :param query: SQL query :type query: str :returns: Dataframe containing the resulting accession ids and additional data. :rtype: pd.DataFrame .. py:method:: get_by_accession_number(project_id: str, accession_id: str, resource_type: flip.constants.flip_constants.ResourceType | list[flip.constants.flip_constants.ResourceType] = ResourceType.NIFTI) -> pathlib.Path Calls the imaging-service to return a filepath that contains images downloaded from XNAT based on the accession number. :param project_id: The ID of the project. :type project_id: str :param accession_id: The accession ID of the imaging study. :type accession_id: str :param resource_type: The type of resource to download. Defaults to :type resource_type: ResourceType | list[ResourceType] :param ResourceType.NIFTI.: :returns: Path to the downloaded data for that accession_id. :rtype: Path .. py:method:: add_resource(project_id: str, accession_id: str, scan_id: str, resource_id: str, files: list[str]) -> None Calls the imaging-service to upload image(s) to XNAT based on the accession number, scan ID, and resource ID. :param project_id: Unique project identifier :type project_id: str :param accession_id: Accession ID to upload the resource to :type accession_id: str :param scan_id: ID of the scan to upload :type scan_id: str :param resource_id: Type of resource that is being uploaded (e.g. NIFTI) :type resource_id: str :param files: List of files to upload :type files: list[str] .. py:method:: update_status(model_id: str, new_model_status: flip.constants.flip_constants.ModelStatus) -> None Updates the model status on the Central Hub. :param model_id: Unique model identifier. :type model_id: str :param new_model_status: New model status value. :type new_model_status: ModelStatus .. py:method:: send_metrics(client_name: str, model_id: str, label: str, value: float, global_round: int, x_value: float | None = None, x_label: str | None = None) -> None Sends a metric value to the Central Hub. :param client_name: The name of the client. :type client_name: str :param model_id: The ID of the model. :type model_id: str :param label: The label of the metric. :type label: str :param value: The value of the metric. :type value: float :param global_round: Provenance — the FL global round the metric is reported in (never the plot coordinate). :type global_round: int :param x_value: The x-coordinate the metric is plotted at; ``None`` plots it at ``global_round`` (the schema backfills it). :type x_value: float | None :param x_label: Label naming the x-axis; falls back to "Global Rounds" when not given. :type x_label: str | None .. py:method:: send_handled_exception(formatted_exception: str, client_name: str | None, model_id: str) -> None Sends a handled exception to the Central Hub. :param formatted_exception: The formatted exception message. :type formatted_exception: str :param client_name: The name of the client that raised the exception. None when the client cannot be identified (e.g. a Flower reply that crashed before its first healthy response), in which case the hub records the exception model-level rather than rejecting it. :type client_name: str | None :param model_id: The ID of the model associated with the exception. :type model_id: str .. py:method:: send_event(model_id: str, event_type: flip.schemas.FLLogEvent, global_round: int, client_name: str | None = None, details: dict[str, Any] | None = None, success: bool = True) -> None Sends a typed round-progress event to the Central Hub. Facts only — the hub composes display text at serve time. Best-effort: a failed post and a payload that fails validation are logged and never break training. Only an invalid ``model_id`` raises — a deliberate precondition, matching ``send_handled_exception``. :param model_id: The ID of the model the event belongs to. :type model_id: str :param event_type: Which round event this is. :type event_type: FLLogEvent :param global_round: The 1-based federated round. :type global_round: int :param client_name: FL client identity for trust-attributed events; None for hub-attributed ones. :type client_name: str | None :param details: Event-specific facts. :type details: dict[str, Any] | None :param success: Whether the event marks a healthy step. :type success: bool .. py:method:: upload_results_to_s3(results_folder: pathlib.Path, model_id: str) -> None Uploads results to S3 bucket in standard mode. :param results_folder: The folder containing results to upload :type results_folder: Path :param model_id: The model UUID for which results are being uploaded :type model_id: str .. py:method:: cleanup(path: pathlib.Path) -> None Cleans up local files by deleting the specified path. .. py:class:: FLIPStandardDev Bases: :py:obj:`flip.core.base.FLIPBase` Development implementation of FLIP for standard job types. .. py:attribute:: _name :value: 'FLIPStandardDev' .. py:attribute:: logger .. py:method:: get_dataframe(project_id: str, query: str) -> pandas.DataFrame Retrieves the dataframe from the specified CSV path. :param project_id: Project identifier (validated but not used in dev) :type project_id: str :param query: SQL query (validated but not used in dev) :type query: str :returns: Dataframe from the DEV_DATAFRAME CSV file. :rtype: pd.DataFrame .. py:method:: get_by_accession_number(project_id: str, accession_id: str, resource_type: flip.constants.flip_constants.ResourceType | list[flip.constants.flip_constants.ResourceType] = ResourceType.NIFTI) -> pathlib.Path Returns the path to the image directory for a specific accession ID. :param project_id: Project identifier :type project_id: str :param accession_id: Accession ID to retrieve :type accession_id: str :param resource_type: Type of imaging resource (not used in dev) :type resource_type: ResourceType | list[ResourceType] :returns: Path to the accession_id folder within the images folder. :rtype: Path .. py:method:: add_resource(project_id: str, accession_id: str, scan_id: str, resource_id: str, files: list[str]) -> None Log only in dev mode - no actual upload. .. py:method:: update_status(model_id: str, new_model_status: flip.constants.flip_constants.ModelStatus) -> None Log only in dev mode - no actual status update. .. py:method:: send_metrics(client_name: str, model_id: str, label: str, value: float, global_round: int, x_value: float | None = None, x_label: str | None = None) -> None Log only in dev mode - no actual metrics sending. .. py:method:: send_handled_exception(formatted_exception: str, client_name: str | None, model_id: str) -> None Log only in dev mode - no actual exception sending. .. py:method:: send_event(model_id: str, event_type: flip.schemas.FLLogEvent, global_round: int, client_name: str | None = None, details: dict[str, Any] | None = None, success: bool = True) -> None Log only in dev mode - no actual event sending. .. py:method:: upload_results_to_s3(results_folder: pathlib.Path, model_id: str) -> None Log only in dev mode - no actual upload. .. py:method:: cleanup(path: pathlib.Path) -> None Log only in dev mode - no actual deletion of any files.