The simplest way of doing this is to simply scan the file line by line and add the statements when you find a line that matches.
The following code does what you want, but it is not robust at all:
def add_info_on_loops(iterable):
in_loop = False
for line in iterable:
if not in_loop:
if line.startswith('for ') or line.startswith('while '):
in_loop = True
yield 'count = 0\n'
yield 'print "Entry of loop"\n'
yield line
yield ' print "Iteration Number:", count'
yield ' count += 1\n'
else:
yield line
else:
if not line.startswith(' '):
in_loop = False
yield 'print "Exit of loop"\n'
yield line
Usage:
>>> code = StringIO("""[code Starts]
... .
... .
... .
... while [condition]:
... [statements]
... [statements]
... [statements]
...
... .
... .
... .
... [code ends]""")
>>> print ''.join(add_info_on_loops(code))
[code Starts]
.
.
.
count = 0
print "Entry of loop"
while [condition]:
print "Iteration Number:", count count += 1
[statements]
[statements]
[statements]
print "Exit of loop"
.
.
.
[code ends]
Pitfalls of the code:
- The code handles only loops at the top level. Something like
if condition: for x in a: ... isn't recognized. This can be solved stripping the lines of whitespace before checking if we got a loop or not(but you then must take into account the different levels of indentation etc.)
- The code breaks whenever a loop has a line that isn't indented. This will happen, for example, if you "split" the code with a blank line and the IDE strips the whitespace. A solution might be to wait for a non-blank, non-indented line instead of a non-indented line.
- The code doesn't handle tabs for indentation(easily fixed)
- The code doesn't handle one-line loops (e.g.
for x in a: print x). In this case you'll obtain a wrong output. Easily fixed checking whether there is something after the :.
- Using a single
count variable is troublesome if you want to add support for nested loops. You should probably have an integer id somewhere and use variable names such as count_0, count_1 with the id that is incremented every time you find a new loop.
- The code doesn't handle expressions with parenthesis that do not have whitespace from the keyboard. e.g.
for(a,b) in x: isn't detected as a loop, while for (a,b) in x: is detected. This can be easily solved. First you check whether the line starts with for and while and the next character must not be a letter, number, underscore(actually in python3 you can use unicode characters as well, and this becomes harder to test, but possible).
- The code doesn't handle source code that ends with an indented loop line. e.g.
for x in a: indented_last_line_of_code() the exit print wont be added.(easily fixed adding a check on in_loop outside the for of the function to see whether we have this situation).
As you can see writing a piece of code that does what you asked is not so trivial.
I believe the best you can do is to use ast to parse the code then visit the tree and add the nodes at the correct places, then re-visit the code and generate the python source code(usually nodes have indication on the line in the source code, which allows you to copy-paste the exact same code).
astmodule? This task is very similar to your previous question.if some condition: for elem in iterable: do stuffdo you want to add the code for the innerfor? Do you mind nested loops? Do you want to handle one-line loops(e.g.for x in a: print x)? In the simplest case it should be pretty easy to simply read the file line by line and output the extra lines when needed, otherwise you have to do more parsing.