Package: exceptionite
ExceptioniteA Python exception library designed to make handling and displaying exceptions a cinch.Exceptions can be rendered into a beautiful HTML exception page!or in your terminal:Getting StartedFirst install the package:pipinstallexceptioniteThen you can follow instruction for your use case:MasoniteFlaskDjangoDjango REST frameworkPyramidBasic PythonUsage for MasoniteMasonite 4 is already usingexceptionitefor its default error page so you don't have anything
to set up.
If you are usingMasonite < 4.0, please useexceptionite < 2.0.Usage for FlaskIf you are usingFlaskyou can also use this package! Here is an example for a flask application:fromflaskimportFlask,requestfromexceptionite.flaskimportExceptioniteReporterapp=Flask(__name__)@app.errorhandler(Exception)defhandle_exception(exception):handler=ExceptioniteReporter(exception,request)# display exception stack trace nicely in consolehandler.terminal()returnhandler.html()@app.route("/<world>")defhello(world):test="Hello World"return2/0if__name__=="__main__":app.run(debug=True)You'll now see this beautiful exception page:Usage for DjangoYou can customize error reports in Django inDEBUGmode as explained in thedocs.Install the package if you haven't done so yet# settings.py$pipinstallexceptioniteThen simple set a default exception reporter to the exceptionite one. Be careful this reporter
should only be used for local development withDEBUG=True:# myapp/settings.pyifDEBUG:DEFAULT_EXCEPTION_REPORTER="exceptionite.django.ExceptioniteReporter"If you want Django 404 to be also handled by exceptionite you should add an other reporter:# myapp/settings.pyifDEBUG:# handle 404 errorsfromexceptionite.djangoimportExceptionite404ReporterExceptionite404Reporter()# handle all other errorsDEFAULT_EXCEPTION_REPORTER="exceptionite.django.ExceptioniteReporter"Usage for Django REST frameworkYou can also customize error reports when using Django REST framework package inDEBUGmode as explained in thedocs.Install the package if you haven't done so yet# settings.py$pipinstallexceptioniteThen simple set the REST default exception reporter to the exceptionite one:# myapp/settings.pyifDEBUG:REST_FRAMEWORK={"EXCEPTION_HANDLER":"exceptionite.django.drf_exception_handler"}Now when doing API requests acceptingapplication/jsona JSON debug error page
will be returned. When using the Django REST framework browsable API or accessing a GET endpoint from your browser (text/html) the HTML exceptionite page will be
displayed !:warning: Note that this handler will change exception handling behaviour and should be only used when DEBUG mode is enabled.If you want to customize exception handling for other cases you can do:# app/exception_handler.pyfromexceptionite.djangoimportdrf_exception_handlerdefcustom_handler(exc,context):# do what you want hereresponse=drf_exception_handler(exc,context)# do what you want herereturnresponse# myapp/settings.pyREST_FRAMEWORK={"EXCEPTION_HANDLER":"myapp.exception_handler.custom_handler"}Usage for PyramidIf you are usingPyramidyou can also use this package! You just need to register two handlers
function to handle 404 and any other errors.Here is an example for a simple pyramid application:fromwsgiref.simple_serverimportmake_serverfrompyramid.configimportConfiguratorfrompyramid.responseimportResponsefrompyramid.viewimportexception_view_config,notfound_view_configfromexceptioniteimportHandlerhandler=Handler()@exception_view_config(Exception)defhandle_all_exceptions(exc,request):handler.start(exc)handler.render("terminal")response=Response(handler.render("web"))response.status_int=500returnresponse@notfound_view_config()defhandle_404(exc,request):handler.start(exc)handler.render("terminal")response=Response(handler.render("web"))response.status_int=404returnresponsedefhello_world(request):1/0returnResponse("Hello World!")if__name__=="__main__":withConfigurator()asconfig:config.add_route("hello","/")config.add_view(hello_world,route_name="hello")# this line below is very important to scan our decorated error handlersconfig.scan()app=config.make_wsgi_app()server=make_server("127.0.0.1",8000,app)server.serve_forever()Usage for PythonIf you are not using a specific framework you can still use this library. You just have to get
an instance of theHandlerclass and use thestart()method to start handling the exception.Then you can get useful information easily and also define how you want to render the error. You
can even add your own renderer.fromexceptioniteimportHandlertry:2/0exceptExceptionase:handler=Handler()handler.start(e)Once you have the handler class theres a whole bunch of things we can now do!Getting Exception DetailsGetting the exception name:handler.exception()#== ZeroDivisionErrorGetting the exception message:handler.message()#== cannot divide by 0Getting the exception namespace:handler.namespace()#== builtins.ZeroDivisionErrorRendering an HTML pageYou can render an elegant exception page by using therendermethod with theWebRenderer:handler.render("web")#== <html> ... </html>If you have a framework or an application you can swap the exception handler out with this handler
and then call this method.Adding ContextSometimes you will need to add more information to the exception page. This is where contexts come into play. Contexts are the ability to add any information you need to help you debug information.If you use a framework like Masonite you might want to see information related to your Service Providers. If you use a framework like django you might want to see a list of your installed apps.On the left side of the page below the stack trace you will find the context menu. Context is organised into blocks.You can register new contexts quickly by supplying a dictionary or a callable providing a dictionary:importsyshandler.renderer("web").context("System Variables",{"sys argv":sys.argv})Or youcan create custom blocksand add them to theContexttab:importsysfromexceptioniteimportBlockclassSystemVarsBlock(Block):id="system_vars"name="System Variables"defbuild(self):return{"sys argv":sys.argv}handler.renderer("web").tab("context").add_blocks(SystemVarsBlock)The second method allows to customize the block.Hiding Sensitive DataExceptionite is configured by default to scrub data displayed in tab and blocks. This allows hiding sensitive data, by replacing it with*****.Hiding sensitive data can be disabled globally in handler options withoptions.hide_sensitive_data.It can also be disabled per block by settingdisable_scrubbing = Trueinblock class.The keywords defined to find sensitive data can be edited:# define a new set of keywordshandler.set_scrub_keywords(["app_secret","pwd"])# add new keywordshandler.add_scrub_keywords(["app_secret","pwd"])You can see the default keywords by accessinghandler.scrub_keywords.ConfigurationOptionsTheexceptionitehandler comes with the default options below:{"options":{"editor":"vscode","search_url":"https://www.google.com/search?q=","links":{"doc":"https://docs.masoniteproject.com","repo":"https://github.com/MasoniteFramework/masonite",},"stack":{"offset":8,"shorten":True},"hide_sensitive_data":True},"handlers":{"context":True,"solutions":{"stackoverflow":False,"possible_solutions":True},"recommendations":{"packages_updates":{"list":["exceptionite"]}},},}You can configure it by usingset_options(options)method:fromexceptioniteimportHandler,DefaultOptionshandler=Handler()options=DefaultOptionsoptions.get("options").update({"search_url":"https://duckduckgo.com/?q="})handler.set_options(options)For Masonite, options are defined inexceptions.pyconfiguration file.RenderersWhen an error is caught by Exceptionite, it can be rendered in many ways through configured renderers. Available renderers are:WebRenderer: renders the exception as a beautiful HTML error pageTerminalRenderer: renders the exception nicely in the consoleJSONRenderer: renders the exception as a JSON payload (useful for API errors handling)A renderer is a simple Python class withbuild()andrender()methods. Feel free to create
your own one if needed !classCustomRenderer:def__init__(self,handler:"Handler"):self.handler=handlerself.data=Nonedefbuild(self):exception=self.handler.exception()stack=self.handler.stacktrace()# build data from exception here...data=...returndatadefrender(self)->str:self.data=self.build()# render the data as you wantreturnTo add a renderer:handler.add_renderer("json",JSONRenderer)Then to render the exception using the renderer:handler.render("json")#== [{"exception": ...}]Web Renderer Specific OptionsThe HTML exception page created with the WebRenderer is highly configurable:Search engine used to search the error message on the web:"options":{"search_url":"https://www.google.com/search?q="# ...}Editor used to open the line on the stack trace at click:"options":{"editor":"sublime"# ...}Available editors arevscode,pycharm,idea,sublime,atom,textmate,emacs,macvim,vscodium.Navbar links to documentation and repository can be customized:"options":{"links":{"doc":"https://docs.masoniteproject.com","repo":"https://github.com/MasoniteFramework/exceptionite",},}Tabs can be disabled. To disablesolutionstab:"handlers":{"solutions":False}New tabs can be added:handler.renderer("web").add_tabs(DumpsTab)Blocks and Tabs APITabA tab is defined with the following attributes:id (str): slug of the tab that should be unique, and used to access it from handlername (str): name of the tab displayed in the error pageicon (str): icon of the tab displayed in the error page (available icons are definedhere. The name should be converted to UpperCamelCase.)advertise_content (bool): ifTruea animated dot will be displayed in error page navbar, ifhas_content()method returnsTruedisable_scrubbing (bool): ifTrue, data won't be scrubbed, meaning thatsensitive datawon't be hidden.and with the following methods (that can be overriden):has_content(): should returns aboolthat indicates if tab has content.BlockA block is located in a tab. A tab can have many blocks. Blocks are added to tab in the following manner:classContextTab(Tab):name="Context"id="context"icon="ViewListIcon"def__init__(self,handler):super().__init__(handler)self.add_blocks(Environment,Packages,Git)# ORhandler.renderer("web").tab("context").add_blocks(Environment,Packages,Git)A block is defined with the following attributes:id (str): slug of the block that should be unique, and used to access it from handlername (str): name of the block displayed in the error pageicon (str): icon of the block displayed in the error page (available icons are definedhere. The name should be converted to UpperCamelCase.)disable_scrubbing (bool): ifTrue, data won't be scrubbed, meaning thatsensitive datawon't be hidden.empty_msg (str): message that will be displayed if block data is empty.has_sections (bool): enable this to render dict as sections, where each root key is a section title and value is a nested dict.and with the following methods:build(): must be implemented and should returns data that can be serialized. This data will be provided to the Vue block component.has_content(): should returns aboolthat indicates if tab has content.ContributingPlease read theContributing Documentationhere.MaintainersJoseph MancusoSamuel GirardinLicenseExceptionite is open-sourced software licensed under theMIT license.