errorSemantics.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # errorSemantics.py
  2. # Test the Python error handling semantics. Specifically:
  3. #
  4. # * When a Python COM object is called via IDispatch, the nominated
  5. # scode is placed in the exception tuple, and the HRESULT is
  6. # DISP_E_EXCEPTION
  7. # * When the same interface is called via IWhatever, the
  8. # nominated scode is returned directly (with the scode also
  9. # reflected in the exception tuple)
  10. # * In all cases, the description etc end up in the exception tuple
  11. # * "Normal" Python exceptions resolve to an E_FAIL "internal error"
  12. import pythoncom
  13. from win32com.server.exception import COMException
  14. from win32com.server.util import wrap
  15. from win32com.client import Dispatch
  16. import winerror
  17. from win32com.test.util import CaptureWriter
  18. class error(Exception):
  19. def __init__(self, msg, com_exception=None):
  20. Exception.__init__(self, msg, str(com_exception))
  21. # Our COM server.
  22. class TestServer:
  23. _public_methods_ = [ 'Clone', 'Commit', 'LockRegion', 'Read']
  24. _com_interfaces_ = [ pythoncom.IID_IStream ]
  25. def Clone(self):
  26. raise COMException("Not today", scode=winerror.E_UNEXPECTED)
  27. def Commit(self, flags):
  28. raise Exception("foo")
  29. def test():
  30. # Call via a native interface.
  31. com_server = wrap(TestServer(), pythoncom.IID_IStream)
  32. try:
  33. com_server.Clone()
  34. raise error("Expecting this call to fail!")
  35. except pythoncom.com_error as com_exc:
  36. if com_exc.hresult != winerror.E_UNEXPECTED:
  37. raise error("Calling the object natively did not yield the correct scode", com_exc)
  38. exc = com_exc.excepinfo
  39. if not exc or exc[-1] != winerror.E_UNEXPECTED:
  40. raise error("The scode element of the exception tuple did not yield the correct scode", com_exc)
  41. if exc[2] != "Not today":
  42. raise error("The description in the exception tuple did not yield the correct string", com_exc)
  43. cap = CaptureWriter()
  44. try:
  45. cap.capture()
  46. try:
  47. com_server.Commit(0)
  48. finally:
  49. cap.release()
  50. raise error("Expecting this call to fail!")
  51. except pythoncom.com_error as com_exc:
  52. if com_exc.hresult != winerror.E_FAIL:
  53. raise error("The hresult was not E_FAIL for an internal error", com_exc)
  54. if com_exc.excepinfo[1] != "Python COM Server Internal Error":
  55. raise error("The description in the exception tuple did not yield the correct string", com_exc)
  56. # Check we saw a traceback in stderr
  57. if cap.get_captured().find("Traceback")<0:
  58. raise error("Could not find a traceback in stderr: %r" % (cap.get_captured(),))
  59. # Now do it all again, but using IDispatch
  60. com_server = Dispatch(wrap(TestServer()))
  61. try:
  62. com_server.Clone()
  63. raise error("Expecting this call to fail!")
  64. except pythoncom.com_error as com_exc:
  65. if com_exc.hresult != winerror.DISP_E_EXCEPTION:
  66. raise error("Calling the object via IDispatch did not yield the correct scode", com_exc)
  67. exc = com_exc.excepinfo
  68. if not exc or exc[-1] != winerror.E_UNEXPECTED:
  69. raise error("The scode element of the exception tuple did not yield the correct scode", com_exc)
  70. if exc[2] != "Not today":
  71. raise error("The description in the exception tuple did not yield the correct string", com_exc)
  72. cap.clear()
  73. try:
  74. cap.capture()
  75. try:
  76. com_server.Commit(0)
  77. finally:
  78. cap.release()
  79. raise error("Expecting this call to fail!")
  80. except pythoncom.com_error as com_exc:
  81. if com_exc.hresult != winerror.DISP_E_EXCEPTION:
  82. raise error("Calling the object via IDispatch did not yield the correct scode", com_exc)
  83. exc = com_exc.excepinfo
  84. if not exc or exc[-1] != winerror.E_FAIL:
  85. raise error("The scode element of the exception tuple did not yield the correct scode", com_exc)
  86. if exc[1] != "Python COM Server Internal Error":
  87. raise error("The description in the exception tuple did not yield the correct string", com_exc)
  88. # Check we saw a traceback in stderr
  89. if cap.get_captured().find("Traceback")<0:
  90. raise error("Could not find a traceback in stderr: %r" % (cap.get_captured(),))
  91. try:
  92. import logging
  93. except ImportError:
  94. logging = None
  95. if logging is not None:
  96. import win32com
  97. class TestLogHandler(logging.Handler):
  98. def __init__(self):
  99. self.num_emits = 0
  100. logging.Handler.__init__(self)
  101. def emit(self, record):
  102. self.num_emits += 1
  103. return
  104. print("--- record start")
  105. print(self.format(record))
  106. print("--- record end")
  107. def testLogger():
  108. assert not hasattr(win32com, "logger")
  109. handler = TestLogHandler()
  110. formatter = logging.Formatter('%(message)s')
  111. handler.setFormatter(formatter)
  112. log = logging.getLogger("win32com_test")
  113. log.addHandler(handler)
  114. win32com.logger = log
  115. # Now throw some exceptions!
  116. # Native interfaces
  117. com_server = wrap(TestServer(), pythoncom.IID_IStream)
  118. try:
  119. com_server.Commit(0)
  120. raise RuntimeError("should have failed")
  121. except pythoncom.error:
  122. pass
  123. assert handler.num_emits == 1, handler.num_emits
  124. handler.num_emits = 0 # reset
  125. com_server = Dispatch(wrap(TestServer()))
  126. try:
  127. com_server.Commit(0)
  128. raise RuntimeError("should have failed")
  129. except pythoncom.error:
  130. pass
  131. assert handler.num_emits == 1, handler.num_emits
  132. if __name__=='__main__':
  133. test()
  134. if logging is not None:
  135. testLogger()
  136. from .util import CheckClean
  137. CheckClean()
  138. print("error semantic tests worked")