Parsing Python function calls to get argument positions

2024/10/2 12:34:28

I want code that can analyze a function call like this:

whatever(foo, baz(), 'puppet', 24+2, meow=3, *meowargs, **meowargs)

And return the positions of each and every argument, in this case foo, baz(), 'puppet', 24+2, meow=3, *meowargs, **meowargs.

I tried using the _ast module, and it seems to be just the thing for the job, but unfortunately there were problems. For example, in an argument like baz() which is a function call itself, I couldn't find a simple way to get its length. (And even if I found one, I don't want a bunch of special cases for every different kind of argument.)

I also looked at the tokenize module but couldn't see how to use it to get the arguments.

Any idea how to solve this?

Answer

This code uses a combination of ast (to find the initial argument offsets) and regular expressions (to identify boundaries of the arguments):

import ast
import redef collect_offsets(call_string):def _abs_offset(lineno, col_offset):current_lineno = 0total = 0for line in call_string.splitlines():current_lineno += 1if current_lineno == lineno:return col_offset + totaltotal += len(line)# parse call_string with astcall = ast.parse(call_string).body[0].value# collect offsets provided by astoffsets = []for arg in call.args:a = argwhile isinstance(a, ast.BinOp):a = a.leftoffsets.append(_abs_offset(a.lineno, a.col_offset))for kw in call.keywords:offsets.append(_abs_offset(kw.value.lineno, kw.value.col_offset))if call.starargs:offsets.append(_abs_offset(call.starargs.lineno, call.starargs.col_offset))if call.kwargs:offsets.append(_abs_offset(call.kwargs.lineno, call.kwargs.col_offset))offsets.append(len(call_string))return offsetsdef argpos(call_string):def _find_start(prev_end, offset):s = call_string[prev_end:offset]m = re.search('(\(|,)(\s*)(.*?)$', s)return prev_end + m.regs[3][0]def _find_end(start, next_offset):s = call_string[start:next_offset]m = re.search('(\s*)$', s[:max(s.rfind(','), s.rfind(')'))])return start + m.start()offsets = collect_offsets(call_string)   result = []# previous endend = 0# given offsets = [9, 14, 21, ...],# zip(offsets, offsets[1:]) returns [(9, 14), (14, 21), ...]for offset, next_offset in zip(offsets, offsets[1:]):#print 'I:', offset, next_offsetstart = _find_start(end, offset)end = _find_end(start, next_offset)#print 'R:', start, endresult.append((start, end))return resultif __name__ == '__main__':try:while True:call_string = raw_input()positions = argpos(call_string)for p in positions:print ' ' * p[0] + '^' + ((' ' * (p[1] - p[0] - 2) + '^') if p[1] - p[0] > 1 else '')print positionsexcept EOFError, KeyboardInterrupt:pass

Output:

whatever(foo, baz(), 'puppet', 24+2, meow=3, *meowargs, **meowargs)^ ^^   ^^      ^^  ^^    ^^       ^^        ^
[(9, 12), (14, 19), (21, 29), (31, 35), (37, 43), (45, 54), (56, 66)]
f(1, len(document_text) - 1 - position)^^                               ^
[(2, 3), (5, 38)]
https://en.xdnf.cn/q/70856.html

Related Q&A

Is there a proper way to subclass Tensorflows Dataset?

I was looking at different ways that one can do custom Tensorflow datasets, and I was used to looking at PyTorchs datasets, but when I went to look at Tensorflows datasets, I saw this example: class Ar…

Install pyserial Mac OS 10.10?

Attempting to communicate with Arduino serial ports using Python 2.7. Have downloaded pyserial 2.7 (unzipped and put folder pyserial folder in python application folder). Didnt work error message. &quo…

Binning frequency distribution in Python

I have data in the two lists value and freq like this:value freq 1 2 2 1 3 3 6 2 7 3 8 3 ....and I want the output to be bin freq 1-3 6 4-6 2 7-9 6 ...I can write fe…

R style data-axis buffer in matplotlib

R plots automatically set the x and y limits to put some space between the data and the axes. I was wondering if there is a way for matplotlib to do the same automatically. If not, is there a good form…

Python code for the coin toss issues

Ive been writing a program in python that simulates 100 coin tosses and gives the total number of tosses. The problem is that I also want to print the total number of heads and tails.Heres my code:impo…

Preprocess a Tensorflow tensor in Numpy

I have set up a CNN in Tensorflow where I read my data with a TFRecordReader. It works well but I would like to do some more preprocessing and data augmentation than offered by the tf.image functions. …

Os.path : can you explain this behavior?

I love Python because it comes batteries included, and I use built-in functions, a lot, to do the dirty job for me.I have always been using happily the os.path module to deal with file path but recentl…

admin.py for project, not app

How can I specify a project level admin.py?I asked this question some time ago and was just awarded the Tumbleweed award because of the lack of activity on the question! >_<Project:settings.py a…

Python Socket Receive/Send Multi-threading

I am writing a Python program where in the main thread I am continuously (in a loop) receiving data through a TCP socket, using the recv function. In a callback function, I am sending data through the …

numpy array2string applied on huge array, skips central values, ( ... in the middle )

I have array of size (3, 3, 19, 19), which I applied flatten to get array of size 3249.I had to write these values to file along with some other data, so I did following to get the array in string.np.a…