Skip to content

Instantly share code, notes, and snippets.

@cb109
Created December 12, 2017 13:25
Show Gist options
  • Save cb109/b99c8d7c627e5238992b5f8a353c79c7 to your computer and use it in GitHub Desktop.
Save cb109/b99c8d7c627e5238992b5f8a353c79c7 to your computer and use it in GitHub Desktop.
Python per-module excepthooks
from .hook import register_module_excepthook
from .hook import install_global_excepthook
def some_module_function_that_may_fail():
raise ValueError("whoops!")
def module_excepthook(type_, value, tb):
print("Gosh, " + __name__ + " has produced an error!")
print(tb)
register_module_excepthook(__name__, module_excepthook)
# This must be called once somewhere in the application.
install_global_excepthook()
"""
sys.excepthook is global, meaning we can only define one at any given time.
Using the functions below we can make the global excepthook handle errors
differently based on the module filepath they came from, effectively giving
us per-module excepthooks.
"""
import os
import re
import sys
import traceback
from StringIO import StringIO
tb_file_regex = r'\"(?P<file>.+)\.py[cod]{0,1}\"'
file_regex = r'(?P<file>.+)\.py[cod]{0,1}'
_excepthook_registry = {}
def install_global_excepthook():
sys.excepthook = _excepthook
def register_module_excepthook(module_name, func):
module = sys.modules[module_name]
module_file = os.path.abspath(module.__file__)
relevant_filename = re.match(file_regex, module_file).group("file")
_excepthook_registry[relevant_filename] = func
def _excepthook(type_, value, tb):
"""Assign this to sys.excepthook to handle per-module-hooks."""
buf = StringIO()
traceback.print_tb(tb, file=buf)
matches = re.findall(tb_file_regex, buf.getvalue())
if not matches:
return
culprit_filepath = matches[-1]
culprit_relevant_filename, _ = os.path.splitext(culprit_filepath)
hook = _excepthook_registry.get(culprit_relevant_filename)
if hook:
hook(type_, value, tb)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment