{"id":34082450,"url":"https://github.com/nsarang/pymortem","last_synced_at":"2026-04-24T10:04:44.585Z","repository":{"id":293432550,"uuid":"983718186","full_name":"nsarang/pymortem","owner":"nsarang","description":"Post-mortem debugging tool for Python that provides direct access to variables and frames after exceptions occur. Rich tracebacks, frame inspection, and context execution without separate interactive shells.","archived":false,"fork":false,"pushed_at":"2025-05-16T20:55:15.000Z","size":41,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-16T14:32:59.405Z","etag":null,"topics":["debugger","developer-tools","error-analysis","exception-handling","jupyter","post-mortem","python-debugging","traceback"],"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/nsarang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-14T20:06:07.000Z","updated_at":"2025-07-20T19:02:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"b534700b-a503-42b7-8e10-8a016fc73d8d","html_url":"https://github.com/nsarang/pymortem","commit_stats":null,"previous_names":["nsarang/pymortem"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/nsarang/pymortem","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarang%2Fpymortem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarang%2Fpymortem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarang%2Fpymortem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarang%2Fpymortem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nsarang","download_url":"https://codeload.github.com/nsarang/pymortem/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarang%2Fpymortem/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32218290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T09:47:08.147Z","status":"ssl_error","status_checked_at":"2026-04-24T09:46:41.165Z","response_time":64,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["debugger","developer-tools","error-analysis","exception-handling","jupyter","post-mortem","python-debugging","traceback"],"created_at":"2025-12-14T12:16:30.565Z","updated_at":"2026-04-24T10:04:44.580Z","avatar_url":"https://github.com/nsarang.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pymortem: Advanced Python Debugging\n\n\u003cdiv align=\"center\"\u003e\n\n[![PyPI](https://img.shields.io/pypi/v/pymortem?logoSize=auto)](https://pypi.org/project/pymortem/)\n[![Python Versions](https://img.shields.io/pypi/pyversions/pymortem?logoSize=auto)](https://pypi.org/project/pymortem/)\n![License](https://img.shields.io/pypi/l/pymortem?logo=auto)\n[![Codecov](https://codecov.io/gh/nsarang/pymortem/branch/main/graph/badge.svg)](https://codecov.io/gh/nsarang/pymortem)\n\n\u003c/div\u003e\n\nPymortem is a post-mortem debugging tool that lets you inspect and manipulate execution contexts after exceptions occur. Unlike traditional debuggers that require a separate interactive shell, pymortem gives you direct access to all variables and frames in the exception stack, making it valuable in Jupyter notebooks and interactive environments.\n\n\u003e This package evolved from an educational [blog post](https://nimasarang.com/blog/2025-01-30-post-mortem/) on post-mortem debugging techniques. What began as educational code examples has been refined into a practical debugging library.\n\n## Installation\n\n```bash\npip install pymortem\n```\n\n## Features\n\n- **Enhanced Tracebacks**: Rich, visual traceback output showing code context around errors with line numbers and error indicators\n- **Frame Inspection**: Directly examine variables at any level in the call stack without navigating through a separate command interface\n- **Code Execution in Context**: Run arbitrary code in the context of any stack frame without restarting your program\n- **Chained Exception Support**: Clear visualization of exception chains, showing both \"raised from\" and \"during handling\" relationships\n- **No Special Setup**: Works with standard Python without requiring breakpoints or special execution modes\n\n## Usage\n\n### Examining an Exception after it Occurs\n\n```python\n# In one cell where an error happens:\ndef foo():\n    x = 10\n    output = x / 0\n    return output\n\nfoo()\n```\n\n```python\n# In the next cell, examine the exception:\nimport pymortem\n\n# Get enhanced traceback and frame information\ntraceback_msg, frames = pymortem.extract_from_exception()\n\n# Display the improved traceback\nprint(traceback_msg)\n```\n\n### Inspecting Variables in the Error Context\n\n```python\n# After running the above cells\n# Let's examine the local variables in different frames\n\n# The frame where the error occurred\nprint(\"Locals in error frame:\", frames[-1][\"locals\"])\n\n# Check global variables too\nprint(\"Some globals:\", {k: v for k, v in list(frames[-1][\"globals\"].items())[:5]})\n```\n\n### Executing Code in a Frame's Context\n\n```python\nimport pymortem\nimport sys\n\n# Get the most recent exception\nexception = pymortem.retrieve_the_last_exception() # Store the exception\n_, frames = pymortem.extract_from_exception(exception)\n\n# Choose a frame to work with (e.g., frames[1] for a specific frame)\nwork_frame = frames[-1]\n\n# Execute code in that frame's context\npymortem.execute(\n    \"\"\"\n    # You can access all variables that existed when the error occurred\n    print(\"Available variables:\", list(locals().keys()))\n\n    # Test potential fixes without rerunning the entire notebook\n    try:\n        # Try a fix for a ZeroDivisionError\n        denominator = 2  # Was 0 before\n        fixed_result = x / denominator\n        print(f\"Fix worked! Result = {fixed_result}\")\n    except Exception as e:\n        print(f\"Fix didn't work: {e}\")\n    \"\"\",\n    work_frame\n)\n```\n\n### Handling Chained Exceptions\n\n```python\n# Create a chained exception scenario\ntry:\n    try:\n        x = {\"key\": \"value\"}\n        result = x[\"missing_key\"]  # Will raise KeyError\n    except KeyError:\n        result = 10 + \"0\"  # Will raise ValueError\nexcept Exception as e:\n    chain_exception = e\n\n# Examine the exception chain\ntraceback_msg, all_frames = pymortem.extract_from_exception(chain_exception)\nprint(traceback_msg)\nprint(\"\")\n\n# Frames are arranged in chronological order, with the first exception first\noriginal_error_frame = all_frames[0]  # Frame from the KeyError\nraised_from_frame = all_frames[-1]    # Frame from the ValueError\n\nprint(f\"First exception type: {type(chain_exception.__cause__)}\")\nprint(f\"Second exception type: {type(chain_exception)}\")\n```\n\n## Why Use Pymortem?\n\nPost-mortem debugging in Python traditionally requires using tools like `pdb.pm()` or `%debug` in IPython, which launch a separate command interface with its own syntax and navigation model. Pymortem takes a different approach:\n\n1. **Direct Context Access**: Instead of a separate debugging shell, access frame data directly in your current Python environment\n2. **Better Visualization**: See more context around exceptions with cleaner, more informative tracebacks\n3. **Natural Code Execution**: Run diagnostic code directly in frame contexts using standard Python syntax\n4. **Stays in Flow**: Particularly valuable in notebooks where switching to a separate debugging interface breaks your workflow\n5. **Handles Complexity**: Elegantly deals with nested and chained exceptions that can be confusing in traditional debuggers\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsarang%2Fpymortem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnsarang%2Fpymortem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsarang%2Fpymortem/lists"}