Source code for akvo.iati.iati_validator

# -*- coding: utf-8 -*-

# Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.

import requests
from typing import Dict, Any, Optional
from dataclasses import dataclass

IATI_VALIDATOR_URL = "https://api.iatistandard.org/validator/validate?group=true&details=false"


[docs]class IATIValidatorException(Exception): pass
[docs]class IATIValidatorTimeoutException(IATIValidatorException): pass
[docs]class IATIValidatorResponseException(IATIValidatorException): def __init__(self, status_code: int, content: str): self.status_code = status_code self.content = content super().__init__(f"Error response {status_code=}, {content=}")
[docs]@dataclass(frozen=True) class IATIValidationResult: error_count: int warning_count: int data: Dict[str, Any]
[docs] @classmethod def make(cls, data: Dict[str, Any]): return cls( error_count=data['summary']['error'] + data['summary']['critical'], warning_count=data['summary']['warning'], data=data, )
[docs]class IATIValidatorAPI: ''' An abstraction class for IATI validator API service https://developer.iatistandard.org/api-details#api=iati-validator-v2&operation=post-pub-validate-post ''' def __init__(self, subscription_key: str, timeout: Optional[float] = None): self.subscription_key = subscription_key self.timeout = timeout
[docs] def validate(self, xml_doc: bytes) -> IATIValidationResult: headers = { 'Content-Type': 'application/xml', 'Accept': 'application/json', 'Cache-Control': 'no-cache', 'Ocp-Apim-Subscription-Key': self.subscription_key, } try: response = requests.post(IATI_VALIDATOR_URL, data=xml_doc, headers=headers, timeout=self.timeout) except requests.Timeout as te: # Caller could retry when connection timeout raise IATIValidatorTimeoutException() from te except requests.RequestException as re: # Could be caused by bad configuration raise IATIValidatorException() from re if response.status_code not in [200, 422]: # More likely caused by bad configuration raise IATIValidatorResponseException(response.status_code, str(response.content)) return IATIValidationResult.make(response.json())