_result.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """
  2. Hook wrapper "result" utilities.
  3. """
  4. from __future__ import annotations
  5. from types import TracebackType
  6. from typing import Callable
  7. from typing import cast
  8. from typing import final
  9. from typing import Generic
  10. from typing import Optional
  11. from typing import TypeVar
  12. _ExcInfo = tuple[type[BaseException], BaseException, Optional[TracebackType]]
  13. ResultType = TypeVar("ResultType")
  14. class HookCallError(Exception):
  15. """Hook was called incorrectly."""
  16. @final
  17. class Result(Generic[ResultType]):
  18. """An object used to inspect and set the result in a :ref:`hook wrapper
  19. <hookwrappers>`."""
  20. __slots__ = ("_result", "_exception", "_traceback")
  21. def __init__(
  22. self,
  23. result: ResultType | None,
  24. exception: BaseException | None,
  25. ) -> None:
  26. """:meta private:"""
  27. self._result = result
  28. self._exception = exception
  29. # Exception __traceback__ is mutable, this keeps the original.
  30. self._traceback = exception.__traceback__ if exception is not None else None
  31. @property
  32. def excinfo(self) -> _ExcInfo | None:
  33. """:meta private:"""
  34. exc = self._exception
  35. if exc is None:
  36. return None
  37. else:
  38. return (type(exc), exc, self._traceback)
  39. @property
  40. def exception(self) -> BaseException | None:
  41. """:meta private:"""
  42. return self._exception
  43. @classmethod
  44. def from_call(cls, func: Callable[[], ResultType]) -> Result[ResultType]:
  45. """:meta private:"""
  46. __tracebackhide__ = True
  47. result = exception = None
  48. try:
  49. result = func()
  50. except BaseException as exc:
  51. exception = exc
  52. return cls(result, exception)
  53. def force_result(self, result: ResultType) -> None:
  54. """Force the result(s) to ``result``.
  55. If the hook was marked as a ``firstresult`` a single value should
  56. be set, otherwise set a (modified) list of results. Any exceptions
  57. found during invocation will be deleted.
  58. This overrides any previous result or exception.
  59. """
  60. self._result = result
  61. self._exception = None
  62. self._traceback = None
  63. def force_exception(self, exception: BaseException) -> None:
  64. """Force the result to fail with ``exception``.
  65. This overrides any previous result or exception.
  66. .. versionadded:: 1.1.0
  67. """
  68. self._result = None
  69. self._exception = exception
  70. self._traceback = exception.__traceback__ if exception is not None else None
  71. def get_result(self) -> ResultType:
  72. """Get the result(s) for this hook call.
  73. If the hook was marked as a ``firstresult`` only a single value
  74. will be returned, otherwise a list of results.
  75. """
  76. __tracebackhide__ = True
  77. exc = self._exception
  78. tb = self._traceback
  79. if exc is None:
  80. return cast(ResultType, self._result)
  81. else:
  82. raise exc.with_traceback(tb)
  83. # Historical name (pluggy<=1.2), kept for backward compatibility.
  84. _Result = Result