exceptions.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. """Exceptions for nbclient."""
  2. from __future__ import annotations
  3. from typing import Any
  4. from nbformat import NotebookNode
  5. class CellControlSignal(Exception): # noqa
  6. """
  7. A custom exception used to indicate that the exception is used for cell
  8. control actions (not the best model, but it's needed to cover existing
  9. behavior without major refactors).
  10. """
  11. pass
  12. class CellTimeoutError(TimeoutError, CellControlSignal):
  13. """
  14. A custom exception to capture when a cell has timed out during execution.
  15. """
  16. @classmethod
  17. def error_from_timeout_and_cell(
  18. cls, msg: str, timeout: int, cell: NotebookNode
  19. ) -> CellTimeoutError:
  20. """Create an error from a timeout on a cell."""
  21. if cell and cell.source:
  22. src_by_lines = cell.source.strip().split("\n")
  23. src = (
  24. cell.source
  25. if len(src_by_lines) < 11
  26. else f"{src_by_lines[:5]}\n...\n{src_by_lines[-5:]}"
  27. )
  28. else:
  29. src = "Cell contents not found."
  30. return cls(timeout_err_msg.format(timeout=timeout, msg=msg, cell_contents=src))
  31. class DeadKernelError(RuntimeError):
  32. """A dead kernel error."""
  33. pass
  34. class CellExecutionComplete(CellControlSignal):
  35. """
  36. Used as a control signal for cell execution across execute_cell and
  37. process_message function calls. Raised when all execution requests
  38. are completed and no further messages are expected from the kernel
  39. over zeromq channels.
  40. """
  41. pass
  42. class CellExecutionError(CellControlSignal):
  43. """
  44. Custom exception to propagate exceptions that are raised during
  45. notebook execution to the caller. This is mostly useful when
  46. using nbconvert as a library, since it allows to deal with
  47. failures gracefully.
  48. """
  49. def __init__(self, traceback: str, ename: str, evalue: str) -> None:
  50. """Initialize the error."""
  51. super().__init__(traceback)
  52. self.traceback = traceback
  53. self.ename = ename
  54. self.evalue = evalue
  55. def __reduce__(self) -> tuple[Any]:
  56. """Reduce implementation."""
  57. return type(self), (self.traceback, self.ename, self.evalue) # type:ignore[return-value]
  58. def __str__(self) -> str:
  59. """Str repr."""
  60. if self.traceback:
  61. return self.traceback
  62. else:
  63. return f"{self.ename}: {self.evalue}"
  64. @classmethod
  65. def from_cell_and_msg(cls, cell: NotebookNode, msg: dict[str, Any]) -> CellExecutionError:
  66. """Instantiate from a code cell object and a message contents
  67. (message is either execute_reply or error)
  68. """
  69. # collect stream outputs for our error message
  70. stream_outputs: list[str] = []
  71. for output in cell.outputs:
  72. if output["output_type"] == "stream":
  73. stream_outputs.append(
  74. stream_output_msg.format(name=output["name"], text=output["text"].rstrip())
  75. )
  76. if stream_outputs:
  77. # add blank line before, trailing separator
  78. # if there is any stream output to display
  79. stream_outputs.insert(0, "")
  80. stream_outputs.append("------------------")
  81. stream_output: str = "\n".join(stream_outputs)
  82. tb = "\n".join(msg.get("traceback", []) or [])
  83. return cls(
  84. exec_err_msg.format(
  85. cell=cell,
  86. stream_output=stream_output,
  87. traceback=tb,
  88. ),
  89. ename=msg.get("ename", "<Error>"),
  90. evalue=msg.get("evalue", ""),
  91. )
  92. stream_output_msg: str = """\
  93. ----- {name} -----
  94. {text}"""
  95. exec_err_msg: str = """\
  96. An error occurred while executing the following cell:
  97. ------------------
  98. {cell.source}
  99. ------------------
  100. {stream_output}
  101. {traceback}
  102. """
  103. timeout_err_msg: str = """\
  104. A cell timed out while it was being executed, after {timeout} seconds.
  105. The message was: {msg}.
  106. Here is a preview of the cell contents:
  107. -------------------
  108. {cell_contents}
  109. -------------------
  110. """