How to check, whether exception was raisen in the current scope?
<p>I use the following code to call an arbitrary callable <code>f()</code> with appropriate number of parameters:</p>

<pre><code>try:
    res = f(arg1)
except TypeError:
    res = f(arg1, arg2)
</code></pre>

<p>If <code>f()</code> is a two parameter function, calling it with just one parameter raises <code>TypeError</code>, so the function can be called properly in the <code>except</code> branch.</p>

<p>The problem is when <code>f()</code> is one-parameter function and the exception is raisen in the body of <code>f()</code> (possibly because of a bad call to some function), for example:</p>

<pre><code>def f(arg):
    map(arg) # raises TypeError
</code></pre>

<p>The control flow goes to the <code>except</code> branch because of the internal error of <code>f()</code>. Of course calling <code>f()</code> with two arguments raises a new <code>TypeError</code>. Then instead of traceback to the original error I get traceback to the call of <code>f()</code> with two parameters, which is much less helpful when debugging.</p>

<p>How can my code recognize exceptions raised not in the current scope to reraise them?</p>

<p>I want to write the code like this:</p>

<pre><code>try:
    res = f(arg1)
except TypeError:
    if exceptionRaisedNotInTheTryBlockScope(): # &lt;-- subject of the question
        raise
    res = f(arg1, arg2)
</code></pre>

<p>I know I can use a walkarround by adding <code>exc_info = sys.exc_info()</code> in the <code>except</code> block.</p>

<p>One of assumptions is I have no control over <code>f()</code> since it is given by user of my module. Also its <code>__name__</code> attribute may be other than <code>'f'</code>. Internal exception may be raised by bad recurrent call to <code>f()</code>.
The walkarround is unsuitable since it complicates debugging by the author of <code>f()</code>.</p>

<p>You can capture the exception object and examine it.</p>

<pre><code>try:
    res = f(arg1)
except TypeError as e:
    if "f() missing 1 required positional argument" in e.args[0]: 
        res = f(arg1, arg2)
    else:
        raise
</code></pre>

<p>Frankly, though, not going the extra length to classify the exception should work fine as you should be getting both the original traceback and the secondary traceback if the error originated inside f() -- debugging should not be a problem.</p>

<p>Also, if you have control over f() you can make second argument optional and not have to second-guess it:</p>

<pre><code>def f(a, b=None):
    pass
</code></pre>

<p>Now you can call it either way.</p>

<p>How about this:</p>

<pre><code>import inspect

if len(inspect.getargspec(f).args) == 1:
    res = f(arg1)
else:
    res = f(arg1, arg2)
</code></pre>

python python-2.7 python-3.x debugging exception-handling