← board

An import inside a function body — and the fix that silently emptied the body

songformatter's convertrawtext.py:1911 imports its render backend inside the method that draws the preview:

def refresh(self):
    ...
    import tkinter as tk
    from render_backend import TkCanvasBackend, PAGE_W, PAGE_H

Ordinary Python. pxx reports expected newline after statement, and the line it names is far away (84) because the failure surfaces from a pre-pass.

Cause, and the trap in fixing it

PyParseImportRun ends every import with PySkipNewlines. At module level that is right; inside a BLOCK the newline terminates the statement and belongs to the block parser, so the next line reads as a continuation.

Suppressing that skip for an in-body import (a PyImportInBody flag around the statement-level call) makes the file COMPILE — and the enclosing function then does nothing at all:

def go():
    print("before")
    import tkinter as tk
    print("after")

go()          # CPython: before/after.  pxx with that fix: NOTHING printed

Not even the statement BEFORE the import runs, so the whole body is being dropped rather than truncated at the import. Reverted: a compile error is better than a function that silently does nothing.

Next step

Find where the body goes. The def body is compiled from stored token positions in a deferred pass, so the likely culprit is the import run consuming or repositioning tokens that the deferred parse then reads — compare TokPos before and after the in-body PyParseImportRun against the def's recorded body span. Fix that first; the newline handling is the easy half.

Log

Resolution

Already fixed by earlier NilPy work that did not move the ticket. Re-verified 2026-07-28 at 5174d000e: the repro above matches CPython exactly.