Finding full pathname in a Python trace
Question: When turning on Python trace, the filename is provided, along with the module
and sourcecode.

Is it possible to show the file path as well as the filename?

I am using:

    
    
    -m trace -t
    

In the example below there are two different **account_bank_statement.py**
files in different directories.

    
    
    17  --- modulename: account_bank_statement, funcname: button_create_invoice
    18 account_bank_statement.py(329):         if context is None:
    19 account_bank_statement.py(333):         currency =  self.read(cr, uid, ids, ['currency'])[0]['currency']
    20  --- modulename: account_bank_statement, funcname: _currency
    21 account_bank_statement.py(107):         res = {}
    22 account_bank_statement.py(108):         res_currency_obj = self.pool.get('res.currency')
    

This is a duplicate of this (unanswered) question: [Tracing fIle path and line
number](http://stackoverflow.com/questions/14638041/tracing-file-path-and-
line-number#comment31443029_14638041)

An answer that would involve hacking the trace module would work for me.

**EDIT**

A solution, based on Alfe's answer below. It **is** intrusive, but is does
what I an looking for. I have left the modulename and also added the pathname.
I am working with OpenERP and there is often the same modulename defined in
multiple locations.

I have not posted this an answer as it is really a refinement of Alfe's
solution, so if you like please up vote his answer.

(1) Copy trace.py to your local path (2) Edit as below:

    
    
    171 def modname(path):
    172     """Return a plausible module name for the patch."""
    173 
    174     base = os.path.basename(path)
    175     filename, ext = os.path.splitext(base)
    176     return filename
    
    593     def globaltrace_lt(self, frame, why, arg):
    594         """Handler for call events.
    595 
    596         If the code block being entered is to be ignored, returns `None',
    597         else returns self.localtrace.
    598         """
    599         if why == 'call':
    600             code = frame.f_code
    601             filename = frame.f_globals.get('__file__', None)
    602             if filename:
    603                 # XXX modname() doesn't work right for packages, so
    604                 # the ignore support won't work right for packages
    605                 #modulename = fullmodname(filename)
    606                 modfile, ext = os.path.splitext(filename)
    607                 modulename = fullmodname(modfile)
    608                 if modulename is not None:
    609                     ignore_it = self.ignore.names(modfile, modulename)
    610                     if not ignore_it:
    611                         if self.trace:
    612                             print (" --- modulename: %s, funcname: %s, filename: %s"
    613                                    % (modulename, code.co_name, filename))
    614                         return self.localtrace
    615             else:
    616                 return None
    

**Sample Output**

Note there are 2 different module names, contained in different directories,
with the same filenames. This modified _trace.py_ * handles this.

    
    
    2  --- modulename: register_accounting, funcname: button_create_invoice, filename: /home/sean/unifield/utp729/unifield-wm/register_accounting/account_bank_statement.pyc
    3 account_bank_statement.py(329):         if context is None:
    4 account_bank_statement.py(333):         currency =  self.read(cr, uid, ids, ['currency'])[0]['currency']
    5  --- modulename: account, funcname: _currency, filename: /home/sean/unifield/utp729/unifield-addons/account/account_bank_statement.pyc
    6 account_bank_statement.py(107):         res = {}
    7 account_bank_statement.py(108):         res_currency_obj = self.pool.get('res.currency')
    


Answer: If patching of `trace.py` is allowed, this task is easy.

Copy `trace.py` (from `/usr/lib/python2.7/` in my case) to a local directory
(e. g. the current one), then patch the function `modname(path)` in that local
copy. That function strips the directories off the module paths, so the
package information is lost. The original contains the line

    
    
    filename, ext = os.path.splitext(base)
    

which can be changed to

    
    
    filename, ext = os.path.splitext(path)
    

in order to _not_ strip the directory.

The output of a call like `./trace.py --trace t.py` then looks like this:

    
    
     --- modulename: t, funcname: <module>
    t.py(3): import mypackage.mymodule
     --- modulename: mypackage/__init__, funcname: <module>
    __init__.py(1):   --- modulename: mypackage/mymodule, funcname: <module>
    mymodule.py(1): print 42
    42
    t.py(5): print 5
    5
     --- modulename: ./trace, funcname: _unsettrace
    trace.py(80):         sys.settrace(None)
    

I'm tracing a test script called `t.py` which imports a module `mymodule.py`
which is in a package `mypackage` (so the filename is
`./mypackage/mymodule.py`). That module only prints 42, the test script itself
prints 5.

Does this solve your issue?

EDIT:

Upon second view, I propose a different patch.

In function `globaltrace_lt()` the modulename is derived by calling
`modname()`; patch this to call `fullmodname()`:

    
    
                modulename = fullmodname(filename)
    

I think this might be a less intrusive patch.

