Python · Errors

Errors

import ucallfrom ucall import Error 1.0.0-rc.1 · 60202332

A failed operation raises ucall.Error, a RuntimeError whose status is the ucall.Status it reported and whose message is a static detail beside it. Each failing status raises a subclass of its own, named after the status, such as ucall.ConnectionFailedError or ucall.NotFoundError. Where a built-in exception names the same fault, the subclass derives it too: ConnectionError for connection failures, TimeoutError, MemoryError, OSError, ValueError for invalid or malformed input, KeyError, NotImplementedError, OverflowError and BlockingIOError. str(error) joins the two, as in “CONNECTION_FAILED: connection-failed”. Arguments of the wrong type raise TypeError, a key of the wrong length or an unknown enum name raises ValueError, and a reply while views over the body are alive raises BufferError.

import ucall

client = ucall.Client(connections=1)
try:
    response = client.get("http://127.0.0.1:1/")
    print("answered", response.status_code)
except ucall.ConnectionFailedError as error:  # or: except ConnectionError
    assert error.status == ucall.Status.CONNECTION_FAILED
    print("nobody listens:", error)

ucall.Status, Backend, CPUClass, Security, Verb, BodyDelivery and LogLevel are enum.IntEnum classes, and every argument taking one also takes its name in any case, with ”-” or ”_” between words. ucall.Status.from_name("out-of-memory") reads a status back from the spelling the library gives it, ucall.version() numbers the linked library, and ucall.__version__ spells it with any candidate suffix. A submitted call that fails completes with that status in Completed.status, such as CONNECTION_FAILED, CONNECTION_CLOSED, TIMEOUT, HANDSHAKE_FAILED or PEER_REJECTED, and HTTP error statuses are ordinary responses. On the serving side, failures become replies rather than exceptions: 400 for parameters that do not bind, 500 for a handler that raised or a request released unanswered.

API

Types

StatusThe outcome of a verb, which Error.status and Completed.status carry.
__init__.py:84 ↗
class Status(enum.IntEnum)

Values

SUCCESS0
DEFERRED1
OUT_OF_MEMORY2
IO7
MALFORMED9
INTERNAL10
OVERFLOW11
UNINITIALIZED12
CONTENDED14
UNSUPPORTED16
INVALID_ARGUMENT17
NOT_FOUND18
ALREADY_EXISTS19
CONNECTION_FAILED20
CONNECTION_CLOSED21
TIMEOUT22
HANDSHAKE_FAILED23
PEER_REJECTED24
WOULD_BLOCK25

Examples

>>> ucall.Status.CONTENDED.name
'CONTENDED'
OutOfMemoryErrorAn allocation could not be satisfied.
__init__.py:249 ↗
class OutOfMemoryError(Error, MemoryError)
InputOutputErrorA file or socket could not be opened, read, written, or closed.
__init__.py:252 ↗
class InputOutputError(Error, OSError)
MalformedErrorThe peer sent bytes that do not decode as the expected protocol.
__init__.py:255 ↗
class MalformedError(Error, ValueError)
InternalErrorThe library violated its contract, which points at a defect.
__init__.py:258 ↗
class InternalError(Error)
OverflowErrorA requested size exceeds the representable range.
__init__.py:261 ↗
class OverflowError(Error, builtins.OverflowError)
UninitializedErrorThe call needs a handle that was never initialized.
__init__.py:264 ↗
class UninitializedError(Error)
ContendedErrorThe call was refused rather than waited for, like a submission to a full client.
__init__.py:267 ↗
class ContendedError(Error)
UnsupportedErrorThe build, backend, or machine does not implement the requested feature.
__init__.py:270 ↗
class UnsupportedError(Error, NotImplementedError)
InvalidArgumentErrorAn argument is missing, out of range, or contradicts another argument.
__init__.py:273 ↗
class InvalidArgumentError(Error, ValueError)
NotFoundErrorThe requested endpoint, header, parameter, or file does not exist.
__init__.py:276 ↗
class NotFoundError(Error, KeyError)
AlreadyExistsErrorAn endpoint with the same template and verb is already registered.
__init__.py:279 ↗
class AlreadyExistsError(Error, ValueError)
ConnectionFailedErrorDNS lookup or connection establishment failed.
__init__.py:282 ↗
class ConnectionFailedError(Error, ConnectionError)
ConnectionClosedErrorThe connection closed before the exchange completed.
__init__.py:285 ↗
class ConnectionClosedError(Error, ConnectionError)
TimeoutErrorThe exchange did not finish within its deadline.
__init__.py:288 ↗
class TimeoutError(Error, builtins.TimeoutError)
HandshakeFailedErrorThe Noise handshake failed to authenticate or agree on keys.
__init__.py:291 ↗
class HandshakeFailedError(Error)
PeerRejectedErrorThe peer authorizer declined the authenticated static key.
__init__.py:294 ↗
class PeerRejectedError(Error)
WouldBlockErrorNothing was ready, like a body pull on the polling thread before any bytes arrived.
__init__.py:297 ↗
class WouldBlockError(Error, BlockingIOError)
ClassErrorA failed verb, raised with the Status it reported and a static detail.3
lib.pyi:226 ↗
class Error(RuntimeError)

Each failing status raises its own subclass, like ConnectionFailedError, which derives the built-in naming the same fault, here ConnectionError.

Examples

>>> error = ucall.Error(ucall.Status.TIMEOUT, "no reply")
>>> error.status, error.message, str(error)
(<Status.TIMEOUT: 22>, 'no reply', 'TIMEOUT: no reply')
Error
lib.pyi:241 ↗
Error(status: Status, message: str, /)
statusThe Status of the failure.
lib.pyi:243 ↗
status: Status
messageThe detail of the failure.
lib.pyi:246 ↗
message: str