# -*- coding: utf-8 -*-
# Copyright (C) 2016, Maximilian Köhl <mail@koehlma.de>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License version 3 as published by
# the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function, unicode_literals, division, absolute_import
import errno
import io
import socket
from . import common
from .library import ffi, lib
[docs]class StatusCodes(common.Enumeration):
"""
Status codes enumeration. Status codes are instances of this class
and — beside SUCCESS — vary across platforms. Status codes other
than SUCCESS are linked with a corresponding exception.
"""
SUCCESS = 0
"""
Success — no error occoured.
:type: uv.StatusCodes
"""
E2BIG = lib.UV_E2BIG
"""
Argument list too long.
:type: uv.StatusCodes
"""
EACCES = lib.UV_EACCES
"""
Permission denied.
:type: uv.StatusCodes
"""
EADDRINUSE = lib.UV_EADDRINUSE
"""
Address already in use.
:type: uv.StatusCodes
"""
EADDRNOTAVAIL = lib.UV_EADDRNOTAVAIL
"""
Address not available.
:type: uv.StatusCodes
"""
EAFNOSUPPORT = lib.UV_EAFNOSUPPORT
"""
Address family not supported.
:type: uv.StatusCodes
"""
EAGAIN = lib.UV_EAGAIN
"""
Resource temporarily unavailable.
:type: uv.StatusCodes
"""
EAI_ADDRFAMILY = lib.UV_EAI_ADDRFAMILY
"""
Address family not supported.
:type: uv.StatusCodes
"""
EAI_AGAIN = lib.UV_EAI_AGAIN
"""
Temporary failure.
:type: uv.StatusCodes
"""
EAI_BADFLAGS = lib.UV_EAI_BADFLAGS
"""
Bad address flags value.
:type: uv.StatusCodes
"""
EAI_BADHINTS = lib.UV_EAI_BADHINTS
"""
Invalid value for hints.
:type: uv.StatusCodes
"""
EAI_CANCELED = lib.UV_EAI_CANCELED
"""
Request canceled.
:type: uv.StatusCodes
"""
EAI_FAIL = lib.UV_EAI_FAIL
"""
Permanent failure.
:type: uv.StatusCodes
"""
EAI_FAMILY = lib.UV_EAI_FAMILY
"""
Address family not supported.
:type: uv.StatusCodes
"""
EAI_MEMORY = lib.UV_EAI_MEMORY
"""
Out of memory.
:type: uv.StatusCodes
"""
EAI_NODATA = lib.UV_EAI_NODATA
"""
No address.
:type: uv.StatusCodes
"""
EAI_NONAME = lib.UV_EAI_NONAME
"""
Unknown node or service.
:type: uv.StatusCodes
"""
EAI_OVERFLOW = lib.UV_EAI_OVERFLOW
"""
Argument buffer overflow.
:type: uv.StatusCodes
"""
EAI_PROTOCOL = lib.UV_EAI_PROTOCOL
"""
Resolved protocol is unknown.
:type: uv.StatusCodes
"""
EAI_SERVICE = lib.UV_EAI_SERVICE
"""
Service not available for socket type.
:type: uv.StatusCodes
"""
EAI_SOCKTYPE = lib.UV_EAI_SOCKTYPE
"""
Socket type not supported.
:type: uv.StatusCodes
"""
EALREADY = lib.UV_EALREADY
"""
Connection already in progress.
:type: uv.StatusCodes
"""
EBADF = lib.UV_EBADF
"""
Bad file descriptor.
:type: uv.StatusCodes
"""
EBUSY = lib.UV_EBUSY
"""
Resource busy or locked.
:type: uv.StatusCodes
"""
ECANCELED = lib.UV_ECANCELED
"""
Operation canceled.
:type: uv.StatusCodes
"""
ECHARSET = lib.UV_ECHARSET
"""
Invalid Unicode character.
:type: uv.StatusCodes
"""
ECONNABORTED = lib.UV_ECONNABORTED
"""
Software caused connection abort.
:type: uv.StatusCodes
"""
ECONNREFUSED = lib.UV_ECONNREFUSED
"""
Connection refused.
:type: uv.StatusCodes
"""
ECONNRESET = lib.UV_ECONNRESET
"""
Connection reset by peer.
:type: uv.StatusCodes
"""
EDESTADDRREQ = lib.UV_EDESTADDRREQ
"""
Destination address required.
:type: uv.StatusCodes
"""
EEXIST = lib.UV_EEXIST
"""
File already exists.
:type: uv.StatusCodes
"""
EFAULT = lib.UV_EFAULT
"""
Bad address in system call argument.
:type: uv.StatusCodes
"""
EFBIG = lib.UV_EFBIG
"""
File too large.
:type: uv.StatusCodes
"""
EHOSTUNREACH = lib.UV_EHOSTUNREACH
"""
Host is unreachable.
:type: uv.StatusCodes
"""
EINTR = lib.UV_EINTR
"""
Interrupted system call.
:type: uv.StatusCodes
"""
EINVAL = lib.UV_EINVAL
"""
Invalid argument.
:type: uv.StatusCodes
"""
EIO = lib.UV_EIO
"""
IO error.
:type: uv.StatusCodes
"""
EISCONN = lib.UV_EISCONN
"""
Socket is already connected.
:type: uv.StatusCodes
"""
EISDIR = lib.UV_EISDIR
"""
Illegal operation on a directory.
:type: uv.StatusCodes
"""
ELOOP = lib.UV_ELOOP
"""
Too many symbolic links encountered.
:type: uv.StatusCodes
"""
EMFILE = lib.UV_EMFILE
"""
Too many open files.
:type: uv.StatusCodes
"""
EMSGSIZE = lib.UV_EMSGSIZE
"""
Message too long.
:type: uv.StatusCodes
"""
ENAMETOOLONG = lib.UV_ENAMETOOLONG
"""
Name too long.
:type: uv.StatusCodes
"""
ENETDOWN = lib.UV_ENETDOWN
"""
Network is down.
:type: uv.StatusCodes
"""
ENETUNREACH = lib.UV_ENETUNREACH
"""
Network is unreachable.
:type: uv.StatusCodes
"""
ENFILE = lib.UV_ENFILE
"""
File table overflow.
:type: uv.StatusCodes
"""
ENOBUFS = lib.UV_ENOBUFS
"""
No buffer space available.
:type: uv.StatusCodes
"""
ENODEV = lib.UV_ENODEV
"""
No such device.
:type: uv.StatusCodes
"""
ENOENT = lib.UV_ENOENT
"""
No such file or directory.
:type: uv.StatusCodes
"""
ENOMEM = lib.UV_ENOMEM
"""
Not enough memory.
:type: uv.StatusCodes
"""
ENONET = lib.UV_ENONET
"""
Machine is not on the network.
:type: uv.StatusCodes
"""
ENOPROTOOPT = lib.UV_ENOPROTOOPT
"""
Protocol not available.
:type: uv.StatusCodes
"""
ENOSPC = lib.UV_ENOSPC
"""
No space left on device.
:type: uv.StatusCodes
"""
ENOSYS = lib.UV_ENOSYS
"""
Function not implemented.
:type: uv.StatusCodes
"""
ENOTCONN = lib.UV_ENOTCONN
"""
Socket is not connected.
:type: uv.StatusCodes
"""
ENOTDIR = lib.UV_ENOTDIR
"""
Not a directory.
:type: uv.StatusCodes
"""
ENOTEMPTY = lib.UV_ENOTEMPTY
"""
Directory not empty.
:type: uv.StatusCodes
"""
ENOTSOCK = lib.UV_ENOTSOCK
"""
Socket operation on non-socket.
:type: uv.StatusCodes
"""
ENOTSUP = lib.UV_ENOTSUP
"""
Operation not supported on socket.
:type: uv.StatusCodes
"""
EPERM = lib.UV_EPERM
"""
Operation not permitted.
:type: uv.StatusCodes
"""
EPIPE = lib.UV_EPIPE
"""
Broken pipe.
:type: uv.StatusCodes
"""
EPROTO = lib.UV_EPROTO
"""
Protocol error.
:type: uv.StatusCodes
"""
EPROTONOSUPPORT = lib.UV_EPROTONOSUPPORT
"""
Protocol not supported.
:type: uv.StatusCodes
"""
EPROTOTYPE = lib.UV_EPROTOTYPE
"""
Protocol wrong type for socket.
:type: uv.StatusCodes
"""
ERANGE = lib.UV_ERANGE
"""
Result too large.
:type: uv.StatusCodes
"""
EROFS = lib.UV_EROFS
"""
Read-only file system.
:type: uv.StatusCodes
"""
ESHUTDOWN = lib.UV_ESHUTDOWN
"""
Cannot send after transport endpoint shutdown.
:type: uv.StatusCodes
"""
ESPIPE = lib.UV_ESPIPE
"""
Invalid seek.
:type: uv.StatusCodes
"""
ESRCH = lib.UV_ESRCH
"""
No such process.
:type: uv.StatusCodes
"""
ETIMEDOUT = lib.UV_ETIMEDOUT
"""
Connection timed out.
:type: uv.StatusCodes
"""
ETXTBSY = lib.UV_ETXTBSY
"""
Text file is busy.
:type: uv.StatusCodes
"""
EXDEV = lib.UV_EXDEV
"""
Cross-device link not permitted.
:type: uv.StatusCodes
"""
UNKNOWN = lib.UV_UNKNOWN
"""
Unknown error.
:type: uv.StatusCodes
"""
EOF = lib.UV_EOF
"""
End of file.
:type: uv.StatusCodes
"""
ENXIO = lib.UV_ENXIO
"""
No such device or address.
:type: uv.StatusCodes
"""
EMLINK = lib.UV_EMLINK
"""
Too many links.
:type: uv.StatusCodes
"""
EHOSTDOWN = lib.UV_EHOSTDOWN
"""
Host is down.
:type: uv.StatusCodes
"""
def __call__(self, exception):
assert self._exception is UVError
self._exception = exception
self._exception.code = self
return self._exception
@property
def exception(self):
"""
Corresponding exception (subclass of :class:`uv.error.UVError`).
:readonly:
True
:rtype:
Subclass[uv.error.UVError]
"""
return self._exception
@property
def message(self):
"""
Human readable error message.
:readonly:
True
:rtype:
unicode
"""
return ffi.string(lib.uv_strerror(self)).decode()
@classmethod
[docs] def get(cls, code):
"""
Look up the given status code und return the corresponding
instance of :class:`uv.StatusCodes` or the original integer
if there is no such status code.
:param code:
potential status code
:type code:
uv.StatusCodes | int | None
:return:
status code instance or original status code integer
:rtype:
uv.StatusCodes | int
"""
if not code:
# for performance
return StatusCodes.SUCCESS
try:
return StatusCodes(code)
except ValueError:
return code
@classmethod
def from_error_number(cls, error_number):
if not error_number:
return StatusCodes.SUCCESS
return getattr(cls, errno.errorcode[error_number], cls.UNKNOWN)
[docs]class UVError(OSError):
""" Base class of all uv-related exceptions. """
code = None
def __new__(cls, code=None, message=''):
if cls is UVError:
try:
# replace generic uv error with a specialized one if possible
code = StatusCodes(code)
if code.exception is not UVError:
return code.exception(code, message or code.message)
except ValueError:
pass
return super(UVError, cls).__new__(cls, code, message)
def __init__(self, code=None, message=''):
"""
:param code:
Error-Code
:param message:
Error-Message
:type code:
uv.StatusCodes | int | None
:type message:
unicode
"""
try:
code = StatusCodes(code or self.code)
name = code.name
message = message or code.message
except ValueError:
code = code
name = 'UNKNOWN'
message = message or 'some unknown error occoured'
self.code = code
"""
Error-Code
:readonly:
True
:type:
uv.StatusCodes | int | None
"""
self.name = name
"""
Error-Name
:readonly:
True
:type:
unicode
"""
self.message = message
"""
Error-Message
:readonly:
True
:type:
unicode
"""
super(UVError, self).__init__(self.code, '[%s] %s' % (self.name, self.message))
def _get_builtin(name, default=None):
return getattr(common.builtins, name, default)
class _DummyClass(object):
pass
# support for PEP 3151 exception hierarchy
_ConnectionError = _get_builtin('ConnectionError', common.builtins.IOError)
_BrokenPipeError = _get_builtin('BrokenPipeError', common.builtins.IOError)
_ConnectionAbortedError = _get_builtin('ConnectionAbortedError', socket.error)
_ConnectionRefusedError = _get_builtin('ConnectionRefusedError', socket.error)
_ConnectionResetError = _get_builtin('ConnectionResetError', socket.error)
_FileExistsError = _get_builtin('FileExistsError', common.builtins.IOError)
_FileNotFoundError = _get_builtin('FileNotFoundError', common.builtins.IOError)
_InterruptedError = _get_builtin('InterruptedError', _DummyClass)
_IsADirectoryError = _get_builtin('IsADirectoryError', common.builtins.IOError)
_NotADirectoryError = _get_builtin('NotADirectoryError', common.builtins.IOError)
_PermissionError = _get_builtin('PermissionError', common.builtins.IOError)
_ProcessLookupError = _get_builtin('ProcessLookupError', _DummyClass)
_TimeoutError = _get_builtin('TimeoutError', socket.timeout)
# assign default exception
StatusCodes._exception = UVError
@StatusCodes.EINVAL
@StatusCodes.E2BIG
@StatusCodes.EAI_OVERFLOW
@StatusCodes.EFAULT
[docs]class ArgumentError(UVError, ValueError):
""" Invalid arguments. """
@StatusCodes.EAGAIN
@StatusCodes.EAI_AGAIN
[docs]class TemporaryUnavailableError(UVError, io.BlockingIOError):
""" Resource temporary unavailable. """
@StatusCodes.ECANCELED
@StatusCodes.EAI_CANCELED
[docs]class CanceledError(UVError):
""" Request canceled. """
@StatusCodes.EAI_FAIL
[docs]class PermanentError(UVError):
""" Permanent failure. """
@StatusCodes.EACCES
@StatusCodes.EPERM
@StatusCodes.EROFS
[docs]class PermissionError(UVError, _PermissionError):
""" Permission denied. """
@StatusCodes.EBADF
[docs]class BadFileDescriptorError(UVError, common.builtins.IOError):
""" Bad file descriptor. """
@StatusCodes.EBUSY
@StatusCodes.ETXTBSY
[docs]class ResourceBusyError(UVError, common.builtins.IOError):
""" Resource busy or locked. """
@StatusCodes.ECHARSET
[docs]class CharsetError(UVError, UnicodeError):
""" Invalid unicode character. """
@StatusCodes.EEXIST
[docs]class FileExistsError(UVError, _FileExistsError):
""" File already exists. """
@StatusCodes.EFBIG
@StatusCodes.EINTR
[docs]class InterruptedError(UVError, _InterruptedError):
""" Interrupted system call. """
@StatusCodes.EIO
[docs]class IOError(UVError, common.builtins.IOError):
""" Generic IO related error. """
@StatusCodes.EISCONN
[docs]class IsConnectedError(ArgumentError):
""" Socket is already connected. """
@StatusCodes.EISDIR
[docs]class IsADirectoryError(UVError, _IsADirectoryError):
""" Illegal operation on a directory. """
@StatusCodes.ENOTDIR
[docs]class NotADirectoryError(UVError, _NotADirectoryError):
""" Not a directory. """
@StatusCodes.ENOTEMPTY
[docs]class NotEmptyError(UVError):
""" Directory is not empty. """
@StatusCodes.EMSGSIZE
@StatusCodes.ENAMETOOLONG
@StatusCodes.ENOBUFS
[docs]class BufferSpaceError(UVError):
""" No buffer space available. """
@StatusCodes.ENOSPC
[docs]class NoSpaceError(UVError):
""" No space left on the device. """
@StatusCodes.ENOSYS
[docs]class NotImplementedError(UVError, common.builtins.NotImplementedError):
""" Function not implemented. """
@StatusCodes.ENOTCONN
[docs]class NotConnectedError(UVError):
""" Socket is not connected. """
@StatusCodes.EHOSTUNREACH
[docs]class HostUnreachableError(UVError):
""" Host is unreachable. """
@StatusCodes.ERANGE
@StatusCodes.ESPIPE
[docs]class SeekError(UVError):
""" Invalid seek. """
@StatusCodes.ESRCH
[docs]class ProcessLookupError(UVError, _ProcessLookupError):
""" No such progress. """
@StatusCodes.ETIMEDOUT
[docs]class TimeoutError(UVError, _TimeoutError):
""" Operation timed out. """
@StatusCodes.EXDEV
[docs]class CrossDeviceError(UVError):
""" Cross device link not permitted. """
@StatusCodes.EOF
[docs]class EOFError(UVError, common.builtins.EOFError):
""" End of file error. """
[docs]class UnsupportedOperation(UVError):
""" Base class of all unsupported operation related errors. """
[docs]class ClosedStructureError(UnsupportedOperation):
""" Invalid operation on closed structure. """
def __init__(self):
message = 'invalid operation on closed structure'
super(ClosedStructureError, self).__init__(StatusCodes.EINVAL, message)
[docs]class ClosedHandleError(ClosedStructureError):
""" Invalid operation on closed handle. """
[docs]class ClosedLoopError(ClosedStructureError):
""" Invalid operation on closed loop. """
@StatusCodes.ENOTSOCK
[docs]class NotSocketError(UnsupportedOperation):
""" Socket operation on non-socket. """
@StatusCodes.ENOTSUP
[docs]class NotSupportedError(UnsupportedOperation):
""" Operation not supported on socket. """
@StatusCodes.EPROTO
[docs]class ProtocolError(UVError):
""" Protocol error. """
@StatusCodes.ENOPROTOOPT
[docs]class ProtocolNoOptionError(UVError):
""" Protocol option unavailable. """
@StatusCodes.EPROTONOSUPPORT
[docs]class ProtocolNotSupportedError(UVError):
""" Protocol not supported. """
@StatusCodes.EPROTOTYPE
[docs]class ProtocolTypeError(UVError):
""" Protocol wrong type for socket. """
[docs]class AddressError(UVError):
""" Base class of all address related errors. """
@StatusCodes.EADDRNOTAVAIL
[docs]class AddressUnavailableError(AddressError):
""" Address not available. """
@StatusCodes.EADDRINUSE
[docs]class AddressInUseError(AddressUnavailableError):
""" Address already in use. """
@StatusCodes.EAFNOSUPPORT
@StatusCodes.EAI_ADDRFAMILY
@StatusCodes.EAI_FAMILY
[docs]class AddressFamilyError(AddressError, socket.gaierror):
""" Address family not supported. """
@StatusCodes.EAI_BADFLAGS
[docs]class AddressFlagsError(ArgumentError, AddressError, socket.gaierror):
""" Bad address flags value. """
@StatusCodes.EAI_BADHINTS
[docs]class AddressHintsError(ArgumentError, AddressError, socket.gaierror):
""" Bad address hints value. """
@StatusCodes.EAI_NODATA
[docs]class AddressDataError(ArgumentError, AddressError, socket.gaierror):
""" No address given. """
@StatusCodes.EAI_NONAME
[docs]class AddressNameError(AddressError, socket.gaierror):
""" Unknown node or service. """
@StatusCodes.EAI_PROTOCOL
[docs]class AddressProtocolError(AddressError, ProtocolError, socket.gaierror):
""" Resolved protocol is unknown. """
@StatusCodes.EAI_SERVICE
[docs]class AddressServiceError(AddressError, socket.gaierror):
""" Service not available for socket type. """
@StatusCodes.EAI_SOCKTYPE
[docs]class AddressSocketTypeError(AddressError, socket.gaierror):
""" Socket type not supported. """
@StatusCodes.EDESTADDRREQ
[docs]class DestinationAddressError(AddressError):
""" Destination address required. """
[docs]class ConnectionError(UVError):
""" Base class of all connection related errors. """
@StatusCodes.EPIPE
@StatusCodes.ESHUTDOWN
[docs]class BrokenPipeError(ConnectionError, _BrokenPipeError):
""" Broken pipe. """
@StatusCodes.ECONNABORTED
[docs]class ConnectionAbortedError(ConnectionError, _ConnectionAbortedError):
""" Software caused connection abort. """
@StatusCodes.ECONNREFUSED
[docs]class ConnectionRefusedError(ConnectionError, _ConnectionRefusedError):
""" Connection refused. """
@StatusCodes.ECONNRESET
[docs]class ConnectionResetError(ConnectionError, _ConnectionResetError):
""" Connection reset by peer. """
@StatusCodes.EALREADY
[docs]class ConnectionInProgressError(ConnectionError, io.BlockingIOError):
""" Connection already in progress. """
[docs]class NotFoundError(UVError):
""" Base class of all not found related errors. """
@StatusCodes.ENODEV
@StatusCodes.ENXIO
[docs]class DeviceNotFoundError(NotFoundError):
""" No such device or address. """
@StatusCodes.ENOENT
[docs]class FileNotFoundError(NotFoundError, _FileNotFoundError):
""" No such file or directory. """
[docs]class NetworkError(UVError):
""" Base class of all network related errors. """
@StatusCodes.ENETDOWN
[docs]class NetworkDownError(NetworkError):
""" Network is down. """
@StatusCodes.ENETUNREACH
[docs]class NetworkUnreachableError(NetworkError):
""" Network is unreachable. """
@StatusCodes.ENONET
[docs]class NoNetworkError(NetworkError):
""" Machine is not on the network. """
[docs]class SystemFailureError(UVError):
""" Base class of all system related errors. """
@StatusCodes.ENOMEM
@StatusCodes.EAI_MEMORY
[docs]class MemoryError(SystemFailureError, common.builtins.MemoryError):
""" Not enough memory. """
@StatusCodes.EMLINK
[docs]class TooManyLinksError(SystemFailureError):
""" Too many links encountered. """
@StatusCodes.ELOOP
[docs]class TooManySymbolicLinksError(TooManyLinksError):
""" Too many symbolic links encountered. """
@StatusCodes.EMFILE
[docs]class TooManyOpenFilesError(SystemFailureError):
""" Too many open files. """
@StatusCodes.ENFILE
[docs]class FileTableOverflowError(SystemFailureError):
""" File table overflow. """