Source code for fgen_runtime.exceptions
"""
Exception classes for wrapper-specific errors
"""
from __future__ import annotations
from typing import Any, Callable, Optional
from numpy.typing import NDArray
[docs]class WrapperError(ValueError):
"""
Base exception for errors that arise from wrapper
"""
[docs]class WrapperErrorUnknownCause(WrapperError):
"""
Raised when there is an error with the wrapper, but we have nothing to help debug
"""
def __init__(self, msg: str):
suffix = "Underlying reason unknown"
error_msg = f"{msg}. {suffix}."
super().__init__(error_msg)
[docs]class InitialisationError(WrapperError):
"""
Raised when the wrapper around the Fortran module hasn't been initialised yet
"""
def __init__(self, instance: Any, method: Optional[Callable[..., Any]] = None):
if method:
error_msg = f"{instance} must be initialised before {method} is called"
else:
error_msg = f"instance ({instance:r}) is not initialized yet"
super().__init__(error_msg)
[docs]class CompiledExtensionNotFoundError(ImportError):
"""
Raised when a compiled extension can't be import i.e. found
"""
def __init__(self, compiled_extension_name: str):
error_msg = f"Could not find compiled extension {compiled_extension_name!r}"
super().__init__(error_msg)
[docs]class BadPointerError(ValueError):
"""
Raised when a pointer has a value we know is wrong
"""
def __init__(self, pointer_value: Any, extra_info: str):
error_msg = (
f"The array pointer value is wrong ({pointer_value=}). "
f"{extra_info}. "
"Further underlying reason for the error is unknown."
)
super().__init__(error_msg)
[docs]class PointerArrayConversionError(ValueError):
"""
Raised when we know a pointer has been incorrectly converted to an array
"""
def __init__(
self,
array: NDArray[Any],
ptr: int,
expected_array_interface_data: tuple[int, bool],
):
error_msg = (
"The array pointer has been incorrectly converted to an numpy array. "
f"We received {array.__array_interface__['data']=}. "
f"The expected value is {expected_array_interface_data}. "
f"Full context: {ptr=} {array.__array_interface__=}"
)
super().__init__(error_msg)
[docs]class UnallocatedMemoryError(ValueError):
"""
Raised when we try to allocate memory that has not yet been allocated
We can't always catch this error, but this is what we raise when we can.
"""
def __init__(self, variable_name: str):
error_msg = (
f"The memory required to access ``{variable_name}`` is unallocated. "
"You must allocate it before trying to access its value. "
"Unfortunately, we cannot provide more information "
"about why this memory is not yet allocated."
)
super().__init__(error_msg)
[docs]class RelativePythonModuleNotFoundError(ImportError):
"""
Raised when a Python import configured by fgen fails
"""
def __init__(
self,
requesting_python_module: str,
requested: str,
requested_from_python_module: str,
):
"""
Initialise
Parameters
----------
requesting_python_module
The Python module in which the ``import`` statement appears
requested
The thing that is being requested e.g. ``HelpfulType``
requested_from_python_module
The Python module from which ``requested`` is being imported e.g.
``source_module`` in
``from source_module import HelpfulType``
"""
error_msg = (
"There is something wrong with your fgen configuration for "
f"{requesting_python_module!r}. "
"Somewhere (likely in the `.yaml` file which is used to generate "
f"{requesting_python_module!r} with fgen) you are specifying that "
f"{requested!r} can be imported from "
f"{requested_from_python_module!r}, but this is failing."
)
super().__init__(error_msg)
[docs]class SolveError(ValueError):
"""
Exception raised when an solver can't solve
For example, because the integration has a runaway effect in it
"""