18

In pycharm, I would like to break on a breakpoint that does nothing, during debugging. How can I do this?

For example, I would like to break on the pass statement:

for i in range(999999):
    if i == 6232:
        pass

If I set a breakpoint on pass, the debugger doesn't break there. The closest I've been able to do so far is to make up some unused variable name, and assign it a pointless value, so I can set a breakpoint on that line:

for i in range(999999):
    if i == 6232:
        foobar_unused_variable = "At least I can set a breakpoint on this line."
Edward Ned Harvey
  • 6,525
  • 5
  • 36
  • 45
  • 1
    I've run into this as well - generally I just put some kind of noop statement (such as `i`, which is valid python but doesn't do anything). This has the added benefit of being picked up by pylint so I don't accidentally commit it. – Shadow Dec 04 '17 at 02:07
  • 3
    `pass` means do nothing, and doing nothing is decided while compiling, so there is no executable code at `pass`, and finally debugger cannot debug `nothing`. – Sraw Dec 04 '17 at 02:11
  • 1
    @Sraw This seems wrong because that is exactly what a 'nop' is for so the debugger can debug "nothing" am i wrong? – Laz Nikolaj Andersen Apr 17 '18 at 10:23
  • @LazNikolajAndersen AFAIK, you are wrong. First, a debugger can only debug what is really executing, it cannot break at a non-exist place. Second, image if you are the author of that compiler, you will definitely try your best to optimize and reduce the redundant code as possible as you can. In this case, will you add an exactly useless code to target code? Surely you won't as no matter how much time it needs to execute, it is a waste. – Sraw Apr 17 '18 at 10:32
  • @Sraw For example, it is useful for conditional breakpoint `if : pass` if you add break to the pass, the sentence would be executed only if the condition is true. – Xwtek Jun 22 '20 at 05:31

5 Answers5

11

This issue transcends PyCharm. It's a Python issue. When the compiler compiles the AST to byte code, it doesn't even compile the Pass node; it simply skips it. The pass keyword's intended purpose is to prevent the compiler from complaining about what would otherwise be an empty (and thus syntactically invalid) block. Therefore, because the debugger operates on byte code, it will never know about the elided pass statements, so although a line containing a pass statement is somehow technically a valid breakpoint location, it will never trigger.

One has a few options:

  • Replace pass with a call to the builtin breakpoint function.
  • Replace pass with an effect-less statement (e.g. 0 or print(end='')) and break on it. Be sure to remove them when you're done with them. However, in certain Python implementations, these might or might not be optimized away.
  • Set a conditional breakpoint on the condition check instead of breaking within the body (assuming that the break condition has no meaningful side effects).
Tyler Crompton
  • 12,284
  • 14
  • 65
  • 94
8

Use Ellipsis!

For quick breakpoints or something that make minimum visual impact to you code, you may insert and break on an ... (Ellipsis):

For example:

while some_condition():
    do_something()
    ...  #  <<< set break point here!

this may the most clean way towards me.

Some background

Ellipsis is a special built-in python object mainly for Slice notating. Here I (ab)use it to do something else. See: What does the Python Ellipsis object do?

It is OK to insert a bare integer, variable name or something into code to set break point on certain place, but it may look odd and clutter your code, but ... is visually harmless. Compare with this:

break_point = 0
while some_condition():
    do_something()
    break_point # <<< set break point here!

or this:

while some_condition():
    do_something()
    if False: # <<< set break point here!
        pass

some other tricks tested:

del []  # works(with warning: "cannot assign to []")
[]  # works(with warning: Statement seems to have no effect)
setbreakpoint = 1  # works(with warning: "local variable value is not used")
Ellipsis  # works(with warning: Statement seems to have no effect)

another interesting thing that happens to me is, when i set breakpoints on pass it may or may not break, depending to its location in code, but the exact rule for break or not is somehow unclear.

imkzh
  • 211
  • 2
  • 9
  • 3
    Nice try, but ... When I simply stick a `...` or a `3` into code and set a breakpoint on it ... It doesn't break. I guess some compile optimizer is optimizing it away... Even if I put in `if False:` and try to break on that, it doesn't break. More evidence to suggest compiler optimizes it away. ¯\\_(ツ)_/¯ – Edward Ned Harvey Oct 30 '18 at 23:09
  • Hi @Edward, i have tried this in PyCharm Community 2017.3 with cpython plugin (without ipython), and it will break on bare variables, `...` and `if False:`, but will not break on `pass` or `3`, what IDE you are using? – imkzh Oct 31 '18 at 02:35
  • Interesting... I'm using PyCharm Pro 2018.2.4. You said `cpython` but did you mean `cython`? The [comparison matrix](https://www.jetbrains.com/pycharm/features/editions_comparison_matrix.html) says you need pro to support `cython`. – Edward Ned Harvey Oct 31 '18 at 17:12
  • Ah yes its Cython. (On a fresh PyCharm install, it will frequently prompt user to install Cython extension to speed up debugging, and i followed the install link just to make it quiet, as stated in https://www.jetbrains.com/help/pycharm/cython-speedups.html : “Thankfully, Python supports compiled C-extensions through Cython. PyCharm ships with C versions of debugger code, which you can compile to make debugging in PyCharm faster.”) @Edward – imkzh Oct 31 '18 at 17:30
  • Working great in PyCharm Community 2020.2. Thanks so much! – Christopher Galpin Sep 04 '20 at 15:33
4

As others have said, there is no clean way to do this. I recommend instead of pass, enter a useless statement such as

dbg = True

then set the break point on that line.

Advantages:

  1. It allows you to set a breakpoint there. (What you wanted to do.)
  2. Once you are accustomed to the idiom, you know what it really means.
  3. Every now and then you can go through your code and remove the old ones that you no longer use.

Disadvantages:

  1. It clutters up your code if you don't periodically remove them.
  2. Collaborators may become confused as to what you are doing.
  3. If you leave them in production code there might be a slight performance hit (depending on whether Python optimizes them out).
philologon
  • 2,093
  • 4
  • 19
  • 35
0

The breakpoint function

breakpoint() is good for:

  • Python >= 3.7
  • A built-in code cleanup reminder.
  • Always active; it cannot be toggle off with a mouse click.

A dummy print statement

But when I want to toggle it on and off I use a print function without actually calling it via (); like this:

for i in range(999999):
    print                 # Toggle breakpoint on this line

Dummy variable assignment

This is better than assigning a dummy variable because it doesn't clutter up my namespace (which makes it easier to debug), and PyCharm doesn't warn me about unused variables.

Ellipses

The ellipses solution didn't work for me on my PyCharm.

ChaimG
  • 7,024
  • 4
  • 38
  • 46
0

Building on ChaimG's answer, one might use a dummy breakpoint statement instead:

for i in range(100):
    breakpoint  # <--- toggle breakpoint here, note there is no parenthesis
aleksk
  • 661
  • 7
  • 15