Short version:
Is there a way to achieve the same effect in Python that is achieved with the Perl Carp::carp utility?
Long version (for those who are not familiar with Carp::carp ):
Suppose we implement some library API function (i.e. it is intended for use by other programmers in their code), say spam , and suppose that spam contains some code to verify the validity of the arguments passed to it. Of course, this code should throw an exception if any problem is found with these arguments. Let's say we want the related error message and trace to be as useful as possible for someone debugging some client code.
Ideally, the last trace line generated by this raised exception should indicate a “violation code,” namely, a line in the client code where spam is called with invalid arguments.
Unfortunately, this is not what will happen, at least by default, using Python. Instead, the last trace line will be mentioned somewhere inside the library’s internal code, where the exception was actually raise 'd, which would be rather obscure for the intended audience of this particular trace.
Example:
# spam.py (library code) def spam(ham, eggs): ''' Do something stupid with ham and eggs. At least one of ham and eggs must be True. ''' _validate_spam_args(ham, eggs) return ham == eggs def _validate_spam_args(ham, eggs): if not (ham or eggs): raise ValueError('if we had ham ' 'we could have ham and eggs ' '(if we had eggs)')
When we run client.py , we get:
% python client.py Traceback (most recent call last): File "client.py", line 3, in <module> x = spam(False, False) File "/home/jones/spam.py", line 7, in spam _validate_spam_args(ham, eggs) File "/home/jones/spam.py", line 12, in _validate_spam_args raise ValueError('if we had ham ' ValueError: if we had ham we could have ham and eggs (if we had eggs)
whereas we want to be closer:
% python client.py Traceback (most recent call last): File "client.py", line 3, in <module> x = spam(False, False) ValueError: if we had ham we could have ham and eggs (if we had eggs)
... with a violation code ( x = spam(False, False) ) as the last line of the trace.
We need some way to report the error “from the perspective of the caller” (this is what Carp::carp allows you to do in Perl).
EDIT: To be clear, this question is not about LBYL and EAFP, nor prerequisites, nor programming. I'm sorry if I gave this wrong impression. This question is about how to create a trace, starting from several (one, two) levels up the call stack.
EDIT2: The Python traceback module is the obvious place to look for the Python equivalent of Perl Carp::carp , but after studying it for some time, I could not find a way to use it for what I want to do. FWIW, Perl Carp::carp allows you to fine-tune the source frame for tracing by exposing the global (hence dynamically limited) variable $Carp::CarpLevel . Library functions other than APIs that can carp -out, local -ize and increment this variable when writing (for example, local $Carp::CarpLevel += 1; ). I don't see anything even remotely like this Python traceback module. So, if I didn't miss anything, any solution using Python traceback would have to take a completely different approach ...