Skip to content

trace: line tracing output lacks newlines if source lines are not available #103956

Closed
@chgnrdv

Description

@chgnrdv

trace doesn't print newline character when handling line event if it can't fetch source line that corresponds to a current frame, e. g. in case of frozen modules (or in any other case when frame.f_code.co_filename points to a non-existing file).

Example:

import numpy as np
x = np.array([1, 2, 3])
./python -m trace --trace example.py
--- modulename: example, funcname: <module>
example.py(2): import signal
 --- modulename: _bootstrap, funcname: _find_and_load
<frozen importlib._bootstrap>(1299): <frozen importlib._bootstrap>(1300): <frozen importlib._bootstrap>(1302):  --- modulename: _bootstrap, funcname: __init__
<frozen importlib._bootstrap>(325): <frozen importlib._bootstrap>(326):  --- modulename: _bootstrap, funcname: __enter__
<frozen importlib._bootstrap>(329):  --- modulename: _bootstrap, funcname: _get_module_lock
<frozen importlib._bootstrap>(344): <frozen importlib._bootstrap>(345): <frozen importlib._bootstrap>(346): <frozen importlib._bootstrap>(347): <frozen importlib._bootstrap>(348): <frozen importlib._bootstrap>(349): <frozen importlib._bootstrap>(351): <frozen importlib._bootstrap>(352): <frozen importlib._bootstrap>(355):  --- modulename: _bootstrap, funcname: __init__
<frozen importlib._bootstrap>(165): <frozen importlib._bootstrap>(166): <frozen importlib._bootstrap>(169): <frozen importlib._bootstrap>(173): <frozen importlib._bootstrap>(184): <frozen importlib._bootstrap>(198): <frozen importlib._bootstrap>(357): <frozen importlib._bootstrap>(368): <frozen importlib._bootstrap>(370): <frozen importlib._bootstrap>(372): <frozen importlib._bootstrap>(330):  --- modulename: _bootstrap, funcname: acquire
<frozen importlib._bootstrap>(222): <frozen importlib._bootstrap>(223):  --- modulename: _bootstrap, funcname: __init__
<frozen importlib._bootstrap>(71): <frozen importlib._bootstrap>(72):  --- modulename: _bootstrap, funcname: __enter__
<frozen importlib._bootstrap>(82): <frozen importlib._bootstrap>(83): <frozen importlib._bootstrap>(224): <frozen importlib._bootstrap>(228): <frozen importlib._bootstrap>(229): <frozen importlib._bootstrap>(236): <frozen importlib._bootstrap>(237): <frozen importlib._bootstrap>(238): <frozen importlib._bootstrap>(228): <frozen importlib._bootstrap>(223):  --- modulename: _bootstrap, funcname: __exit__
<frozen importlib._bootstrap>(87): <frozen importlib._bootstrap>(1303): <frozen importlib._bootstrap>(1304): <frozen importlib._bootstrap>(1305):  --- modulename: _bootstrap, funcname: _find_and_load_unlocked
<frozen importlib._bootstrap>(1250): <frozen importlib._bootstrap>(1251): <frozen importlib._bootstrap>(1252): <frozen importlib._bootstrap>(1253): <frozen importlib._bootstrap>(1267):  --- modulename: _bootstrap, funcname: _find_spec
<frozen importlib._bootstrap>(1185): <frozen importlib._bootstrap>(1186): <frozen importlib._bootstrap>(1191): <frozen importlib._bootstrap>(1197): <frozen importlib._bootstrap>(1198): <frozen importlib._bootstrap>(1199):  --- modulename: _bootstrap, funcname: __enter__
...
numeric.py(205):     a = empty(shape, dtype, order)
numeric.py(206):     multiarray.copyto(a, 1, casting='unsafe')
 --- modulename: overrides, funcname: copyto
<__array_function__ internals>(179): <__array_function__ internals>(180):  --- modulename: multiarray, funcname: copyto
multiarray.py(1127):     return (dst, src, where)
<__array_function__ internals>(200): <__array_function__ internals>(201): <__array_function__ internals>(200): numeric.py(207):     return a
__init__.py(348):             if not abs(x.dot(x) - float32(2.0)) < 1e-5:
__init__.py(359):     del _sanity_check
__init__.py(361):     def _mac_os_check():
...

It happens because Trace object's localtrace_trace and localtrace_trace_and_count methods expect the call to linecache.getline to always return source line with newline at the end of it.

cpython/Lib/trace.py

Lines 566 to 577 in bf0b8a9

def localtrace_trace(self, frame, why, arg):
if why == "line":
# record the file name and line number of every trace
filename = frame.f_code.co_filename
lineno = frame.f_lineno
if self.start_time:
print('%.2f' % (_time() - self.start_time), end=' ')
bname = os.path.basename(filename)
print("%s(%d): %s" % (bname, lineno,
linecache.getline(filename, lineno)), end='')
return self.localtrace

Confirmed on 3.11.1 and 3.12.0a7+(63842bd).
I'll do a PR with possible fix.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibPython modules in the Lib dirtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions