Finding full pathname in a Python trace
python, trace
Solution
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.
Problem
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 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') ```