{"id":17703812,"url":"https://github.com/masoniteframework/exceptionite","last_synced_at":"2025-05-16T12:11:49.681Z","repository":{"id":37982570,"uuid":"227259824","full_name":"MasoniteFramework/exceptionite","owner":"MasoniteFramework","description":"A Python Exception Library. Designed to make handling and displaying exceptions a cinch.","archived":false,"fork":false,"pushed_at":"2025-03-24T05:58:22.000Z","size":6652,"stargazers_count":126,"open_issues_count":13,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-07T06:03:23.994Z","etag":null,"topics":["exception-handler","flask","html-page","masonite","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MasoniteFramework.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-11T02:34:55.000Z","updated_at":"2025-03-19T22:55:00.000Z","dependencies_parsed_at":"2024-06-19T03:18:35.679Z","dependency_job_id":"8ec2f877-7d94-450e-9c9b-6af84296b04e","html_url":"https://github.com/MasoniteFramework/exceptionite","commit_stats":{"total_commits":167,"total_committers":4,"mean_commits":41.75,"dds":0.4730538922155688,"last_synced_commit":"dd615bb5cbdc5fdc68ce33c3eae0e67411b5462a"},"previous_names":["masoniteframework/exceptions"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasoniteFramework%2Fexceptionite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasoniteFramework%2Fexceptionite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasoniteFramework%2Fexceptionite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasoniteFramework%2Fexceptionite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MasoniteFramework","download_url":"https://codeload.github.com/MasoniteFramework/exceptionite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247601447,"owners_count":20964864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["exception-handler","flask","html-page","masonite","python"],"created_at":"2024-10-24T21:06:03.268Z","updated_at":"2025-04-07T06:04:02.079Z","avatar_url":"https://github.com/MasoniteFramework.png","language":"Python","readme":"\n# Exceptionite\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://docs.masoniteproject.com\"\u003e\n    \u003cimg alt=\"Masonite Package\" src=\"https://img.shields.io/static/v1?label=Masonite\u0026message=package\u0026labelColor=grey\u0026color=blue\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAA6gAwAEAAAAAQAAAA4AAAAATspU+QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAAAnxJREFUKBVNUl1IVEEUPjPObdd1VdxWM0rMIl3bzbVWLSofVm3th0AhMakHHyqRiNSHEAq5b2HSVvoQRUiEECQUQkkPbRslRGigG8auoon2oPSjpev+3PWeZq7eaC5nDt93vplz5txDQJYpNxX4st4JFiwj9aCqmswUFQNS/A2YskrZJPYefkECC2GhQwAqvLYybwXrwBvq8HSNOXRO92+aH7nW8vc/wS2Z9TqneYt2KHjlf9Iv+43wFJMExzO0YE5OKe60N+AOW6OmE+WJTBrg23jjzWxMBauOlfyycsV24F+cH+zAXYUOGl+DaiDxfl245/W9OnVrSY+O2eqPkyz4sVvHoKp9gOihf5KoAVv3hkQgbj/ihG9fI3RixKcUVx7lJVaEc0vnyf2FFll+ny80ZHZiGhIKowWJBCEAKr+FSuNDLt+lxybSF51lo74arqs113dOZqwsptxNs5bwi7Q3q8npSC2AWmvjTncZf1l61e5DEizNn5mtufpsqk5+CZTuq00sP1wkNPv8jeEikVVlJso+GEwRtNs3QeBt2YP2V2ZI3Tx0e+7T89zK5tNASOLEytJAryGtkLc2PcBM5byyUWYkMQpMioYcDcchC6xN220Iv36Ot8pV0454RHLEwmmD7UWfIdX0zq3GjMPG5NKBtv5qiPEPekK2U51j1451BZoc3i+1ohSQ/UzzG5uYFFn2mwVUnO4O3JblXA91T51l3pB3QweDl7sNXMyEjbguSjrPcQNmwDkNc8CbCvDd0+xCC7RFi9wFulD3mJeXqxQevB4prrqgc0TmQ85NG/K43e2UwnMVAJIEBNfWRYR3HfnvivrIzMyo4Hgy+hfscvLo53jItAAAAABJRU5ErkJggg==\"\u003e\n  \u003c/a\u003e\n  \u003cimg alt=\"GitHub Workflow Status\" src=\"https://img.shields.io/github/workflow/status/MasoniteFramework/exceptionite/Test%20Application\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/python-3.7+-blue.svg\" alt=\"Python Version\"\u003e\n  \u003cimg alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/exceptionite\"\u003e\n  \u003cimg alt=\"License\" src=\"https://img.shields.io/github/license/MasoniteFramework/exceptionite\"\u003e\n  \u003ca href=\"https://github.com/psf/black\"\u003e\u003cimg alt=\"Code style: black\" src=\"https://img.shields.io/badge/code%20style-black-000000.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA Python exception library designed to make handling and displaying exceptions a cinch.\n\nExceptions can be rendered into a beautiful HTML exception page!\n\n![](screenshots/masonite_1.png)\n![](screenshots/masonite_2.png)\n\nor in your terminal:\n\n![](screenshots/terminal_handler.png)\n\n\n# Getting Started\n\nFirst install the package:\n\n```bash\npip install exceptionite\n```\n\nThen you can follow instruction for your use case:\n\n- [Masonite](#usage-for-masonite)\n- [Flask](#usage-for-flask)\n- [Django](#usage-for-django)\n- [Django REST framework](#usage-for-django-rest-framework)\n- [Pyramid](#usage-for-pyramid)\n- [Basic Python](#usage-for-python)\n\n## Usage for Masonite\n\nMasonite 4 is already using `exceptionite` for its default error page so you don't have anything\nto set up.\nIf you are using `Masonite \u003c 4.0`, please use `exceptionite \u003c 2.0`.\n\n## Usage for Flask\n\nIf you are using `Flask` you can also use this package! Here is an example for a flask application:\n\n```python\nfrom flask import Flask, request\nfrom exceptionite.flask import ExceptioniteReporter\n\napp = Flask(__name__)\n\n\n@app.errorhandler(Exception)\ndef handle_exception(exception):\n    handler = ExceptioniteReporter(exception, request)\n    # display exception stack trace nicely in console\n    handler.terminal()\n    return handler.html()\n\n\n@app.route(\"/\u003cworld\u003e\")\ndef hello(world):\n    test = \"Hello World\"\n    return 2 / 0\n\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n```\n\nYou'll now see this beautiful exception page:\n![](screenshots/flask_1.png)\n![](screenshots/flask_2.png)\n\n\n## Usage for Django\n\nYou can customize error reports in Django in `DEBUG` mode as explained in the [docs](https://docs.djangoproject.com/en/3.2/howto/error-reporting/#custom-error-reports).\n\nInstall the package if you haven't done so yet\n\n```python\n# settings.py\n$ pip install exceptionite\n```\n\nThen simple set a default exception reporter to the exceptionite one. Be careful this reporter\nshould only be used for local development with `DEBUG=True`:\n\n```python\n# myapp/settings.py\nif DEBUG:\n    DEFAULT_EXCEPTION_REPORTER = \"exceptionite.django.ExceptioniteReporter\"\n```\n\nIf you want Django 404 to be also handled by exceptionite you should add an other reporter:\n\n```python\n# myapp/settings.py\nif DEBUG:\n    # handle 404 errors\n    from exceptionite.django import Exceptionite404Reporter\n\n    Exceptionite404Reporter()\n\n    # handle all other errors\n    DEFAULT_EXCEPTION_REPORTER = \"exceptionite.django.ExceptioniteReporter\"\n```\n\n## Usage for Django REST framework\n\nYou can also customize error reports when using Django REST framework package in `DEBUG` mode as explained in the [docs](https://www.django-rest-framework.org/api-guide/exceptions/).\n\nInstall the package if you haven't done so yet\n\n```python\n# settings.py\n$ pip install exceptionite\n```\n\nThen simple set the REST default exception reporter to the exceptionite one:\n\n```python\n# myapp/settings.py\nif DEBUG:\n    REST_FRAMEWORK = {\n        \"EXCEPTION_HANDLER\": \"exceptionite.django.drf_exception_handler\"\n    }\n```\n\nNow when doing API requests accepting `application/json` a JSON debug error page\nwill 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\ndisplayed !\n\n:warning: Note that this handler will change exception handling behaviour and should be only used when DEBUG mode is enabled.\n\nIf you want to customize exception handling for other cases you can do:\n\n```python\n# app/exception_handler.py\nfrom exceptionite.django import drf_exception_handler\n\ndef custom_handler(exc, context):\n    # do what you want here\n\n    response = drf_exception_handler(exc, context)\n\n    # do what you want here\n    return response\n```\n\n```python\n# myapp/settings.py\n\nREST_FRAMEWORK = {\n    \"EXCEPTION_HANDLER\": \"myapp.exception_handler.custom_handler\"\n}\n```\n\n## Usage for Pyramid\n\nIf you are using `Pyramid` you can also use this package! You just need to register two handlers\nfunction to handle 404 and any other errors.\n\nHere is an example for a simple pyramid application:\n\n```python\nfrom wsgiref.simple_server import make_server\nfrom pyramid.config import Configurator\nfrom pyramid.response import Response\nfrom pyramid.view import exception_view_config, notfound_view_config\n\nfrom exceptionite import Handler\n\nhandler = Handler()\n\n\n@exception_view_config(Exception)\ndef handle_all_exceptions(exc, request):\n    handler.start(exc)\n    handler.render(\"terminal\")\n    response = Response(handler.render(\"web\"))\n    response.status_int = 500\n    return response\n\n\n@notfound_view_config()\ndef handle_404(exc, request):\n    handler.start(exc)\n    handler.render(\"terminal\")\n    response = Response(handler.render(\"web\"))\n    response.status_int = 404\n    return response\n\ndef hello_world(request):\n    1 / 0\n    return Response(\"Hello World!\")\n\n\nif __name__ == \"__main__\":\n    with Configurator() as config:\n        config.add_route(\"hello\", \"/\")\n        config.add_view(hello_world, route_name=\"hello\")\n        # this line below is very important to scan our decorated error handlers\n        config.scan()\n        app = config.make_wsgi_app()\n    server = make_server(\"127.0.0.1\", 8000, app)\n    server.serve_forever()\n```\n\n## Usage for Python\n\nIf you are not using a specific framework you can still use this library. You just have to get\nan instance of the `Handler` class and use the `start()` method to start handling the exception.\n\nThen you can get useful information easily and also define how you want to render the error. You\ncan even add your own renderer.\n\n```python\nfrom exceptionite import Handler\n\ntry:\n    2/0\nexcept Exception as e:\n    handler = Handler()\n    handler.start(e)\n```\n\nOnce you have the handler class theres a whole bunch of things we can now do!\n\n### Getting Exception Details\n\nGetting the exception name:\n\n```python\nhandler.exception() #== ZeroDivisionError\n```\n\nGetting the exception message:\n\n```python\nhandler.message() #== cannot divide by 0\n```\n\nGetting the exception namespace:\n\n```python\nhandler.namespace() #== builtins.ZeroDivisionError\n```\n\n### Rendering an HTML page\n\nYou can render an elegant exception page by using the `render` method with the [WebRenderer](#renderers):\n\n```python\nhandler.render(\"web\") #== \u003chtml\u003e ... \u003c/html\u003e\n```\n\nIf you have a framework or an application you can swap the exception handler out with this handler\nand then call this method.\n\n### Adding Context\n\nSometimes 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.\n\nIf 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.\n\nOn the left side of the page below the stack trace you will find the context menu. Context is organised into blocks.\n\n1. You can register new contexts quickly by supplying a dictionary or a callable providing a dictionary:\n\n```python\nimport sys\n\nhandler.renderer(\"web\").context(\"System Variables\", {\"sys argv\": sys.argv})\n```\n\n2. Or you [can create custom blocks](#block) and add them to the `Context` tab:\n\n```python\nimport sys\nfrom exceptionite import Block\n\nclass SystemVarsBlock(Block):\n    id = \"system_vars\"\n    name= \"System Variables\"\n\n    def build(self):\n        return {\n           \"sys argv\": sys.argv\n        }\n\nhandler.renderer(\"web\").tab(\"context\").add_blocks(SystemVarsBlock)\n```\n\nThe second method allows to customize the block.\n\n### Hiding Sensitive Data\n\nExceptionite is configured by default to scrub data displayed in tab and blocks. This allows hiding sensitive data, by replacing it with `*****`.\n\nHiding sensitive data can be disabled globally in handler options with `options.hide_sensitive_data`.\n\nIt can also be disabled per block by setting `disable_scrubbing = True` in [block class](#block).\n\nThe keywords defined to find sensitive data can be edited:\n\n```python\n# define a new set of keywords\nhandler.set_scrub_keywords([\"app_secret\", \"pwd\"])\n# add new keywords\nhandler.add_scrub_keywords([\"app_secret\", \"pwd\"])\n```\n\nYou can see the default keywords by accessing `handler.scrub_keywords`.\n\n\n# Configuration\n\n## Options\n\nThe `exceptionite` handler comes with the default options below:\n```python\n{\n    \"options\": {\n        \"editor\": \"vscode\",\n        \"search_url\": \"https://www.google.com/search?q=\",\n        \"links\": {\n            \"doc\": \"https://docs.masoniteproject.com\",\n            \"repo\": \"https://github.com/MasoniteFramework/masonite\",\n        },\n        \"stack\": {\"offset\": 8, \"shorten\": True},\n        \"hide_sensitive_data\": True\n    },\n    \"handlers\": {\n        \"context\": True,\n        \"solutions\": {\"stackoverflow\": False, \"possible_solutions\": True},\n        \"recommendations\": {\"packages_updates\": {\"list\": [\"exceptionite\"]}},\n    },\n}\n```\n\nYou can configure it by using `set_options(options)` method:\n```python\nfrom exceptionite import Handler, DefaultOptions\n\nhandler = Handler()\noptions = DefaultOptions\noptions.get(\"options\").update({\"search_url\": \"https://duckduckgo.com/?q=\"})\nhandler.set_options(options)\n```\n\nFor Masonite, options are defined in `exceptions.py` configuration file.\n\n## Renderers\n\nWhen an error is caught by Exceptionite, it can be rendered in many ways through configured renderers. Available renderers are:\n- WebRenderer: renders the exception as a beautiful HTML error page\n- TerminalRenderer: renders the exception nicely in the console\n- JSONRenderer: renders the exception as a JSON payload (useful for API errors handling)\n\nA renderer is a simple Python class with `build()` and `render()` methods. Feel free to create\nyour own one if needed !\n```python\nclass CustomRenderer:\n    def __init__(self, handler: \"Handler\"):\n        self.handler = handler\n        self.data = None\n\n    def build(self):\n        exception = self.handler.exception()\n        stack = self.handler.stacktrace()\n        # build data from exception here...\n        data = ...\n        return data\n\n    def render(self) -\u003e str:\n        self.data = self.build()\n        # render the data as you want\n        return\n```\n\nTo add a renderer:\n```python\nhandler.add_renderer(\"json\", JSONRenderer)\n```\n\nThen to render the exception using the renderer:\n```python\nhandler.render(\"json\") #== [{\"exception\": ...}]\n```\n\n\n## Web Renderer Specific Options\n\nThe HTML exception page created with the WebRenderer is highly configurable:\n\n- Search engine used to search the error message on the web:\n```python\n\"options\": {\n    \"search_url\": \"https://www.google.com/search?q=\"\n    # ...\n}\n```\n- Editor used to open the line on the stack trace at click:\n\n```python\n\"options\": {\n    \"editor\": \"sublime\"\n    # ...\n}\n```\n\nAvailable editors are `vscode`, `pycharm`, `idea`, `sublime`, `atom`, `textmate`, `emacs`, `macvim`, `vscodium`.\n\n- Navbar links to documentation and repository can be customized:\n\n```python\n\"options\": {\n    \"links\": {\n        \"doc\": \"https://docs.masoniteproject.com\",\n        \"repo\": \"https://github.com/MasoniteFramework/exceptionite\",\n    },\n}\n```\n\n- Tabs can be disabled. To disable `solutions` tab:\n```python\n\"handlers\": {\n    \"solutions\": False\n}\n```\n\n- New tabs can be added:\n```python\nhandler.renderer(\"web\").add_tabs(DumpsTab)\n```\n\n\n### Blocks and Tabs API\n\n#### Tab\n\nA tab is defined with the following attributes:\n- `id (str)`: slug of the tab that should be unique, and used to access it from handler\n- `name (str)`: name of the tab displayed in the error page\n- `icon (str)`: icon of the tab displayed in the error page (available icons are defined [here](https://heroicons.com/). The name should be converted to UpperCamelCase.)\n- `advertise_content (bool)`: if `True` a animated dot will be displayed in error page navbar, if `has_content()` method returns `True`\n- `disable_scrubbing (bool)`: if `True`, data won't be scrubbed, meaning that [sensitive data](#hiding-sensitive-data) won't be hidden.\n\nand with the following methods (that can be overriden):\n- `has_content()`: should returns a `bool` that indicates if tab has content.\n\n\n#### Block\n\nA block is located in a tab. A tab can have many blocks. Blocks are added to tab in the following manner:\n```python\nclass ContextTab(Tab):\n\n    name = \"Context\"\n    id = \"context\"\n    icon = \"ViewListIcon\"\n\n    def __init__(self, handler):\n        super().__init__(handler)\n        self.add_blocks(Environment, Packages, Git)\n# OR\nhandler.renderer(\"web\").tab(\"context\").add_blocks(Environment, Packages, Git)\n```\n\nA block is defined with the following attributes:\n- `id (str)`: slug of the block that should be unique, and used to access it from handler\n- `name (str)`: name of the block displayed in the error page\n- `icon (str)`: icon of the block displayed in the error page (available icons are defined [here](https://heroicons.com/). The name should be converted to UpperCamelCase.)\n- `disable_scrubbing (bool)`: if `True`, data won't be scrubbed, meaning that [sensitive data](#hiding-sensitive-data) won't be hidden.\n- `empty_msg (str)`: message that will be displayed if block data is empty.\n- `has_sections (bool)`: enable this to render dict as sections, where each root key is a section title and value is a nested dict.\n\nand with the following methods:\n\n- `build()`: must be implemented and should returns data that can be serialized. This data will be provided to the Vue block component.\n- `has_content()`: should returns a `bool` that indicates if tab has content.\n\n\n# Contributing\n\nPlease read the [Contributing Documentation](CONTRIBUTING.md) here.\n\n# Maintainers\n\n- [Joseph Mancuso](https://github.com/josephmancuso)\n- [Samuel Girardin](https://www.github.com/girardinsamuel)\n\n# License\n\nExceptionite is open-sourced software licensed under the [MIT license](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasoniteframework%2Fexceptionite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmasoniteframework%2Fexceptionite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasoniteframework%2Fexceptionite/lists"}