vinegar.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. """
  2. vinegar ('when things go sour'): safe serialization of exceptions.
  3. note that by changing the configuration parameters, this module can be
  4. made non-secure
  5. """
  6. import sys
  7. import exceptions
  8. import traceback
  9. from types import InstanceType, ClassType
  10. from rpyc.core import brine
  11. from rpyc.core import consts
  12. class GenericException(Exception):
  13. pass
  14. _generic_exceptions_cache = {}
  15. STOP_ITERATION_MAGIC = 0
  16. def dump(typ, val, tb, include_local_traceback):
  17. if type(typ) is str:
  18. return typ
  19. if typ is StopIteration:
  20. return consts.EXC_STOP_ITERATION # optimization
  21. if include_local_traceback:
  22. tbtext = "".join(traceback.format_exception(typ, val, tb))
  23. else:
  24. tbtext = "<traceback denied>"
  25. attrs = []
  26. args = []
  27. for name in dir(val):
  28. if name == "args":
  29. for a in val.args:
  30. if brine.dumpable(a):
  31. args.append(a)
  32. else:
  33. args.append(repr(a))
  34. elif not name.startswith("_") or name == "_remote_tb":
  35. attrval = getattr(val, name)
  36. if not brine.dumpable(attrval):
  37. attrval = repr(attrval)
  38. attrs.append((name, attrval))
  39. return (typ.__module__, typ.__name__), tuple(args), tuple(attrs), tbtext
  40. try:
  41. BaseException
  42. except NameError:
  43. # python 2.4 compatible
  44. BaseException = Exception
  45. def load(val, import_custom_exceptions, instantiate_custom_exceptions, instantiate_oldstyle_exceptions):
  46. if val == consts.EXC_STOP_ITERATION:
  47. return StopIteration # optimization
  48. if type(val) is str:
  49. return val # deprecated string exceptions
  50. (modname, clsname), args, attrs, tbtext = val
  51. if import_custom_exceptions and modname not in sys.modules:
  52. try:
  53. mod = __import__(modname, None, None, "*")
  54. except ImportError:
  55. pass
  56. if instantiate_custom_exceptions:
  57. cls = getattr(sys.modules[modname], clsname, None)
  58. elif modname == "exceptions":
  59. cls = getattr(exceptions, clsname, None)
  60. else:
  61. cls = None
  62. if not isinstance(cls, (type, ClassType)):
  63. cls = None
  64. elif issubclass(cls, ClassType) and not instantiate_oldstyle_exceptions:
  65. cls = None
  66. elif not issubclass(cls, BaseException):
  67. cls = None
  68. if cls is None:
  69. fullname = "%s.%s" % (modname, clsname)
  70. if fullname not in _generic_exceptions_cache:
  71. fakemodule = {"__module__" : "%s.%s" % (__name__, modname)}
  72. if isinstance(GenericException, ClassType):
  73. _generic_exceptions_cache[fullname] = ClassType(fullname, (GenericException,), fakemodule)
  74. else:
  75. _generic_exceptions_cache[fullname] = type(fullname, (GenericException,), fakemodule)
  76. cls = _generic_exceptions_cache[fullname]
  77. # support old-style exception classes
  78. if isinstance(cls, ClassType):
  79. exc = InstanceType(cls)
  80. else:
  81. exc = cls.__new__(cls)
  82. exc.args = args
  83. for name, attrval in attrs:
  84. setattr(exc, name, attrval)
  85. if hasattr(exc, "_remote_tb"):
  86. exc._remote_tb += (tbtext,)
  87. else:
  88. exc._remote_tb = (tbtext,)
  89. return exc
  90. #===============================================================================
  91. # customized except hook
  92. #===============================================================================
  93. if hasattr(sys, "excepthook"):
  94. _orig_excepthook = sys.excepthook
  95. else:
  96. # ironpython forgot to implement excepthook, scheisse
  97. _orig_excepthook = None
  98. def rpyc_excepthook(typ, val, tb):
  99. if hasattr(val, "_remote_tb"):
  100. sys.stderr.write("======= Remote traceback =======\n")
  101. tbtext = "\n--------------------------------\n\n".join(val._remote_tb)
  102. sys.stderr.write(tbtext)
  103. sys.stderr.write("\n======= Local exception ========\n")
  104. _orig_excepthook(typ, val, tb)
  105. def install_rpyc_excepthook():
  106. if _orig_excepthook is not None:
  107. sys.excepthook = rpyc_excepthook
  108. def uninstall_rpyc_excepthook():
  109. if _orig_excepthook is not None:
  110. sys.excepthook = _orig_excepthook