exceptions.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. """Exceptions used by amqp."""
  2. # Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
  3. from __future__ import absolute_import, unicode_literals
  4. from .five import python_2_unicode_compatible
  5. from .platform import pack, unpack
  6. __all__ = [
  7. 'AMQPError',
  8. 'ConnectionError', 'ChannelError',
  9. 'RecoverableConnectionError', 'IrrecoverableConnectionError',
  10. 'RecoverableChannelError', 'IrrecoverableChannelError',
  11. 'ConsumerCancelled', 'ContentTooLarge', 'NoConsumers',
  12. 'ConnectionForced', 'InvalidPath', 'AccessRefused', 'NotFound',
  13. 'ResourceLocked', 'PreconditionFailed', 'FrameError', 'FrameSyntaxError',
  14. 'InvalidCommand', 'ChannelNotOpen', 'UnexpectedFrame', 'ResourceError',
  15. 'NotAllowed', 'AMQPNotImplementedError', 'InternalError',
  16. 'MessageNacked',
  17. 'AMQPDeprecationWarning',
  18. ]
  19. class AMQPDeprecationWarning(UserWarning):
  20. """Warning for deprecated things."""
  21. class MessageNacked(Exception):
  22. """Message was nacked by broker."""
  23. @python_2_unicode_compatible
  24. class AMQPError(Exception):
  25. """Base class for all AMQP exceptions."""
  26. code = 0
  27. def __init__(self, reply_text=None, method_sig=None,
  28. method_name=None, reply_code=None):
  29. self.message = reply_text
  30. self.reply_code = reply_code or self.code
  31. self.reply_text = reply_text
  32. self.method_sig = method_sig
  33. self.method_name = method_name or ''
  34. if method_sig and not self.method_name:
  35. self.method_name = METHOD_NAME_MAP.get(method_sig, '')
  36. Exception.__init__(self, reply_code,
  37. reply_text, method_sig, self.method_name)
  38. def __str__(self):
  39. if self.method:
  40. return '{0.method}: ({0.reply_code}) {0.reply_text}'.format(self)
  41. return self.reply_text or '<{}: unknown error>'.format(
  42. type(self).__name__
  43. )
  44. @property
  45. def method(self):
  46. return self.method_name or self.method_sig
  47. class ConnectionError(AMQPError):
  48. """AMQP Connection Error."""
  49. class ChannelError(AMQPError):
  50. """AMQP Channel Error."""
  51. class RecoverableChannelError(ChannelError):
  52. """Exception class for recoverable channel errors."""
  53. class IrrecoverableChannelError(ChannelError):
  54. """Exception class for irrecoverable channel errors."""
  55. class RecoverableConnectionError(ConnectionError):
  56. """Exception class for recoverable connection errors."""
  57. class IrrecoverableConnectionError(ConnectionError):
  58. """Exception class for irrecoverable connection errors."""
  59. class Blocked(RecoverableConnectionError):
  60. """AMQP Connection Blocked Predicate."""
  61. class ConsumerCancelled(RecoverableConnectionError):
  62. """AMQP Consumer Cancelled Predicate."""
  63. class ContentTooLarge(RecoverableChannelError):
  64. """AMQP Content Too Large Error."""
  65. code = 311
  66. class NoConsumers(RecoverableChannelError):
  67. """AMQP No Consumers Error."""
  68. code = 313
  69. class ConnectionForced(RecoverableConnectionError):
  70. """AMQP Connection Forced Error."""
  71. code = 320
  72. class InvalidPath(IrrecoverableConnectionError):
  73. """AMQP Invalid Path Error."""
  74. code = 402
  75. class AccessRefused(IrrecoverableChannelError):
  76. """AMQP Access Refused Error."""
  77. code = 403
  78. class NotFound(IrrecoverableChannelError):
  79. """AMQP Not Found Error."""
  80. code = 404
  81. class ResourceLocked(RecoverableChannelError):
  82. """AMQP Resource Locked Error."""
  83. code = 405
  84. class PreconditionFailed(IrrecoverableChannelError):
  85. """AMQP Precondition Failed Error."""
  86. code = 406
  87. class FrameError(IrrecoverableConnectionError):
  88. """AMQP Frame Error."""
  89. code = 501
  90. class FrameSyntaxError(IrrecoverableConnectionError):
  91. """AMQP Frame Syntax Error."""
  92. code = 502
  93. class InvalidCommand(IrrecoverableConnectionError):
  94. """AMQP Invalid Command Error."""
  95. code = 503
  96. class ChannelNotOpen(IrrecoverableConnectionError):
  97. """AMQP Channel Not Open Error."""
  98. code = 504
  99. class UnexpectedFrame(IrrecoverableConnectionError):
  100. """AMQP Unexpected Frame."""
  101. code = 505
  102. class ResourceError(RecoverableConnectionError):
  103. """AMQP Resource Error."""
  104. code = 506
  105. class NotAllowed(IrrecoverableConnectionError):
  106. """AMQP Not Allowed Error."""
  107. code = 530
  108. class AMQPNotImplementedError(IrrecoverableConnectionError):
  109. """AMQP Not Implemented Error."""
  110. code = 540
  111. class InternalError(IrrecoverableConnectionError):
  112. """AMQP Internal Error."""
  113. code = 541
  114. ERROR_MAP = {
  115. 311: ContentTooLarge,
  116. 313: NoConsumers,
  117. 320: ConnectionForced,
  118. 402: InvalidPath,
  119. 403: AccessRefused,
  120. 404: NotFound,
  121. 405: ResourceLocked,
  122. 406: PreconditionFailed,
  123. 501: FrameError,
  124. 502: FrameSyntaxError,
  125. 503: InvalidCommand,
  126. 504: ChannelNotOpen,
  127. 505: UnexpectedFrame,
  128. 506: ResourceError,
  129. 530: NotAllowed,
  130. 540: AMQPNotImplementedError,
  131. 541: InternalError,
  132. }
  133. def error_for_code(code, text, method, default):
  134. try:
  135. return ERROR_MAP[code](text, method, reply_code=code)
  136. except KeyError:
  137. return default(text, method, reply_code=code)
  138. METHOD_NAME_MAP = {
  139. (10, 10): 'Connection.start',
  140. (10, 11): 'Connection.start_ok',
  141. (10, 20): 'Connection.secure',
  142. (10, 21): 'Connection.secure_ok',
  143. (10, 30): 'Connection.tune',
  144. (10, 31): 'Connection.tune_ok',
  145. (10, 40): 'Connection.open',
  146. (10, 41): 'Connection.open_ok',
  147. (10, 50): 'Connection.close',
  148. (10, 51): 'Connection.close_ok',
  149. (20, 10): 'Channel.open',
  150. (20, 11): 'Channel.open_ok',
  151. (20, 20): 'Channel.flow',
  152. (20, 21): 'Channel.flow_ok',
  153. (20, 40): 'Channel.close',
  154. (20, 41): 'Channel.close_ok',
  155. (30, 10): 'Access.request',
  156. (30, 11): 'Access.request_ok',
  157. (40, 10): 'Exchange.declare',
  158. (40, 11): 'Exchange.declare_ok',
  159. (40, 20): 'Exchange.delete',
  160. (40, 21): 'Exchange.delete_ok',
  161. (40, 30): 'Exchange.bind',
  162. (40, 31): 'Exchange.bind_ok',
  163. (40, 40): 'Exchange.unbind',
  164. (40, 41): 'Exchange.unbind_ok',
  165. (50, 10): 'Queue.declare',
  166. (50, 11): 'Queue.declare_ok',
  167. (50, 20): 'Queue.bind',
  168. (50, 21): 'Queue.bind_ok',
  169. (50, 30): 'Queue.purge',
  170. (50, 31): 'Queue.purge_ok',
  171. (50, 40): 'Queue.delete',
  172. (50, 41): 'Queue.delete_ok',
  173. (50, 50): 'Queue.unbind',
  174. (50, 51): 'Queue.unbind_ok',
  175. (60, 10): 'Basic.qos',
  176. (60, 11): 'Basic.qos_ok',
  177. (60, 20): 'Basic.consume',
  178. (60, 21): 'Basic.consume_ok',
  179. (60, 30): 'Basic.cancel',
  180. (60, 31): 'Basic.cancel_ok',
  181. (60, 40): 'Basic.publish',
  182. (60, 50): 'Basic.return',
  183. (60, 60): 'Basic.deliver',
  184. (60, 70): 'Basic.get',
  185. (60, 71): 'Basic.get_ok',
  186. (60, 72): 'Basic.get_empty',
  187. (60, 80): 'Basic.ack',
  188. (60, 90): 'Basic.reject',
  189. (60, 100): 'Basic.recover_async',
  190. (60, 110): 'Basic.recover',
  191. (60, 111): 'Basic.recover_ok',
  192. (60, 120): 'Basic.nack',
  193. (90, 10): 'Tx.select',
  194. (90, 11): 'Tx.select_ok',
  195. (90, 20): 'Tx.commit',
  196. (90, 21): 'Tx.commit_ok',
  197. (90, 30): 'Tx.rollback',
  198. (90, 31): 'Tx.rollback_ok',
  199. (85, 10): 'Confirm.select',
  200. (85, 11): 'Confirm.select_ok',
  201. }
  202. for _method_id, _method_name in list(METHOD_NAME_MAP.items()):
  203. METHOD_NAME_MAP[unpack('>I', pack('>HH', *_method_id))[0]] = \
  204. _method_name