mod_result.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. """
  2. Модуль предоставляет тип результата.
  3. """
  4. from typing import TypeVar
  5. T = TypeVar("T")
  6. class Result[T]:
  7. """
  8. Класс результата. Предоставляет полезный результат, либо ошибку.
  9. Если экземпляр содержит ошибку и не было её получения (либо проверки)
  10. приложение аварийно завершится.
  11. """
  12. __slots__: list[str] = ["__val", "__err", "__is_check"]
  13. def __init__(self, result: T | None = None, err: str | None = None) -> None:
  14. # Инициализируем __is_check до любых возможных exit()
  15. self.__is_check = False
  16. """Признак предварительной проверки ошибки"""
  17. # Результат и ошибка не могут быть вместе None
  18. if result is None and err is None:
  19. print("=" * 80)
  20. print("ERROR: Result.__init__(): called with both result=None and err=None")
  21. print("This indicates a programming error in the code.")
  22. print("=" * 80)
  23. exit(1)
  24. # Результат есть. err не может быть значением
  25. if result is not None and err is not None:
  26. msg = "Result.__init__(): some and err not None."
  27. self.__out(msg)
  28. exit(2)
  29. self.__val: T | None = result
  30. """Содержит результат"""
  31. self.__err: str | None = err
  32. """Содержит ошибку"""
  33. @property
  34. def is_err(self) -> bool:
  35. """
  36. Возвращает признак содержания ошибки.
  37. """
  38. _is_err = self.__err is not None
  39. self.__is_check = True
  40. return _is_err
  41. def hassert(self, msg: str) -> None:
  42. """
  43. Принудительная проверка на отсутствие ошибки/ Если ошибка -- падение.
  44. """
  45. _is_err = self.__err is not None
  46. self.__is_check = True
  47. if _is_err:
  48. print("=" * 80)
  49. print("ERROR: Missing required environment variable!")
  50. print("=" * 80)
  51. print(f"Context: {msg}")
  52. if self.__err:
  53. print(f"Error details: {self.__err}")
  54. print("=" * 80)
  55. self.__out(msg)
  56. exit(4)
  57. @property
  58. def val(self) -> T:
  59. """Возвращает хранимый результат"""
  60. if not self.__is_check:
  61. msg = "Result.val(): result not checked."
  62. self.__out(msg)
  63. exit(3)
  64. if self.__val is None:
  65. msg = "Result.val(): err not None."
  66. self.__out(msg)
  67. exit(4)
  68. return self.__val
  69. @property
  70. def err(self) -> str:
  71. """Возвращает ошибку из результата"""
  72. if self.__err is None:
  73. msg = "Result.err(): error is None."
  74. self.__out(msg)
  75. exit(5)
  76. return self.__err
  77. def __del__(self) -> None:
  78. """Контроль на проверенную ошибку"""
  79. # Проверяем наличие атрибута на случай неполной инициализации
  80. if not hasattr(self, "_Result__is_check"):
  81. return
  82. if self.__is_check:
  83. return
  84. msg = "Result.__del__(): error not checked"
  85. self.__out(msg)
  86. exit(6)
  87. def __out(self, msg: str) -> None:
  88. """Выводит детальную информацию об ошибке"""
  89. print(f"Result error details:")
  90. print(f" Message: {msg}")
  91. if self.__err:
  92. # Извлекаем имя переменной из сообщения об ошибке, если возможно
  93. err_msg = self.__err
  94. if "env " in err_msg and " not set" in err_msg:
  95. # Формат: "env_str(): env VAR_NAME not set"
  96. try:
  97. var_name = err_msg.split("env ")[1].split(" not set")[0]
  98. print(f" Missing environment variable: {var_name}")
  99. except IndexError:
  100. pass
  101. print(f" Error: {err_msg}")
  102. print(f" Result value: {self.__val}")