py_errors.cpp 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. #include "py_errors.h"
  2. #include "py_ptr.h"
  3. #include "py_cast.h"
  4. #include "py_utils.h"
  5. #include <util/generic/string.h>
  6. #include <util/stream/output.h>
  7. namespace NPython {
  8. // this function in conjuction with code after Py_Initialize
  9. // does approximately following:
  10. //
  11. // sys.stderr = StderrProxy(sys.stderr)
  12. //
  13. // ...
  14. //
  15. // sys.stderr._toggle_real_mode()
  16. // sys.excepthook(
  17. // sys.last_type,
  18. // sys.last_value,
  19. // sys.last_traceback)
  20. // sys.stderr._get_value()
  21. // sys.stderr._toggle_real_mode()
  22. //
  23. // where _toggle_real_mode, _get_value & all calls to stderr not in real mode
  24. // are handled in a thread-safe way
  25. //
  26. TString GetLastErrorAsString()
  27. {
  28. PyObject* etype;
  29. PyObject* evalue;
  30. PyObject* etraceback;
  31. PyErr_Fetch(&etype, &evalue, &etraceback);
  32. if (!etype) {
  33. return {};
  34. }
  35. TPyObjectPtr etypePtr {etype, TPyObjectPtr::ADD_REF};
  36. TPyObjectPtr evaluePtr {evalue, TPyObjectPtr::ADD_REF};
  37. TPyObjectPtr etracebackPtr {etraceback, TPyObjectPtr::ADD_REF};
  38. TPyObjectPtr stderrObject {PySys_GetObject("stderr"), TPyObjectPtr::ADD_REF};
  39. if (!stderrObject) {
  40. return {};
  41. }
  42. TPyObjectPtr unused = PyObject_CallMethod(stderrObject.Get(), "_toggle_real_mode", nullptr);
  43. PyErr_Restore(etypePtr.Get(), evaluePtr.Get(), etracebackPtr.Get());
  44. // in unusual situations there may be low-level write to stderr
  45. // (by direct C FILE* write), but that's OK
  46. PyErr_Print();
  47. TPyObjectPtr error = PyObject_CallMethod(stderrObject.Get(), "_get_value", nullptr);
  48. if (!error) {
  49. return {};
  50. }
  51. unused.ResetSteal(
  52. PyObject_CallMethod(stderrObject.Get(), "_toggle_real_mode", nullptr)
  53. );
  54. TString errorValue;
  55. if (!TryPyCast(error.Get(), errorValue)) {
  56. errorValue = TString("can't get error string from: ") += PyObjectRepr(error.Get());
  57. }
  58. return errorValue;
  59. }
  60. } // namspace NPython