Coverage for aiocoap/error.py: 90%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

68 statements  

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}")