Claude Code for traceback: Exception Tracebacks in Python — Claude Skills 360 Blog
Blog / AI / Claude Code for traceback: Exception Tracebacks in Python
AI

Claude Code for traceback: Exception Tracebacks in Python

Published: August 5, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s traceback module formats and extracts exception information. import traceback. format_exc: traceback.format_exc() → current exception as string (like what Python prints); returns "None\n" if no active exception. print_exc: traceback.print_exc(file=sys.stderr) — print current traceback. format_exception: traceback.format_exception(exc_type, exc_value, exc_tb) → list of strings. format_exception (3-arg or 1-arg in 3.10+): traceback.format_exception(exc) → list of strings. format_tb: traceback.format_tb(tb) → list of frame strings. extract_tb: traceback.extract_tb(tb)StackSummary. format_stack: traceback.format_stack() → current stack as list of strings. print_stack: traceback.print_stack() — print current stack. TracebackException: te = traceback.TracebackException.from_exception(exc) — rich structured object; te.format() → iterator; te.__cause__, te.__context__, te.__suppress_context__. StackSummary: list of FrameSummary(filename, lineno, name, line). walk_tb: traceback.walk_tb(tb)(frame, lineno) iterator. walk_stack: traceback.walk_stack(frame) → current call stack iterator. limit: format_tb(tb, limit=10) — show at most 10 frames. Claude Code generates structured error reporters, exception loggers, Sentry payload builders, and error summary utilities.

CLAUDE.md for traceback

## traceback Stack
- Stdlib: import traceback
- String:  traceback.format_exc()           # current exception → str
- Struct:  traceback.TracebackException.from_exception(exc)
- Frames:  traceback.extract_tb(exc.__traceback__)  → StackSummary
- Log:     logger.error("err", exc_info=True)  (preferred for prod)
- Compact: traceback.format_exception_only(type(exc), exc) → one-liner list

traceback Structured Error Pipeline

# app/tbutil.py — structured capture, error reporter, chain formatter, log
from __future__ import annotations

import logging
import sys
import traceback
from dataclasses import dataclass, field
from typing import Any


# ─────────────────────────────────────────────────────────────────────────────
# 1. Basic formatting helpers
# ─────────────────────────────────────────────────────────────────────────────

def exc_string(exc: BaseException | None = None, limit: int | None = None) -> str:
    """
    Return a formatted traceback string for exc (or current exception if None).

    Example:
        try:
            risky()
        except Exception as e:
            msg = exc_string(e)
            logger.error(msg)
    """
    if exc is None:
        return traceback.format_exc()
    lines = traceback.format_exception(type(exc), exc, exc.__traceback__, limit=limit)
    return "".join(lines)


def exc_oneliner(exc: BaseException) -> str:
    """
    Return a single-line exception summary: 'ExcType: message'.

    Example:
        label = exc_oneliner(e)   # "ValueError: invalid literal for int()"
    """
    parts = traceback.format_exception_only(type(exc), exc)
    return "".join(parts).strip()


def current_stack(limit: int = 10, skip: int = 1) -> str:
    """
    Return the current call stack as a formatted string (no exception needed).

    Example:
        print(current_stack())
    """
    lines = traceback.format_stack(limit=limit + skip)
    return "".join(lines[skip:])


# ─────────────────────────────────────────────────────────────────────────────
# 2. Structured exception capture
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class FrameInfo:
    filename: str
    lineno:   int
    name:     str
    line:     str


@dataclass
class ErrorReport:
    exc_type:   str
    message:    str
    frames:     list[FrameInfo]
    cause:      "ErrorReport | None"  = None
    context:    "ErrorReport | None"  = None
    full_text:  str                   = ""

    @classmethod
    def from_exception(cls, exc: BaseException, limit: int = 20) -> "ErrorReport":
        """
        Build a structured ErrorReport from an exception.

        Example:
            try:
                load_data()
            except Exception as e:
                report = ErrorReport.from_exception(e)
                send_to_alerting(report.to_dict())
        """
        te = traceback.TracebackException.from_exception(exc, limit=limit)
        frames = [
            FrameInfo(
                filename=fs.filename or "<unknown>",
                lineno=fs.lineno or 0,
                name=fs.name or "<unknown>",
                line=(fs.line or "").strip(),
            )
            for fs in te.stack
        ]
        cause = cls.from_exception(exc.__cause__) if exc.__cause__ else None
        context = (
            cls.from_exception(exc.__context__)
            if exc.__context__ and not exc.__suppress_context__
            else None
        )
        return cls(
            exc_type=te.exc_type.__name__ if te.exc_type else "Exception",
            message="".join(te.format_exception_only()).strip(),
            frames=frames,
            cause=cause,
            context=context,
            full_text="".join(te.format()),
        )

    @property
    def location(self) -> str:
        """'filename:lineno in function_name' of the innermost frame."""
        if self.frames:
            f = self.frames[-1]
            return f"{f.filename}:{f.lineno} in {f.name}"
        return "<unknown>"

    def to_dict(self) -> dict[str, Any]:
        return {
            "exc_type": self.exc_type,
            "message":  self.message,
            "location": self.location,
            "frames":   [{"file": f.filename, "line": f.lineno, "fn": f.name, "src": f.line} for f in self.frames],
            "cause":    self.cause.to_dict() if self.cause else None,
            "context":  self.context.to_dict() if self.context else None,
        }

    def summary(self) -> str:
        parts = [f"{self.exc_type} at {self.location}"]
        if self.cause:
            parts.append(f"  caused by: {self.cause.exc_type} at {self.cause.location}")
        if self.context:
            parts.append(f"  during: {self.context.exc_type} at {self.context.location}")
        return "\n".join(parts)


# ─────────────────────────────────────────────────────────────────────────────
# 3. Logging integration
# ─────────────────────────────────────────────────────────────────────────────

def log_exception(
    logger: logging.Logger,
    exc: BaseException | None = None,
    *,
    message: str = "Unhandled exception",
    level: int = logging.ERROR,
    limit: int | None = None,
) -> None:
    """
    Log an exception with its full traceback at the given level.
    Uses exc_info=True for proper integration with log handlers.

    Example:
        try:
            db.query(sql)
        except Exception as e:
            log_exception(logger, e, message="DB query failed")
    """
    if exc is not None:
        logger.log(level, message, exc_info=(type(exc), exc, exc.__traceback__))
    else:
        logger.log(level, message, exc_info=True)


def log_and_reraise(
    logger: logging.Logger,
    exc: BaseException,
    message: str = "Exception",
) -> None:
    """
    Log the exception then re-raise it.

    Example:
        try:
            compute()
        except Exception as e:
            log_and_reraise(logger, e, "compute() failed")
    """
    log_exception(logger, exc, message=message)
    raise exc


def safe_call(
    fn: Any,
    *args: Any,
    logger: logging.Logger | None = None,
    default: Any = None,
    **kwargs: Any,
) -> Any:
    """
    Call fn(*args, **kwargs); log and return default on any exception.

    Example:
        result = safe_call(fetch_data, url, logger=logger, default=[])
    """
    try:
        return fn(*args, **kwargs)
    except Exception as exc:
        if logger:
            log_exception(logger, exc, message=f"{fn.__name__}() failed")
        return default


# ─────────────────────────────────────────────────────────────────────────────
# 4. Exception chain formatting
# ─────────────────────────────────────────────────────────────────────────────

def format_chain(exc: BaseException, indent: int = 0) -> str:
    """
    Recursively format an exception chain (cause / context) as a tree.

    Example:
        try:
            ...
        except Exception as e:
            print(format_chain(e))
    """
    lines: list[str] = []
    pad  = "  " * indent

    if exc.__cause__ is not None:
        lines.append(format_chain(exc.__cause__, indent + 1))
        lines.append(f"{pad}↳ [caused by above]")
    elif exc.__context__ is not None and not exc.__suppress_context__:
        lines.append(format_chain(exc.__context__, indent + 1))
        lines.append(f"{pad}↳ [during handling of above]")

    report = ErrorReport.from_exception(exc)
    lines.append(f"{pad}{report.exc_type}: {exc}")
    if report.frames:
        last = report.frames[-1]
        lines.append(f"{pad}  at {last.filename}:{last.lineno} in {last.name}()")
        if last.line:
            lines.append(f"{pad}{last.line}")
    return "\n".join(lines)


# ─────────────────────────────────────────────────────────────────────────────
# 5. Exception hook / global handler
# ─────────────────────────────────────────────────────────────────────────────

def install_global_handler(
    logger: logging.Logger | None = None,
    reporter: Any = None,
) -> None:
    """
    Install a sys.excepthook that logs unhandled exceptions and optionally
    calls an external reporter (e.g., Sentry capture_exception).

    Example:
        install_global_handler(logger=app_logger, reporter=sentry_sdk.capture_exception)
    """
    _prev_hook = sys.excepthook

    def _hook(exc_type: type, exc_value: BaseException, exc_tb: Any) -> None:
        if issubclass(exc_type, KeyboardInterrupt):
            _prev_hook(exc_type, exc_value, exc_tb)
            return
        if logger:
            logger.critical(
                "Unhandled exception",
                exc_info=(exc_type, exc_value, exc_tb),
            )
        if reporter is not None:
            try:
                reporter(exc_value)
            except Exception:
                pass
        _prev_hook(exc_type, exc_value, exc_tb)

    sys.excepthook = _hook


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG, format="%(levelname)s %(name)s%(message)s")
    log = logging.getLogger("demo")

    print("=== traceback demo ===")

    print("\n--- exc_string ---")
    try:
        1 / 0
    except ZeroDivisionError as e:
        s = exc_string(e)
        print(s.strip())

    print("\n--- exc_oneliner ---")
    try:
        int("bad")
    except ValueError as e:
        print(f"  oneliner: {exc_oneliner(e)!r}")

    print("\n--- ErrorReport ---")

    def inner():
        raise KeyError("missing_field")

    def outer():
        try:
            inner()
        except KeyError as exc:
            raise RuntimeError("processing failed") from exc

    try:
        outer()
    except RuntimeError as e:
        report = ErrorReport.from_exception(e)
        print(f"  type:     {report.exc_type}")
        print(f"  location: {report.location}")
        print(f"  cause:    {report.cause.exc_type if report.cause else None}")
        print(f"  summary:\n{report.summary()}")

    print("\n--- format_chain ---")
    try:
        outer()
    except RuntimeError as e:
        chain = format_chain(e)
        print(chain)

    print("\n--- log_exception ---")
    try:
        {}["nope"]
    except KeyError as e:
        log_exception(log, e, message="lookup failed", level=logging.WARNING)

    print("\n--- safe_call ---")
    result = safe_call(int, "not_a_number", logger=log, default=-1)
    print(f"  safe_call result: {result}")

    print("\n--- current_stack ---")
    def show_stack():
        return current_stack(limit=4)
    print(show_stack())

    print("\n=== done ===")

For the sys.exc_info() alternative — sys.exc_info() returns (exc_type, exc_value, exc_traceback) inside an except block; it is the raw low-level accessor; traceback module functions accept these values and produce formatted strings — use sys.exc_info() when you need direct access to the traceback object for introspection or passing to frameworks; use traceback.format_exception() / TracebackException.from_exception() for formatting and structured analysis. For the logging.exception / logger.error(exc_info=True) alternative — logger.error("msg", exc_info=True) or logger.exception("msg") captures the full traceback and attaches it to the log record, letting log handlers (file, Sentry, Datadog) process it appropriately; traceback.format_exc() produces a plain string that can be passed to any logger but loses structured metadata like log level and logger name — prefer logger.error(exc_info=True) in production code; use traceback.format_exc() or TracebackException when you need the string for non-logging outputs (JSON payloads, API responses, terminal UIs). The Claude Skills 360 bundle includes traceback skill sets covering exc_string()/exc_oneliner()/current_stack() format helpers, ErrorReport/FrameInfo structured exception capture with cause and context chaining, log_exception()/log_and_reraise()/safe_call() logging integration, format_chain() recursive chain tree formatter, and install_global_handler() sys.excepthook installer. Start with the free tier to try structured error reporting and traceback pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free