Debugging Python Graphics

When a drawing program does something you did not expect, you can stop it at a line and look at its variables, step through it a line at a time, read its errors and printed output, and watch its frame rate. This page covers all of them for a Python file with the preview on.

Errors: read them, then tap them

When your program stops with an error, the message appears in red under the preview, with the line it happened on:

Traceback (most recent call last):
  line 14, in update
NameError: name 'speed' is not defined

Tap or click the error and the editor jumps to that line, ready to fix. On a phone it switches to the code to show you.

A mistake in a drawing call, such as a misspelt name (ctx.fil_rect), is reported the same way, with the line in your file that made it:

line 6: TypeError: ctx has no method "fil_rect"

Printing

print() works as usual. What you print appears under the preview, next to any errors. It is the quickest way to see a value:

score = 0

def update(dt):
    global score
    score += 1
    if score % 60 == 0:
        print("score is", score)

def draw():
    ctx.fill_style = "black"
    ctx.fill_rect(0, 0, width, height)

Print now and then, as above, rather than every frame: sixty lines a second is hard to read. The button at the top of the output clears it.

Breakpoints: stop at a line

A breakpoint stops the program just before a line runs, so you can look at every variable at that moment.

  1. Add a breakpoint: tap or click just left of a line number. A red dot appears. On a touch screen you can also press and hold the line and choose Breakpoint. With the cursor on a line, F9 adds or removes one.
  2. The bug lights up. The Debugging button in the footer is dim until the file has a breakpoint; adding one lights it, which means Run stops at breakpoints.
  3. Press Run. The program runs until it reaches a breakpoint, then stops. The line it stopped on is highlighted.

To run straight through without removing your breakpoints, tap the lit to turn debugging off; tap it again to turn it back on. Tap a red dot to remove that breakpoint.

The debug bar

While the program is being debugged, a bar is docked above the code:

ButtonWhat it does
`icon:SquareStop`
`icon:PlayContinue`
`icon:CornerDownRightOver`
`icon:ArrowDownToLineInto`
`icon:ArrowUpFromLineOut`
LineThe line it stopped on; it reads Running between stops

Looking at variables

Open the Debug tab in the sidebar. While the program is stopped it lists your variables and their values: numbers, text, True/False, and lists and dictionaries with their length. Both the variables of the function it stopped in and the ones at the top of the file are shown. The Debug tab also lists your breakpoints and has the same step and continue controls.

A breakpoint in draw() or update()

These functions run every frame, so a breakpoint inside one stops every frame: press Continue and it stops again on the next frame. That is useful for stepping through one frame at a time. To let the program run on, turn debugging off with , or remove the breakpoint.

A breakpoint inside an if stops only when that if is true, which is a good way to catch a rare moment. For example, put one on lives -= 1 in the game tutorial to stop at the instant a life is lost.

Where stopping at a breakpoint works

Stopping at a breakpoint works when the file runs on iPhone or iPad, with Circuitry's built-in Python. Everywhere else (the desktop app, and the Python that runs inside the page) the program runs straight through your breakpoints, and the output under the preview says so when the run starts. Use print() there. See where your Python runs.

The frame rate

Frame rate, in the footer, shows a small number in the top-right corner of the preview while the program runs: how many frames it drew in the last second. Most screens show 60 a second, and some phones and tablets 120.

If the number drops, your program is doing more each frame than the device can keep up with. The usual causes:

  • Reading values back with await every frame. Each read waits a whole frame. Keep your numbers in Python instead (see Tips and limits).
  • Very many separate drawing calls. Thousands of shapes a frame is fine; tens of thousands is slow. Draw fewer, bigger things, or join many lines into one path and stroke() it once.
  • Heavy Python work every frame. Work things out once at the start and keep the results.

When the preview is frozen or stops moving

If the preview stays blank or stops changing, the program is usually stuck. When draw() or update() has not finished for three seconds, the preview says so under the picture; a loop at the top of the file that never waits just leaves the preview blank. The usual cause is a while True: loop that never waits: every loop that runs forever must await frame() (or await sleep(...)) inside it. Press Stop; see Tips and limits if Stop does not free it.