Schaf,
Yes, I've seen that. In my case, it's not a bug. It's an
intentional
design decision that is necessary for a symbolic debugger to
work the way you want it to. Happens in all symbolic debuggers,
including PyCharm.
Here's a explanation I sent my team recently:
Team,
I just figured out something that has been a mystery to me for
a while.
In some cases, I've found that the PyCharm debugger does 2
weird things:
A. Runs the code differently when I step through it than when I
run it flat out
B. Skips breakpoints that I've set (even if I'm very careful to
have only one Run and/or Debug tab running at a time)
I figured out why. It's a problem common to all symbolic
debuggers but it doesn't come up very often, so I hadn't had
to think about it for a while. It's bitten me a few times lately
because I've been doing detailed debugging of the validation
code that Django runs for forms.
Basically, the problem is that there are 2 things symbolic
debuggers typically do:
1. Execute code internally to compute values to show you in
the Variables and Watches frames of the debugger
2. Skip any breakpoints that occur while executing such code
internally
The standard Django Form class has this code:
def _get_errors(self):
"Returns an ErrorDict for the data provided for the
form"
if self._errors is None:
self.full_clean()
return self._errors
errors = property(_get_errors)
So, errors is a property that calls _get_errors() whenever
PyCharm tries to get its value to show it to me, which happens
each time I hit a breakpoint or single-step past a line of code.
But probably only if I have the Variables pane open with the
tree expanded to show the value of errors.
The first time it's called, _get_errors() notices that _errors is
None, and calls full_clean(), which sets _errors to an ErrorDict.
After that, it never calls full_clean() again.
Our clean() methods and other validation code are called by
full_clean().
I was trying to debug our clean() method, and had set a
breakpoint there. But PyCharm doesn't hit breakpoints there
when it's running the code internally to compute a value to
show it me. See #2 above.
The first evaluation of errors is the only one that calls
full_clean() and that was happening much earlier when I was
poking around in the debugger, peeking at things to see if
they had changed yet, than when I was running the code flat
out. See #1 above.
The upshot was that my breakpoint was never being hit. I had
to add logging statements to convince myself it was really
running, and to debug what was going wrong.
In a nutshell: "Holy Heisenberg Uncertainty Principal, Batman!"