Nick Coghlan <ncogh...@gmail.com> added the comment:

The current pdb misbehaviour when navigating the stack is indeed a valid 
argument in favour of allowing immediate write-through from trace functions for 
regular local variables as well - I don't recall reading that bug report when 
Xavier first linked to it, so thanks for bringing it up again.

Another useful point that bug report highlights is that one of the assumptions 
I'd been making (that typical trace hooks would only need to manipulate the 
frame they were called for) is incorrect: via frame.f_back, the trace hook also 
has access to all of the parent frames, so any delayed write-back based 
approach would need to traverse the whole call stack to be truly robust. At 
that point, granting trace functions access to a write-through proxy as 
f_locals for *every* frame starts looking like a far more attractive option.

This suggests to me that rather than only switching behaviours while the 
traceback function is running, we would instead need to make it so that we 
check for whether or not a trace function is installed for the process whenever 
f_locals is looked up. If it is, and the frame uses fast locals, then f_locals 
will be a _FunctionLocalsProxy instance. Otherwise, it will be a regular 
dictionary.

Making a dynamic decision on whether to return a proxy or not is needed to 
handle the pdb stack traversal use case properly: debuggers are often going to 
be confronted with frames that were created *before* their trace hook was 
installed. Right now, as per the issue Xavier linked, attempted writes back to 
those don't tend to work properly (due to when and where the write-back 
happens), but dynamically upgrading to write-through proxies in the presence of 
a trace hook should help resolve that.

While that's a more pervasive change than what I was considering, I think the 
cited pdb bug provides a strong enough rationale to justify the related risk of 
unintended consequences.

Interestingly, I think it also gives us a way to reduce the degree to which 
installation of a trace hook affects the semantics of locals(): when f_locals 
on a frame is a _FunctionLocalsProxy instance, the locals() builtin can still 
bypass it and return the underlying dict. The difference between this and my 
earlier proposal for two different snapshot namespaces is that there'd still 
only be one snapshot, it's that f_locals would either reference it directly 
(the default state), or else via a write-through proxy (the "tracing mode" 
state).

I think that approach will give us the best possible outcome available:

* for code using locals(), the behaviour in non-tracing mode will be completely 
unchanged, and the semantic differences between tracing and non-tracing mode 
while a function is running will be reduced, since the post-trace-hook 
writeback code will be removed, and locals() itself never return a reference to 
the write-through proxy (only the underlying namespace snapshot). (There will 
still be some semantic differences, since the snapshot will be implicitly 
refreshed in tracing mode, whereas you have to call locals() explicitly to 
refresh it in non-tracing mode)

* for code using frame.f_locals, it will either behave the same as locals() if 
no tracing hook is installed when you retrieve a reference from the frame 
(again, no change from the status quo), *or* it will immediately write through 
to the active locals if a tracing hook *is* installed (replacing the current 
post-trace-hook writeback code)

(Note: if folks want to instead argue for the compatibility break option, 
you're going to have to write your own PEP, as I have zero plans to implement 
that myself, and will oppose it as a gratuitously unnecessary compatibility 
break if it does get proposed. Toggling this behaviour change on "Tracing or 
not?" won't be hard, and it ensures any  unforeseen negative outcomes will only 
impact situations that are currently broken anyway)

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue30744>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to