Pycharm Tip: Conditional Breakpoints

Hi! In this post I'd like to show you a feature of Pycharm (specifically, a feature of its debugger) that I wish I had discovered earlier. Let's take a look at conditional breakpoints.

Exemplary code

Let's imagine we have an application that processes some reports. Each report has an attribute country_code which, as its name indicates, describes the code of report's country. For the sake of simplicity, let's skip any other attributes that such report would have in a real-world application (actual data, creation date and many others).


Country code can be one of three possible values (POL - Poland, DEU - Germany, SWE - Sweden). Let's use enumerations for country codes and data classes for modelling our report object.

from dataclasses import dataclass
from enum import Enum
from typing import Iterable


class CountryCode(Enum):
    POL = 1
    DEU = 2
    SWE = 3


@dataclass
class Report:
    country_code: CountryCode


We also have a function that accepts an iterable of reports and do some processing on them. Implementation details for processing logic is not important at this moment, so we'll skip it as well. Our processing function could look like this:

from typing import Iterable


def process_reports_batch(reports_batch: Iterable[Report]) -> None:  
    for report in reports_batch:  
        print(f"Processing {report} report.")  
        # here goes the logic for processing actual report  
        print("Done!")


Finally, let's create a batch of reports that will be processed.

reports_batch = (  
    Report(country_code=CountryCode.DEU),  
    Report(country_code=CountryCode.DEU),  
    Report(country_code=CountryCode.DEU),  
    Report(country_code=CountryCode.POL),  
    Report(country_code=CountryCode.SWE),  
    Report(country_code=CountryCode.SWE),  
    Report(country_code=CountryCode.DEU),  
)

# do the report processing
process_reports_batch(reports_batch=reports_batch)

Oops, there's an issue!

You've discovered that there's something wrong with the processing logic for Polish reports (represented by enumeration CountryCode.POL). You need to debug the application to sort this out.


Let's start with simply putting a breakpoint inside for report in reports_batch: loop. The problem with this approach is that we'll have to keep pressing Resume Program to skip first three reports (which have DEU code). And what if the batch would contain 1000 reports? This approach doesn't scale well.


How about adding some simple if statement (checking for country code condition) with dummy print statement upon which we could set a breakpoint?


def process_reports_batch(reports_batch: Iterable[Report]) -> None:  
    for report in reports_batch:  
        if report.country_code == CountryCode.POL:
            print() 
        print(f"Processing {report} report.", end=" ")  
        # here goes the logic for processing actual report  
        print("Done!")


No more need to press Resume Program until the desired report is iterated over. But we had to include additional code just for the sake of stopping the program at the right place and state. What if we forgot to remove it and commit it later to repo? As Raymond Hettinger likes to say:

There must be a better way!

Conditional breakpoints for the rescue

Indeed, there is a better way - and it's called conditional breakpoints.


Pycharm allows us to set breakpoints that have conditions bound to them. You can simply specify an expression and, when this condition is met, Pycharm will suspend the execution of our program (if ran in Debug mode, obviously).


So how would we use it in our example?


We set a breakpoint inside the for loop. Once it's set, we right-click on the breakpoint's red dot and we should see a prompt that has a condition input. Since we want to stop on the Polish report, we'll type:

report.country_code == CountryCode.POL


After entering the condition and pressing Done button, you should see a small question mark on the red dot of the breakpoint, indicating that our condition was set properly. The next time we'll run our application in debug mode, execution of the program will be suspended and handed to us in an exact moment we need.

Closing remarks

I purposely skipped an approach where we pass a filtered reports batch iterable containing only Polish reports - it would require touching the code + there might be a case where the batch is created dynamically or somewhere else in our app.
Hope you'll find this feature helpful.

Happy debugging,
Kuba