How to get lineno of "end-of-statement" in Python ast
<p>I am trying to work on a script that manipulates another script in Python, the script to be modified has structure like:</p>

<pre><code>class SomethingRecord(Record):
    description = 'This records something'
    author = 'john smith'
</code></pre>

<p>I use <code>ast</code> to locate the <code>description</code> line number, and I use some code to change the original file with new description string base on the line number. So far so good.</p>

<p>Now the only issue is <code>description</code> occasionally is a multi-line string, e.g.</p>

<pre><code>    description = ('line 1'
                   'line 2'
                   'line 3')
</code></pre>

<p>or</p>

<pre><code>    description = 'line 1' \
        'line 2' \
        'line 3'
</code></pre>

<p>and I only have the line number of the first line, not the following lines. So my one-line replacer would do</p>

<pre><code>    description = 'new value'
        'line 2' \
        'line 3'
</code></pre>

<p>and the code is broken. I figured that if I know both the lineno of start and end/number of lines of <code>description</code> assignment I could repair my code to handle such situation. How do I get such information with Python standard library?</p>

<p>My solution takes a different path: When I had to change code in another file I opened the file, found the line and got all the next lines which had a deeper indent than the first and return the line number for the first line which isn't deeper. 
I return None, None if I couldn't find the text I was looking for.
This is of course incomplete, but I think it's enough to get you through :)</p>

<pre><code>def get_all_indented(text_lines, text_in_first_line):
    first_line = None
    indent = None
    for line_num in range(len(text_lines)):
        if indent is not None and first_line is not None:
            if not text_lines[line_num].startswith(indent):
                return first_line, line_num     # First and last lines
        if text_in_first_line in text_lines[line_num]:
            first_line = line_num
            indent = text_lines[line_num][:text_lines[line_num].index(text_in_first_line)] + ' '  # At least 1 more space.
    return None, None
</code></pre>

python abstract-syntax-tree