# Print stack traces in Python

**URL:** https://sentry.io/answers/print-stack-traces-in-python/

---

## The Problem

When a Python script encounters an unhandled exception, it will normally print a stack trace to help with debugging. This is useful, you may need more control over when and how stack traces are printed. For example, you may want to be able to:

1. Print stack traces manually, at different points in the script's execution, without raising an exception.
2. Print the stack trace of a provided exception object.

## The Solution

We can do both of these things using Python's built-in [`traceback`](https://docs.python.org/3/library/traceback.html#module-traceback) module, which provides stack traces in a manner identical to the Python interpreter itself.

In addition to printing stack traces, several other methods for tracing function execution in Python are available, as discussed in [this answer](python-trace-function-execution-order).

### Print Stack Traces Without Raising an Exception

The function [`traceback.print_stack`](https://docs.python.org/3/library/traceback.html#traceback.print_stack) will print a stack trace at the current point in our script's invocation. The optional `limit` parameter allows us to control how many entries are printed -- by default, the entire stack trace will be printed. Consider the following example script:

```python
import traceback

def trace():
    traceback.print_stack()

def do_something():
    a = 1 + 2
    trace()

do_something()
```

When executed, this script will print the following stack trace:

```
  File "/tmp/trace.py", line 9, in <module>
    do_something()
  File "/tmp/trace.py", line 7, in do_something
    trace()
  File "/tmp/trace.py", line 3, in trace
    traceback.print_stack()
```

### Print the Stack Trace of a Provided Exception Object

We can use [`traceback.print_exception`](https://docs.python.org/3/library/traceback.html#traceback.print_exception) to print the traceback of an exception object we pass to it, along with the usual exception information. Since Python 3.10, this function accepts a single exception object as its argument:

```python
import traceback

traceback.print_exception(exception)
```

Here is an example script that uses `traceback.print_exception` to print the details of a previously caught exception:

```python
import traceback

my_dict = {}
saved_exception = None

try:
    a = my_dict["invalid"]
except Exception as ex:
    saved_exception = ex
    print("An error occurred")

if saved_exception:
    print("Here are the details of an exception that happened earlier:")
    traceback.print_exception(saved_exception)
```

When executed, this script will produce the following output:

```
An error occurred
Here are the details of an exception that happened earlier:
Traceback (most recent call last):
  File "/tmp/manual_exc.py", line 10, in <module>
    a = my_dict["invalid"]
        ~~~~~~~^^^^^^^^^^^
KeyError: 'invalid'
```

Note that `traceback.print_exception` prints the name and details of the exception below the stack trace. If we just want the stack trace on its own, we will need to take a more manual approach, using Python's built-in [`inspect`](https://docs.python.org/3/library/inspect.html) module to iterate through each frame of the exception's traceback object. For example:

```python
import inspect

def print_stacktrace(exception):
    stacktrace = exception.__traceback__

    for frame in inspect.getinnerframes(stacktrace):
        filename = frame.filename
        lineno = frame.lineno
        function = frame.function
        code_context = frame.code_context
        code_context = code_context[0].strip() if code_context else "No code context"
        print(f"File \"{filename}\", line {lineno}, in {function}")
        print(f"  {code_context}")
```

The [`inspect.getinnerframes`](https://docs.python.org/3/library/inspect.html#inspect.getinnerframes) function returns a list of [`FrameInfo`](https://docs.python.org/3/library/inspect.html#inspect.FrameInfo) objects, each of which contains the details of a single frame in the stack trace, including the filename, line number, function, and code context. Inside the `for` loop, we retrieve each of these and then print them, using a format that mimics Python's default stack trace printouts. Unlike `traceback.print_exception`, this approach gives us complete control over how the stack trace is printed.

Here's a modified version of our example script that only prints the stack trace of the exception provided:

```python
import inspect

def print_stacktrace(exception):
    stacktrace = exception.__traceback__

    for frame in inspect.getinnerframes(stacktrace):
        filename = frame.filename
        lineno = frame.lineno
        function = frame.function
        code_context = frame.code_context
        code_context = code_context[0].strip() if code_context else "No code context"
        print(f"File \"{filename}\", line {lineno}, in {function}")
        print(f"  {code_context}")

my_dict = {}
saved_exception = None

try:
    a = my_dict["invalid"]
except Exception as ex:
    saved_exception = ex
    print("An error occurred")

if saved_exception:
    print("Here is the stack trace for the exception that happened earlier:")
    print_stacktrace(saved_exception)
```

When executed, it will print the following output:

```
An error occured
Here is the stack trace for the exception that happened earlier:
File "/tmp/pst.py", line 19, in <module>
  a = my_dict["invalid"]
```

---

*Source: [sentry.io/answers/print-stack-traces-in-python/](https://sentry.io/answers/print-stack-traces-in-python/)*
