How to get actual line number of where python exception occurred?
<p>I have the following python decorator in my file <code>decorators.py</code></p>

<pre><code>def catch_exceptions(function):                                           #Line #1
    @wraps(function)                                                      #Line #2
    def decorator(*args, **kwargs):                                       #Line #3
        try:                                                              #Line #4
            return function(*args, **kwargs)                              #Line #5
        except Exception as e:                                            #Line #6
            exc_type, exc_obj, exc_tb = sys.exc_info()                    #Line #7
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]  #Line #8
            print "E=%s, F=%s, L=%s" % (str(e), fname, exc_tb.tb_lineno)  #Line #9
    return decorator                                                      #Line #10
</code></pre>

<p>In another file <code>my_file.py</code>, I use the <code>catch_exceptions</code> decorator like this:</p>

<pre><code>from decorators import catch_exceptions                                   #Line #1
@catch_exceptions                                                         #Line #2
def my_method()                                                           #Line #3
    print (10/0 - 5/0)                                                    #Line #4
</code></pre>

<p>When I run it, I get the following output:</p>

<pre><code>E=integer division or modulo by zero, F=decorators.py, L=5
</code></pre>

<p>Instead of it reporting the exception location as <code>decorators.py</code>, line #5, How can I get it to report the actual file and line number of where the exception originally occurred? That would be line #4 in <code>my_file.py</code>.</p>

<p>If you want to do it as you described then</p>

<pre><code>from functools import wraps
import sys, os, traceback

def catch_exceptions(function):                                           
    @wraps(function)                                                     
    def decorator(*args, **kwargs):                                      
        try:                                                              
            return function(*args, **kwargs)                              
        except Exception as e:                                            
            exc_type, exc_obj, exc_tb = sys.exc_info()
            print "E=%s, F=%s, L=%s" % (str(e), traceback.extract_tb(exc_tb)[-1][0], traceback.extract_tb(exc_tb)[-1][1]) ) 
    return decorator
</code></pre>

<p>But it's still <a href="https://docs.python.org/2/library/traceback.html#module-traceback" rel="nofollow"><code>traceback</code></a> that you need to know.</p>

<p>I believe that <code>filename</code> that was printing was also a mistake. </p>

<p>So <code>exc_tb</code> is actual <code>traceback</code> object. And extracting it's data is made by <a href="https://docs.python.org/2/library/traceback.html#traceback.extract_tb" rel="nofollow"><code>extract_tb()</code></a> it will do </p>

<blockquote>
  <p>Return a list of up to limit âpre-processedâ stack trace entries extracted from the traceback object tb. It is useful for alternate formatting of stack traces. If limit is omitted or <code>None</code>, all entries are extracted. A âpre-processedâ stack trace entry is a 4-tuple (filename, line number, function name*, text) representing the information that is usually printed for a stack trace.</p>
</blockquote>

<p>So the second last element of <code>traceback.extract_tb(exc_tb)</code> would be exception that is raised in decorator, and the last would be in your function. So the last index(<code>-1</code>) is what we need. Then <code>traceback.extract_tb(exc_tb)[-1][0]</code> would be filename of (I suppose) your desired file, not <em>decorators.py</em> and <code>traceback.extract_tb(exc_tb)[-1][1]</code> would be the line when the exception was fired.</p>

python django exception-handling