
On Jul 27, 2019, at 22:19, James Lu <jamtlu@gmail.com> wrote:
Minimal strawman proposal. New keyword debug.
debug EXPRESSION
Executes EXPRESSION when in debug mode.
You really mean expression, not statement here? That doesn’t seem very useful. Sure, some expressions are used for side effects, but most are used for values, while most things you do want to execute for side effects are statements (and not just expression statements). Also, why is it not sufficient to use if DEBUG: expr (which already works, and can take a statement, even a compound statement)?
debug context
Prints all the variables of the enclosing closure and all the variable names accessed within that block. For example, if in foo you access the global variable spam, spam would be printed. The format would be:
What do you want this for? The previous statement seems like it would only be useful for non-interactive use, but this one seems like it would be useless there. If I’m trying to debug a daemon or a webservice or a GUI app or something, I probably want the debug output to go to my logs, or at least stderr, rather than stdout. An inspect function that gave a string I could print (or a stack of functions similar to the traceback module ones, where the lowest one gives a dict, but there are convenience helpers above that to give a pre-formatted string instead, or to just dump that string directly) seems like it would be more useful (although still, the top one seems like it should dump to stderr rather than stdout). How does the interpreter know which globals are accessed from the current frame? Looking at the frame’s code object’s names gets you about 70% of the way there, but that’s the names of all identifiers that aren’t local/cell/free vars, which includes more than global vars, and it doesn’t include globals looked up indirectly, and it includes globals that are only referenced in dead code, and so on. Plus, if you wanted that, you could write it today as a 3-line function using inspect; no need for a new statement. If you want the interpreter to keep track of things at runtime instead of relying on the statically available information, it seems like the only way to do that is to have debug mode do the equivalent of a per-opcode trace function or an all-variables watchpoint so it can maintain the information in case you ask for it. This would probably be pretty slow. Also, most of the globals used in most functions are the top-level functions and classes used in the function. Since these don’t usually change at runtime, and their reprs don’t tell you anything useful beyond their name, what’s the point in dumping them? Also, what if you have a variable named context? That’s hardly rare as a name, and your two statements seem to be ambiguous in that case. Also, except for this being a statement that needs a new keyword and a new context-sensitive keyword instead of a plain old function you stick in builtins named debug_context(), it seems like any feasible version of this could already be written and used in Python today. (The first one, using static frame info, should be about 3 lines of inspect calls.)
?identifier
would print "identifier: value." Repr as before. Using this in non-debug mode emits a warning.
This would break iPython’s improved interactive console, which already uses this syntax to provide a similar feature. And in non-interactive use, I can’t see any use for this. Especially since it would have to be wrapped in #if DEBUG, so the one-liner brevity doesn’t seem to buy you anything.
?identifier.property.property
is also valid.
Why not just allow anything that’s valid as a target, like identifier[expr]? Or even just any expression at all? Is there an advantage to defining and using a similar but more limited syntax here?
A new property descriptor on the global variable, “debugger.” This is an alias for importing PDB and causing the debugger to pause there.
You want this added to every module’s globals? Why not put it in builtins instead? And why isn’t the existing builtin breakpoint sufficient? I can only see two differences. First, you have to call breakpoint as a function, not just reference it, but I’m having trouble imagining when that’s a problem. Second, your magic property would always use pdb, even if the breakpoint hook has been set to another debugger, but that seems like it’s just always worse when it’s different.
Debug mode may be specified per-module at interpreter launch.
Wait, this new debug mode is separate from the existing debug mode? Then how do they interact? It might help to show us how all this stuff would actually be used in debugging some realistic code in some realistic scenario, maybe by giving us some code with functions whose bodies are like `#80 lines of complicated stuff to get the value for spam` followed by `?spam`, and then a fake console dump or interactive session log showing the program being started and displaying its output?