1# This file is part of the Python aiocoap library project. 2# 3# Copyright (c) 2012-2014 Maciej Wasilak <http://sixpinetrees.blogspot.com/>, 4# 2013-2014 Christian Amsüss <c.amsuess@energyharvesting.at> 5# 6# aiocoap is free software, this file is published under the MIT license as 7# described in the accompanying LICENSE file. 8 9""" 10Common errors for the aiocoap library 11""" 12 13import warnings 14import abc 15 16from .numbers import codes 17 18class Error(Exception): 19 """ 20 Base exception for all exceptions that indicate a failed request 21 """ 22 23class RenderableError(Error, metaclass=abc.ABCMeta): 24 """ 25 Exception that can meaningfully be represented in a CoAP response 26 """ 27 28 @abc.abstractmethod 29 def to_message(self): 30 """Create a CoAP message that should be sent when this exception is 31 rendered""" 32 33class ResponseWrappingError(Error): 34 """ 35 An exception that is raised due to an unsuccessful but received response. 36 37 A better relationship with :mod:`.numbers.codes` should be worked out to do 38 ``except UnsupportedMediaType`` (similar to the various ``OSError`` 39 subclasses). 40 """ 41 def __init__(self, coapmessage): 42 self.coapmessage = coapmessage 43 44 def to_message(self): 45 return self.coapmessage 46 47 def __repr__(self): 48 return "<%s: %s %r>"%(type(self).__name__, self.coapmessage.code, self.coapmessage.payload) 49 50class ConstructionRenderableError(RenderableError): 51 """ 52 RenderableError that is constructed from class attributes :attr:`code` and 53 :attr:`message` (where the can be overridden in the constructor). 54 """ 55 56 def __init__(self, message=None): 57 if message is not None: 58 self.message = message 59 60 def to_message(self): 61 from .message import Message 62 return Message(code=self.code, payload=self.message.encode('utf8')) 63 64 code = codes.INTERNAL_SERVER_ERROR #: Code assigned to messages built from it 65 message = "" #: Text sent in the built message's payload 66 67# FIXME: this should be comprehensive, maybe generted from the code list 68 69class NotFound(ConstructionRenderableError): 70 code = codes.NOT_FOUND 71 72class MethodNotAllowed(ConstructionRenderableError): 73 code = codes.METHOD_NOT_ALLOWED 74 75class UnsupportedContentFormat(ConstructionRenderableError): 76 code = codes.UNSUPPORTED_CONTENT_FORMAT 77 78class Unauthorized(ConstructionRenderableError): 79 code = codes.UNAUTHORIZED 80 81class BadRequest(ConstructionRenderableError): 82 code = codes.BAD_REQUEST 83 84# More detailed versions of code based errors 85 86class NoResource(NotFound): 87 """ 88 Raised when resource is not found. 89 """ 90 message = "Error: Resource not found!" 91 def __init__(self): 92 warnings.warn("NoResource is deprecated in favor of NotFound", DeprecationWarning, stacklevel=2) 93 94class UnallowedMethod(MethodNotAllowed): 95 """ 96 Raised by a resource when request method is understood by the server 97 but not allowed for that particular resource. 98 """ 99 message = "Error: Method not allowed!" 100 101class UnsupportedMethod(MethodNotAllowed): 102 """ 103 Raised when request method is not understood by the server at all. 104 """ 105 message = "Error: Method not recognized!" 106 107 108class NetworkError(Error): 109 """Base class for all "something went wrong with name resolution, sending 110 or receiving packages". 111 112 Errors of these kinds are raised towards client callers when things went 113 wrong network-side, or at context creation. They are often raised from 114 socket.gaierror or similar classes, but these are wrapped in order to make 115 catching them possible independently of the underlying transport.""" 116 117class ResolutionError(NetworkError): 118 """Resolving the host component of a URI to a usable transport address was 119 not possible""" 120 121class MessageError(NetworkError): 122 """Received an error from the remote on the CoAP message level (typically a 123 RST)""" 124 125class NotImplemented(Error): 126 """ 127 Raised when request is correct, but feature is not implemented 128 by library. 129 For example non-sequential blockwise transfers 130 """ 131 132class RemoteServerShutdown(NetworkError): 133 """The peer a request was sent to in a stateful connection closed the 134 connection around the time the request was sent""" 135 136class TimeoutError(NetworkError): 137 """Base for all timeout-ish errors. 138 139 Like NetworkError, receiving this alone does not indicate whether the 140 request may have reached the server or not. 141 """ 142 143class ConRetransmitsExceeded(TimeoutError): 144 """A transport that retransmits CON messages has failed to obtain a response 145 within its retransmission timeout. 146 147 When this is raised in a transport, requests failing with it may or may 148 have been received by the server. 149 """ 150 151class RequestTimedOut(TimeoutError): 152 """ 153 Raised when request is timed out. 154 155 This error is currently not produced by aiocoap; it is deprecated. Users 156 can now catch error.TimeoutError, or newer more detailed subtypes 157 introduced later. 158 """ 159 160 161class WaitingForClientTimedOut(TimeoutError): 162 """ 163 Raised when server expects some client action: 164 165 - sending next PUT/POST request with block1 or block2 option 166 - sending next GET request with block2 option 167 168 but client does nothing. 169 170 This error is currently not produced by aiocoap; it is deprecated. Users 171 can now catch error.TimeoutError, or newer more detailed subtypes 172 introduced later. 173 """ 174 175class ResourceChanged(Error): 176 """ 177 The requested resource was modified during the request and could therefore 178 not be received in a consistent state. 179 """ 180 181class UnexpectedBlock1Option(Error): 182 """ 183 Raised when a server responds with block1 options that just don't match. 184 """ 185 186class UnexpectedBlock2(Error): 187 """ 188 Raised when a server responds with another block2 than expected. 189 """ 190 191class MissingBlock2Option(Error): 192 """ 193 Raised when response with Block2 option is expected 194 (previous response had Block2 option with More flag set), 195 but response without Block2 option is received. 196 """ 197 198class NotObservable(Error): 199 """ 200 The server did not accept the request to observe the resource. 201 """ 202 203class ObservationCancelled(Error): 204 """ 205 The server claimed that it will no longer sustain the observation. 206 """ 207 208class UnparsableMessage(Error): 209 """ 210 An incoming message does not look like CoAP. 211 212 Note that this happens rarely -- the requirements are just two bit at the 213 beginning of the message, and a minimum length. 214 """ 215 216class LibraryShutdown(Error): 217 """The library or a transport registered with it was requested to shut 218 down; this error is raised in all outstanding requests.""" 219 220class AnonymousHost(Error): 221 """This is raised when it is attempted to express as a reference a (base) 222 URI of a host or a resource that can not be reached by any process other 223 than this. 224 225 Typically, this happens when trying to serialize a link to a resource that 226 is hosted on a CoAP-over-TCP or -WebSockets client: Such resources can be 227 accessed for as long as the connection is active, but can not be used any 228 more once it is closed or even by another system.""" 229 230_deprecated_aliases = { 231 "UnsupportedMediaType": "UnsupportedContentFormat", 232 "RequestTimedOut": "TimeoutError", 233 "WaitingForClientTimedOut": "TimeoutError", 234 } 235def __getattr__(name): 236 if name in _deprecated_aliases: 237 modern = _deprecated_aliases[name] 238 from warnings import warn 239 warn(f"{name} is deprecated, use {modern} instead", DeprecationWarning, 240 stacklevel=2) 241 return globals()[modern] 242 raise AttributeError(f"module {__name__} has no attribute {name}") 243