# Path: esteid/exceptions.py
# class ActionInProgress(EsteidError):
#     """
#     Raised when a request to the service is still in pending status,
#     or when it is necessary to move on to the next step while passing some data on to the user
#     (like after successful auth, we initiate a signing request and display verification code)
#     """
# 
#     status = HTTPStatus.ACCEPTED
# 
#     default_message = _("Operation is in progress.")
# 
#     def __init__(self, message=None, data: dict = None):
#         super().__init__(message)
#         self.data = data or {}
# 
# class BadRequest(EsteidError):
#     pass
# 
# class EsteidError(Exception):
#     """
#     A generic Esteid error.
# 
#     Provides an interface for displaying a translated message to the user.
# 
#     Note: by default, any message passed as a first positional argument is ignored, because it only
#     serves for better logging. The User Interface should display a verbose error message
#     in case of a user-caused error so that user can take action accordingly. Errors caused by service malfunction
#     are likely not informative to a user without malicious intent.
# 
#     If the default message contains {key} placeholders, the exception is supposed to be
#     raised with kwargs, these will be passed on to <translated default message>.format(**kwargs).
#     """
# 
#     status = HTTPStatus.INTERNAL_SERVER_ERROR
# 
#     default_message = _("Something went wrong")
# 
#     kwargs: dict
# 
#     def __init__(self, message=None, **kwargs):
#         super().__init__(message)
#         self.kwargs = kwargs
# 
#     def get_message(self):
#         return str(self.default_message).format(**self.kwargs)
# 
#     def get_user_error(self):
#         return {
#             "error": self.__class__.__name__,  # error code that can be bound to JS translations
#             # TODO review errors and add translations
#             "message": self.get_message(),
#         }
# 
# class InvalidCredentials(EsteidError):
#     pass
# 
# class OfflineError(UpstreamServiceError):
#     default_message = _("The {service} service is unavailable at the moment. Please try again later.")
# 
# class SessionDoesNotExist(EsteidError):
#     pass
# 
# class UnsupportedClientImplementation(UpstreamServiceError):
#     pass
# 
# class UpstreamServiceError(EsteidError):
#     """A failure reported by upstream service which is not caused by user.
# 
#     Takes a `service` kwarg, e.g. Mobile ID / Smart ID
#     """
# 
#     status = HTTPStatus.SERVICE_UNAVAILABLE
# 
#     default_message = _("The {service} service reported a failure.")
# 
#     def __init__(self, message=None, *, service, **kwargs):
#         super().__init__(message)
#         self.kwargs = {"service": service, **kwargs}


import logging
import requests
from typing import Union
from uuid import UUID
from .exceptions import (
    ActionInProgress,
    BadRequest,
    EsteidError,
    InvalidCredentials,
    OfflineError,
    SessionDoesNotExist,
    UnsupportedClientImplementation,
    UpstreamServiceError,
)
            "relyingPartyName": self.rp_name,
        }

    def api_url(self, endpoint):
        return f"{self.api_root}{endpoint}"

    def invoke(self, endpoint, method="GET", query=None, data=None):
        query = query or {}

        if method != "GET":
            data = self.rp_params(data or {})

        req = requests.Request(
            method=method,
            url=self.api_url(endpoint),
            params=query,
            json=data,
            headers=self._REQUEST_HEADERS,
        )
        prepared = req.prepare()

        try:
            # Attempt to fulfill the request
            response = self.session.send(prepared)

            # ensure we don't mask errors
            response.raise_for_status()

        except (requests.ConnectionError, requests.Timeout, ConnectionError) as e:
            logger.exception("Failed to get a response from %s.", req.url)

# Path: esteid/exceptions.py
# class ActionInProgress(EsteidError):
#     """
#     Raised when a request to the service is still in pending status,
#     or when it is necessary to move on to the next step while passing some data on to the user
#     (like after successful auth, we initiate a signing request and display verification code)
#     """
# 
#     status = HTTPStatus.ACCEPTED
# 
#     default_message = _("Operation is in progress.")
# 
#     def __init__(self, message=None, data: dict = None):
#         super().__init__(message)
#         self.data = data or {}
# 
# class BadRequest(EsteidError):
#     pass
# 
# class EsteidError(Exception):
#     """
#     A generic Esteid error.
# 
#     Provides an interface for displaying a translated message to the user.
# 
#     Note: by default, any message passed as a first positional argument is ignored, because it only
#     serves for better logging. The User Interface should display a verbose error message
#     in case of a user-caused error so that user can take action accordingly. Errors caused by service malfunction
#     are likely not informative to a user without malicious intent.
# 
#     If the default message contains {key} placeholders, the exception is supposed to be
#     raised with kwargs, these will be passed on to <translated default message>.format(**kwargs).
#     """
# 
#     status = HTTPStatus.INTERNAL_SERVER_ERROR
# 
#     default_message = _("Something went wrong")
# 
#     kwargs: dict
# 
#     def __init__(self, message=None, **kwargs):
#         super().__init__(message)
#         self.kwargs = kwargs
# 
#     def get_message(self):
#         return str(self.default_message).format(**self.kwargs)
# 
#     def get_user_error(self):
#         return {
#             "error": self.__class__.__name__,  # error code that can be bound to JS translations
#             # TODO review errors and add translations
#             "message": self.get_message(),
#         }
# 
# class InvalidCredentials(EsteidError):
#     pass
# 
# class OfflineError(UpstreamServiceError):
#     default_message = _("The {service} service is unavailable at the moment. Please try again later.")
# 
# class SessionDoesNotExist(EsteidError):
#     pass
# 
# class UnsupportedClientImplementation(UpstreamServiceError):
#     pass
# 
# class UpstreamServiceError(EsteidError):
#     """A failure reported by upstream service which is not caused by user.
# 
#     Takes a `service` kwarg, e.g. Mobile ID / Smart ID
#     """
# 
#     status = HTTPStatus.SERVICE_UNAVAILABLE
# 
#     default_message = _("The {service} service reported a failure.")
# 
#     def __init__(self, message=None, *, service, **kwargs):
#         super().__init__(message)
#         self.kwargs = {"service": service, **kwargs}


# Path: esteid/base_service.py
import logging
import requests
from typing import Union
from uuid import UUID
from .exceptions import (
    ActionInProgress,
    BadRequest,
    EsteidError,
    InvalidCredentials,
    OfflineError,
    SessionDoesNotExist,
    UnsupportedClientImplementation,
    UpstreamServiceError,
)

            "relyingPartyName": self.rp_name,
        }

    def api_url(self, endpoint):
        return f"{self.api_root}{endpoint}"

    def invoke(self, endpoint, method="GET", query=None, data=None):
        query = query or {}

        if method != "GET":
            data = self.rp_params(data or {})

        req = requests.Request(
            method=method,
            url=self.api_url(endpoint),
            params=query,
            json=data,
            headers=self._REQUEST_HEADERS,
        )
        prepared = req.prepare()

        try:
            # Attempt to fulfill the request
            response = self.session.send(prepared)

            # ensure we don't mask errors
            response.raise_for_status()

        except (requests.ConnectionError, requests.Timeout, ConnectionError) as e:
            logger.exception("Failed to get a response from %s.", req.url)

            raise OfflineError(service=self.NAME) from e