akinator/
error.rs

1use pyo3::{
2    prelude::*,
3    create_exception,
4    exceptions::{
5        PyException,
6        PyValueError,
7        PyRuntimeError,
8    }
9};
10
11use std::sync::PoisonError;
12use akinator_rs::error::Error as AkiError;
13
14
15macro_rules! create_exceptions {
16    ( $(( $name:ident, $doc:expr )),* $(,)* ) => {
17        $(
18            create_exception!(
19                akinator,
20                $name,
21                PyException,
22                $doc
23            );
24        )*
25    }
26}
27
28create_exceptions![
29    (CantGoBackAnyFurther, "Raised when the akinator is already on the 1st question / there are no more questions to go back on"),
30    (InvalidAnswer, "Raised when an invalid answer string is used when instantiating a Language enum from str"),
31    (InvalidLanguage, "Raised when an invalid language string is used when instantiating a Language enum from str"),
32    (ConnectionError, "Raised when we fail the connect to the akinator servers for whatever reason"),
33    (NoMoreQuestions, "Raised when there are no more questions the akinator can offer"),
34    (TimeoutError, "Raised when the akinator session timed out waiting for a response"),
35    (TechnicalError, "Raised when there is a technical internal error with the akinator servers"),
36    (ServersDown, "Raised when the akinator servers in the requested region are down"),
37];
38
39#[derive(Debug)]
40pub enum Error {
41    AkiError(AkiError),
42    PoisonError,
43}
44
45pub(crate) fn add_exceptions(py: Python<'_>, module: &PyModule) -> PyResult<()> {
46    module.add("CantGoBackAnyFurther", py.get_type::<CantGoBackAnyFurther>())?;
47    module.add("InvalidAnswer", py.get_type::<InvalidAnswer>())?;
48    module.add("InvalidLanguage", py.get_type::<InvalidLanguage>())?;
49    module.add("ConnectionError", py.get_type::<ConnectionError>())?;
50    module.add("NoMoreQuestions", py.get_type::<NoMoreQuestions>())?;
51    module.add("TimeoutError", py.get_type::<TimeoutError>())?;
52    module.add("TechnicalError", py.get_type::<TechnicalError>())?;
53    module.add("ServersDown", py.get_type::<ServersDown>())?;
54
55    Ok(())
56}
57
58impl From<Error> for PyErr {
59    fn from(error: Error) -> Self {
60        match error {
61            Error::AkiError(err) => match err {
62                AkiError::CantGoBackAnyFurther =>
63                    CantGoBackAnyFurther::new_err("Cannot go back any more questions, we are already on the 0th question"),
64                AkiError::InvalidAnswer =>
65                    InvalidAnswer::new_err("Invalid answer string"),
66                AkiError::InvalidLanguage =>
67                    InvalidLanguage::new_err("Invalid language string"),
68                AkiError::ConnectionError =>
69                    ConnectionError::new_err("Failed to connect to akinator servers"),
70                AkiError::NoMoreQuestions =>
71                    NoMoreQuestions::new_err("The akinator has no more questions to ask"),
72                AkiError::TimeoutError =>
73                    TimeoutError::new_err("The akinator session timed out"),
74                AkiError::TechnicalError =>
75                    TechnicalError::new_err("An unknown technical error occured within the akinator servers"),
76                AkiError::ServersDown =>
77                    ServersDown::new_err("The requested akinator servers are down"),
78                AkiError::NoDataFound  | AkiError::UpdateInfoError(_) |
79                AkiError::TimeError(_) | AkiError::RequestError(_) =>
80                    PyRuntimeError::new_err(err.to_string()),
81                AkiError::JsonParseError(_) =>
82                    PyValueError::new_err(err.to_string()),
83            },
84            Error::PoisonError =>
85                PyRuntimeError::new_err("Failed to read attribute values"),
86        }
87    }
88}
89
90impl<T> From<PoisonError<T>> for Error {
91    fn from(_error: PoisonError<T>) -> Self {
92        Self::PoisonError
93    }
94}
95
96impl From<AkiError> for Error {
97    fn from(error: AkiError) -> Self {
98        Self::AkiError(error)
99    }
100}