error.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. """0MQ Error classes and functions."""
  2. # Copyright (C) PyZMQ Developers
  3. # Distributed under the terms of the Modified BSD License.
  4. from errno import EINTR
  5. class ZMQBaseError(Exception):
  6. """Base exception class for 0MQ errors in Python."""
  7. pass
  8. class ZMQError(ZMQBaseError):
  9. """Wrap an errno style error.
  10. Parameters
  11. ----------
  12. errno : int
  13. The ZMQ errno or None. If None, then ``zmq_errno()`` is called and
  14. used.
  15. msg : string
  16. Description of the error or None.
  17. """
  18. errno = None
  19. def __init__(self, errno=None, msg=None):
  20. """Wrap an errno style error.
  21. Parameters
  22. ----------
  23. errno : int
  24. The ZMQ errno or None. If None, then ``zmq_errno()`` is called and
  25. used.
  26. msg : string
  27. Description of the error or None.
  28. """
  29. from zmq.backend import strerror, zmq_errno
  30. if errno is None:
  31. errno = zmq_errno()
  32. if isinstance(errno, int):
  33. self.errno = errno
  34. if msg is None:
  35. self.strerror = strerror(errno)
  36. else:
  37. self.strerror = msg
  38. else:
  39. if msg is None:
  40. self.strerror = str(errno)
  41. else:
  42. self.strerror = msg
  43. # flush signals, because there could be a SIGINT
  44. # waiting to pounce, resulting in uncaught exceptions.
  45. # Doing this here means getting SIGINT during a blocking
  46. # libzmq call will raise a *catchable* KeyboardInterrupt
  47. # PyErr_CheckSignals()
  48. def __str__(self):
  49. return self.strerror
  50. def __repr__(self):
  51. return "%s('%s')" % (self.__class__.__name__, str(self))
  52. class ZMQBindError(ZMQBaseError):
  53. """An error for ``Socket.bind_to_random_port()``.
  54. See Also
  55. --------
  56. .Socket.bind_to_random_port
  57. """
  58. pass
  59. class NotDone(ZMQBaseError):
  60. """Raised when timeout is reached while waiting for 0MQ to finish with a Message
  61. See Also
  62. --------
  63. .MessageTracker.wait : object for tracking when ZeroMQ is done
  64. """
  65. pass
  66. class ContextTerminated(ZMQError):
  67. """Wrapper for zmq.ETERM
  68. .. versionadded:: 13.0
  69. """
  70. def __init__(self, errno='ignored', msg='ignored'):
  71. from zmq import ETERM
  72. super(ContextTerminated, self).__init__(ETERM)
  73. class Again(ZMQError):
  74. """Wrapper for zmq.EAGAIN
  75. .. versionadded:: 13.0
  76. """
  77. def __init__(self, errno='ignored', msg='ignored'):
  78. from zmq import EAGAIN
  79. super(Again, self).__init__(EAGAIN)
  80. try:
  81. InterruptedError
  82. except NameError:
  83. InterruptedError = OSError
  84. class InterruptedSystemCall(ZMQError, InterruptedError):
  85. """Wrapper for EINTR
  86. This exception should be caught internally in pyzmq
  87. to retry system calls, and not propagate to the user.
  88. .. versionadded:: 14.7
  89. """
  90. def __init__(self, errno='ignored', msg='ignored'):
  91. super(InterruptedSystemCall, self).__init__(EINTR)
  92. def __str__(self):
  93. s = super(InterruptedSystemCall, self).__str__()
  94. return s + ": This call should have been retried. Please report this to pyzmq."
  95. def _check_rc(rc, errno=None):
  96. """internal utility for checking zmq return condition
  97. and raising the appropriate Exception class
  98. """
  99. if rc == -1:
  100. if errno is None:
  101. from zmq.backend import zmq_errno
  102. errno = zmq_errno()
  103. from zmq import EAGAIN, ETERM
  104. if errno == EINTR:
  105. raise InterruptedSystemCall(errno)
  106. elif errno == EAGAIN:
  107. raise Again(errno)
  108. elif errno == ETERM:
  109. raise ContextTerminated(errno)
  110. else:
  111. raise ZMQError(errno)
  112. _zmq_version_info = None
  113. _zmq_version = None
  114. class ZMQVersionError(NotImplementedError):
  115. """Raised when a feature is not provided by the linked version of libzmq.
  116. .. versionadded:: 14.2
  117. """
  118. min_version = None
  119. def __init__(self, min_version, msg='Feature'):
  120. global _zmq_version
  121. if _zmq_version is None:
  122. from zmq import zmq_version
  123. _zmq_version = zmq_version()
  124. self.msg = msg
  125. self.min_version = min_version
  126. self.version = _zmq_version
  127. def __repr__(self):
  128. return "ZMQVersionError('%s')" % str(self)
  129. def __str__(self):
  130. return "%s requires libzmq >= %s, have %s" % (self.msg, self.min_version, self.version)
  131. def _check_version(min_version_info, msg='Feature'):
  132. """Check for libzmq
  133. raises ZMQVersionError if current zmq version is not at least min_version
  134. min_version_info is a tuple of integers, and will be compared against zmq.zmq_version_info().
  135. """
  136. global _zmq_version_info
  137. if _zmq_version_info is None:
  138. from zmq import zmq_version_info
  139. _zmq_version_info = zmq_version_info()
  140. if _zmq_version_info < min_version_info:
  141. min_version = '.'.join(str(v) for v in min_version_info)
  142. raise ZMQVersionError(min_version, msg)
  143. __all__ = [
  144. 'ZMQBaseError',
  145. 'ZMQBindError',
  146. 'ZMQError',
  147. 'NotDone',
  148. 'ContextTerminated',
  149. 'InterruptedSystemCall',
  150. 'Again',
  151. 'ZMQVersionError',
  152. ]