Reputation: 199
import inspect
def a(x, y, z):
frame = inspect.stack()[1]
print(frame.code_context)
def b():
a(
1,
2,
3,
)
b()
>> [' 3,\n']
Why is code_context only returning the last line?? The documentation says code_context is "a list of lines of context from the source code"
I would expect the code_context to include something along the lines of:
[
' 1,\n',
' 2,\n',
' 3,\n',
]
I would like to obtain all lines of context.
Upvotes: 0
Views: 2116
Reputation: 106543
For a robust solution that preserves white spaces and comments, you can use the lib2to3
module to parse and scrape all the simple statement nodes (denoted by simple_stmt
in the Python grammar from Grammar.txt) from the file the parent frame belongs to, and return the node whose starting line number and the number of lines (calculated by counting the number of newline characters) cover the line number of the frame. Note that the statement node does not contain the preceding indentation if it's at the beginning of a code block, however, so you would have to obtain the indentation from its previous sibling node if it is a node of white spaces:
from lib2to3 import fixer_base, refactor
class StatementScraper(fixer_base.BaseFix):
PATTERN = 'simple_stmt'
def __init__(self, lineno):
super().__init__(None, None)
self.lineno = lineno
self.statement = ''
def transform(self, node, result):
if not self.statement and self.lineno - node.get_lineno() < str(node).count('\n'):
prev_sibling = str(node.prev_sibling)
if prev_sibling.isspace():
self.statement += prev_sibling.lstrip('\n')
self.statement += str(node)
return node
class get_statement(refactor.RefactoringTool):
def __init__(self, source, lineno):
self.source = source
self.scraper = StatementScraper(lineno)
super().__init__(None)
def get_fixers(self):
return [self.scraper], []
def __str__(self):
self.refactor_string(self.source, '')
return self.scraper.statement
so that:
import inspect
def a(x, y, z):
frame = inspect.stack()[1].frame
print(get_statement(open(frame.f_code.co_filename).read(), frame.f_lineno))
def b():
a(
1,
2,
3,
)
b()
outputs:
a(
1,
2,
3,
)
Demo: https://repl.it/@blhsing/HotpinkOpenCgibin
Upvotes: 3
Reputation: 106543
The Python interpreter retains only a single line number for each frame unfortunately. One relatively easy and robust way to seeing the entire code context is by decompiling the code object using the excellent uncompyle6
module. Since the code object does not retain white spaces and comments, you'll see the more compact version of your original code as the decompiled output:
import inspect
from io import StringIO
from uncompyle6 import deparse_code2str
def a(x, y, z):
frame = inspect.stack()[1]
code = StringIO()
deparse_code2str(frame.frame.f_code, out=code)
print(code.getvalue())
def b():
a(
1,
2,
3,
)
b()
This outputs:
a(1, 2, 3)
Demo: https://repl.it/@blhsing/PastelPunyProcess
Upvotes: 2