In <mailman.65.1292517591.6505.python-l...@python.org> Robert Kern <robert.k...@gmail.com> writes:
>Obfuscating the location that an exception gets raised prevents a lot of >debugging... The Python interpreter does a lot of that "obfuscation" already, and I find the resulting tracebacks more useful for it. An error message is only useful to a given audience if that audience can use the information in the message to modify what they are doing to avoid the error. It is of no use (certainly no *immediate* use) to this audience to see tracebacks that go deep into code that they don't know anything about and cannot change. For example, consider this: #----------------------------------------------------------------- def foo(x, **k): pass def bar(*a, **k): if len(a) > 1: raise TypeError('too many args') def baz(*a, **k): _pre_baz(*a, **k) def _pre_baz(*a, **k): if len(a) > 1: raise TypeError('too many args') if __name__ == '__main__': from traceback import print_exc try: foo(1, 2) except: print_exc() try: bar(1, 2) except: print_exc() try: baz(1, 2) except: print_exc() #----------------------------------------------------------------- (The code in the "if __name__ == '__main__'" section is meant to simulate the general case in which the functions defined in this file are called by third-party code.) When you run this code the output is this (a few blank lines added for clarity): Traceback (most recent call last): File "/tmp/ex2.py", line 5, in <module> try: foo(1, 2) TypeError: foo() takes exactly 1 argument (2 given) Traceback (most recent call last): File "/tmp/ex2.py", line 7, in <module> try: bar(1, 2) File "/tmp/example.py", line 4, in bar if len(a) > 1: raise TypeError('too many args') TypeError: too many args Traceback (most recent call last): File "/tmp/ex2.py", line 9, in <module> try: baz(1, 2) File "/tmp/example.py", line 6, in baz def baz(*a, **k): _pre_baz(*a, **k) File "/tmp/example.py", line 9, in _pre_baz if len(a) > 1: raise TypeError('too many args') TypeError: too many args In all cases, the *programming* errors are identical: functions called with the wrong arguments. The traceback from foo(1, 2) tells me this very clearly, and I'm glad that Python is not also giving me the traceback down to where the underlying C code throws the exception: I don't need to see all this machinery. In contrast, the tracebacks from bar(1, 2) and baz(1, 2) obscure the fundamental problem with useless detail. From the point of view of the programmer that is using these functions, it is of no use to know that the error resulted from some "raise TypeError" statement somewhere, let alone that this happened in some obscure, private function _pre_baz. Perhaps I should have made it clearer in my original post that the tracebacks I want to clean up are those from exceptions *explicitly* raised by my argument-validating helper function, analogous to _pre_baz above. I.e. I want that when my spam function is called (by code written by someone else) with the wrong arguments, the traceback looks more like this Traceback (most recent call last): File "/some/python/code.py", line 123, in <module> spam(some, bad, args) TypeError: the second argument is bad than like this: Traceback (most recent call last): File "/some/python/code.py", line 123, in <module> spam(some, bad, args) File "/my/niftymodule.py", line 456, in niftymodule _pre_spam(*a, **k) File "/my/niftymodule.py", line 789, in __pre_spam raise TypeError('second argument to spam is bad') TypeError: the second argument is bad In my opinion, the idea that more is always better in a traceback is flat out wrong. As the example above illustrates, the most useful traceback is the one that stops at the deepest point where the *intended audience* for the traceback can take action, and goes no further. The intended audience for the errors generated by my argument-checking functions should see no further than the point where they called a function incorrectly. ~kj -- http://mail.python.org/mailman/listinfo/python-list