Source code for imednet.core.parsing

"""Centralized model parsing strategy for the iMednet SDK.

This module provides a consistent approach to parsing API responses into
Pydantic models, eliminating duplicated parsing logic across endpoints.
"""

from __future__ import annotations

from collections.abc import Callable
from typing import Any, TypeVar, cast

from pydantic import BaseModel

__all__ = ["ModelParser", "get_model_parser"]


T = TypeVar("T", bound=BaseModel)


[docs]def get_model_parser(model: type[T]) -> Callable[[Any], T]: """Return the appropriate parsing function for a model. This function implements a strategy pattern for model parsing: 1. If the model has a custom `from_json` classmethod, use it 2. Otherwise, fall back to Pydantic's `model_validate` Args: model: The model class to get a parser for Returns: A callable that takes raw data and returns a model instance Example: >>> from imednet.models.studies import Study >>> from imednet.core.parsing import get_model_parser >>> parser = get_model_parser(Study) >>> study = parser({"study_name": "Test", "study_key": "123"}) """ # Check for custom from_json method if hasattr(model, "from_json") and callable(getattr(model, "from_json")): # noqa: B009 return cast(Callable[[Any], T], getattr(model, "from_json")) # noqa: B009 # Fall back to Pydantic's model_validate return cast(Callable[[Any], T], model.model_validate)
[docs]class ModelParser: """Stateful parser that can be configured with a specific model. This class provides a convenient interface for repeated parsing operations with the same model type. Example: >>> from imednet.models.studies import Study >>> from imednet.core.parsing import ModelParser >>> parser = ModelParser(Study) >>> api_response = [{"study_name": "Test1", "study_key": "1"}, {"study_name": "Test2", "study_key": "2"}] >>> studies = [parser.parse(data) for data in api_response] >>> len(studies) 2 """
[docs] def __init__(self, model: type[BaseModel]) -> None: """Initialize parser with a model type. Args: model: The model class to parse data into """ self.model = model self._parse_func: Callable[[Any], BaseModel] = get_model_parser(model)
[docs] def parse(self, data: Any) -> BaseModel: """Parse raw data into a model instance. Args: data: Raw data (usually dict) to parse Returns: Parsed model instance """ return self._parse_func(data)
[docs] def parse_many(self, items: list[Any]) -> list[BaseModel]: """Parse a list of raw data items into model instances. Args: items: List of raw data items Returns: List of parsed model instances """ return [self._parse_func(item) for item in items]