test_exception_hierarchy.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import builtins
  2. import os
  3. import select
  4. import socket
  5. import unittest
  6. import errno
  7. from errno import EEXIST
  8. class SubOSError(OSError):
  9. pass
  10. class SubOSErrorWithInit(OSError):
  11. def __init__(self, message, bar):
  12. self.bar = bar
  13. super().__init__(message)
  14. class SubOSErrorWithNew(OSError):
  15. def __new__(cls, message, baz):
  16. self = super().__new__(cls, message)
  17. self.baz = baz
  18. return self
  19. class SubOSErrorCombinedInitFirst(SubOSErrorWithInit, SubOSErrorWithNew):
  20. pass
  21. class SubOSErrorCombinedNewFirst(SubOSErrorWithNew, SubOSErrorWithInit):
  22. pass
  23. class SubOSErrorWithStandaloneInit(OSError):
  24. def __init__(self):
  25. pass
  26. class HierarchyTest(unittest.TestCase):
  27. def test_builtin_errors(self):
  28. self.assertEqual(OSError.__name__, 'OSError')
  29. self.assertIs(IOError, OSError)
  30. self.assertIs(EnvironmentError, OSError)
  31. def test_socket_errors(self):
  32. self.assertIs(socket.error, OSError)
  33. self.assertIs(socket.gaierror.__base__, OSError)
  34. self.assertIs(socket.herror.__base__, OSError)
  35. self.assertIs(socket.timeout, TimeoutError)
  36. def test_select_error(self):
  37. self.assertIs(select.error, OSError)
  38. # mmap.error is tested in test_mmap
  39. _pep_map = """
  40. +-- BlockingIOError EAGAIN, EALREADY, EWOULDBLOCK, EINPROGRESS
  41. +-- ChildProcessError ECHILD
  42. +-- ConnectionError
  43. +-- BrokenPipeError EPIPE, ESHUTDOWN
  44. +-- ConnectionAbortedError ECONNABORTED
  45. +-- ConnectionRefusedError ECONNREFUSED
  46. +-- ConnectionResetError ECONNRESET
  47. +-- FileExistsError EEXIST
  48. +-- FileNotFoundError ENOENT
  49. +-- InterruptedError EINTR
  50. +-- IsADirectoryError EISDIR
  51. +-- NotADirectoryError ENOTDIR
  52. +-- PermissionError EACCES, EPERM, ENOTCAPABLE
  53. +-- ProcessLookupError ESRCH
  54. +-- TimeoutError ETIMEDOUT
  55. """
  56. def _make_map(s):
  57. _map = {}
  58. for line in s.splitlines():
  59. line = line.strip('+- ')
  60. if not line:
  61. continue
  62. excname, _, errnames = line.partition(' ')
  63. for errname in filter(None, errnames.strip().split(', ')):
  64. if errname == "ENOTCAPABLE" and not hasattr(errno, errname):
  65. continue
  66. _map[getattr(errno, errname)] = getattr(builtins, excname)
  67. return _map
  68. _map = _make_map(_pep_map)
  69. def test_errno_mapping(self):
  70. # The OSError constructor maps errnos to subclasses
  71. # A sample test for the basic functionality
  72. e = OSError(EEXIST, "Bad file descriptor")
  73. self.assertIs(type(e), FileExistsError)
  74. # Exhaustive testing
  75. for errcode, exc in self._map.items():
  76. e = OSError(errcode, "Some message")
  77. self.assertIs(type(e), exc)
  78. othercodes = set(errno.errorcode) - set(self._map)
  79. for errcode in othercodes:
  80. e = OSError(errcode, "Some message")
  81. self.assertIs(type(e), OSError, repr(e))
  82. def test_try_except(self):
  83. filename = "some_hopefully_non_existing_file"
  84. # This checks that try .. except checks the concrete exception
  85. # (FileNotFoundError) and not the base type specified when
  86. # PyErr_SetFromErrnoWithFilenameObject was called.
  87. # (it is therefore deliberate that it doesn't use assertRaises)
  88. try:
  89. open(filename)
  90. except FileNotFoundError:
  91. pass
  92. else:
  93. self.fail("should have raised a FileNotFoundError")
  94. # Another test for PyErr_SetExcFromWindowsErrWithFilenameObject()
  95. self.assertFalse(os.path.exists(filename))
  96. try:
  97. os.unlink(filename)
  98. except FileNotFoundError:
  99. pass
  100. else:
  101. self.fail("should have raised a FileNotFoundError")
  102. class AttributesTest(unittest.TestCase):
  103. def test_windows_error(self):
  104. if os.name == "nt":
  105. self.assertIn('winerror', dir(OSError))
  106. else:
  107. self.assertNotIn('winerror', dir(OSError))
  108. def test_posix_error(self):
  109. e = OSError(EEXIST, "File already exists", "foo.txt")
  110. self.assertEqual(e.errno, EEXIST)
  111. self.assertEqual(e.args[0], EEXIST)
  112. self.assertEqual(e.strerror, "File already exists")
  113. self.assertEqual(e.filename, "foo.txt")
  114. if os.name == "nt":
  115. self.assertEqual(e.winerror, None)
  116. @unittest.skipUnless(os.name == "nt", "Windows-specific test")
  117. def test_errno_translation(self):
  118. # ERROR_ALREADY_EXISTS (183) -> EEXIST
  119. e = OSError(0, "File already exists", "foo.txt", 183)
  120. self.assertEqual(e.winerror, 183)
  121. self.assertEqual(e.errno, EEXIST)
  122. self.assertEqual(e.args[0], EEXIST)
  123. self.assertEqual(e.strerror, "File already exists")
  124. self.assertEqual(e.filename, "foo.txt")
  125. def test_blockingioerror(self):
  126. args = ("a", "b", "c", "d", "e")
  127. for n in range(6):
  128. e = BlockingIOError(*args[:n])
  129. with self.assertRaises(AttributeError):
  130. e.characters_written
  131. with self.assertRaises(AttributeError):
  132. del e.characters_written
  133. e = BlockingIOError("a", "b", 3)
  134. self.assertEqual(e.characters_written, 3)
  135. e.characters_written = 5
  136. self.assertEqual(e.characters_written, 5)
  137. del e.characters_written
  138. with self.assertRaises(AttributeError):
  139. e.characters_written
  140. class ExplicitSubclassingTest(unittest.TestCase):
  141. def test_errno_mapping(self):
  142. # When constructing an OSError subclass, errno mapping isn't done
  143. e = SubOSError(EEXIST, "Bad file descriptor")
  144. self.assertIs(type(e), SubOSError)
  145. def test_init_overridden(self):
  146. e = SubOSErrorWithInit("some message", "baz")
  147. self.assertEqual(e.bar, "baz")
  148. self.assertEqual(e.args, ("some message",))
  149. def test_init_kwdargs(self):
  150. e = SubOSErrorWithInit("some message", bar="baz")
  151. self.assertEqual(e.bar, "baz")
  152. self.assertEqual(e.args, ("some message",))
  153. def test_new_overridden(self):
  154. e = SubOSErrorWithNew("some message", "baz")
  155. self.assertEqual(e.baz, "baz")
  156. self.assertEqual(e.args, ("some message",))
  157. def test_new_kwdargs(self):
  158. e = SubOSErrorWithNew("some message", baz="baz")
  159. self.assertEqual(e.baz, "baz")
  160. self.assertEqual(e.args, ("some message",))
  161. def test_init_new_overridden(self):
  162. e = SubOSErrorCombinedInitFirst("some message", "baz")
  163. self.assertEqual(e.bar, "baz")
  164. self.assertEqual(e.baz, "baz")
  165. self.assertEqual(e.args, ("some message",))
  166. e = SubOSErrorCombinedNewFirst("some message", "baz")
  167. self.assertEqual(e.bar, "baz")
  168. self.assertEqual(e.baz, "baz")
  169. self.assertEqual(e.args, ("some message",))
  170. def test_init_standalone(self):
  171. # __init__ doesn't propagate to OSError.__init__ (see issue #15229)
  172. e = SubOSErrorWithStandaloneInit()
  173. self.assertEqual(e.args, ())
  174. self.assertEqual(str(e), '')
  175. if __name__ == "__main__":
  176. unittest.main()