Source code for pywincffi.exceptions
"""
Exceptions
==========
Custom exceptions that ``pywincffi`` can throw.
"""
import warnings
from cffi.api import CDefError
[docs]class PyWinCFFIError(Exception):
"""
The base class for all custom exceptions that pywincffi can throw.
"""
[docs]class InputError(PyWinCFFIError):
"""
A subclass of :class:`PyWinCFFIError` that's raised when invalid input
is provided to a function. Because we're passing inputs to C we have
to be sure that the input(s) being provided are what we're expecting so
we fail early and provide better error messages.
:param str name:
The name of the parameter being checked.
:param value:
The value of the parameter being checked.
:keyword allowed_types:
The expected type(s). If provided then the exception's message will
be tailored to provide information about ``value``'s type and the
possible input types.
:keyword allowed_values:
The expected value(s). If provided then the exception's message will
be tailored to provide information about what value(s) were allowed
for ``value``.
:keyword ffi:
If ``value`` is a C object, ``ffi`` is provided and ``allowed_types``
is provided as well then the provided ``ffi`` instance will be used
to provide additional context.
:keyword str message:
A custom error message. This will override the default error messages
which :class:`InputError` would normally generate. This can be
helpful if there is a problem with a given input parameter to a
function but it's unrelated to the type of input.
"""
def __init__( # pylint: disable=too-many-arguments
self, name, value,
allowed_types=None, allowed_values=None, ffi=None, message=None):
if allowed_types is not None and allowed_values is not None:
raise ValueError(
"Please provide either `allowed_types` or `allowed_values`")
if (allowed_types is None and allowed_values is None and
message is None):
raise ValueError(
"Please provide `allowed_types`, `allowed_values` or "
"`message`")
self.name = name
self.value = value
self.allowed_types = allowed_types
self.allowed_values = allowed_values
self.message = message
if self.message is None and self.allowed_types is not None:
if ffi is None:
typeof = repr(type(value))
else:
try:
ffi_exceptions = (TypeError, CDefError, ffi.error)
except AttributeError: # pragma: no cover
ffi_exceptions = (TypeError, CDefError)
try:
typeof = ffi.typeof(value)
except ffi_exceptions:
typeof = repr(type(value))
else:
typeof = "{classname}(kind={kind}, cname={cname})".format(
classname=value.__class__.__name__,
kind=repr(typeof.kind), cname=repr(typeof.cname))
self.message = \
"Expected type(s) {expected} for {name}. Type of {name} " \
"is {typeof}.".format(
expected=repr(allowed_types), name=repr(name),
typeof=typeof)
elif self.message is None and self.allowed_values is not None:
self.message = \
"Expected the value of {name} to be in {values}. Value of " \
"{name} is {value}.".format(
name=repr(name), values=allowed_values, value=repr(value))
super(InputError, self).__init__(self.message)
[docs]class WindowsAPIError(PyWinCFFIError):
"""
A subclass of :class:`PyWinCFFIError` that's raised when there was a
problem calling a Windows API function.
:param str function:
The Windows API function being called when the error was raised.
:param str error:
A string representation of the error message.
:param int errno:
An integer representing the error. This usually represents
a constant which Windows has produced in response to a problem.
:keyword int return_code:
If the return value of a function has been checked the resulting
code will be set as this value.
:keyword int expected_return_code:
The value we expected to receive for ``code``.
"""
# pylint: disable=too-many-arguments
def __init__(self, function, error, errno,
return_code=None, expected_return_code=None):
self.function = function
self.error = error
self.errno = errno
self.return_code = return_code
self.expected_return_code = expected_return_code
if return_code is None and expected_return_code is None:
self.message = \
"Error when calling {0}. Message from Windows API was " \
"{1!r} (errno: {2}).".format(self.function, self.error, errno)
elif return_code is not None and expected_return_code is not None:
self.message = (
"Error when calling {0}. Expected to receive {1!r} from {2} "
"but got {3!r} instead. (error: {4!r})".format(
self.function, self.return_code, self.function,
self.expected_return_code, self.error
)
)
# Generic implementation which we should probably handle
# better so throw a warning.
else: # pragma: no cover
warnings.warn(Warning(), "Pre-formatting not available")
self.message = (
"Error when calling {0}. (error: {1}, errno: {2}, "
"return_code: {3!r}, expected_return_code: {4!r})".format(
self.function, self.error, self.errno, self.return_code,
self.expected_return_code
)
)
super(WindowsAPIError, self).__init__(self.message)
def __repr__(self):
return (
"{0}({1!r}, {2!r}, {3!r}, return_code={4!r}, "
"expected_return_code={5!r})".format(
self.__class__.__name__, self.function, self.error,
self.errno, self.return_code, self.expected_return_code))
[docs]class InternalError(PyWinCFFIError):
"""
Raised if we encounter an internal error. Most likely this is an
indication of a bug in pywincffi but it could also be a problem caused by
an unexpected use case.
"""
[docs]class PyWinCFFINotImplementedError(InternalError):
"""
Raised if we encounter a situation where we can't figure out what
to do. The message for this error should contain all the information
necessary to implement a future work around.
"""
[docs]class ResourceNotFoundError(InternalError):
"""Raised when we fail to locate a specific resource"""
[docs]class ConfigurationError(InternalError):
"""Raised when there was a problem with the configuration file"""