When something goes wrong¶
Everyone sees error messages. They are not a telling-off: they tell you what to change.
How to read one. Python prints a long message when a sketch stops. Read the last line
first. It names the kind of error (ValueError, RuntimeError, TypeError, NameError) and says
what went wrong. The lines above it show where: the file name and the line number in your sketch.
funground's own messages are written to be read. Most say what is wrong and what to try. The
messages below are the real ones. Where a message has your own words in it (a colour name, a file
name), they are shown here as 'tomatoe' or 'photo.png'.
Words you do not know? See the glossary.
- The sketch does not start
- Python errors in sketches
- Drawing and style
- Files
- Saving and recording
- Controls
- Sound and the microphone
- Warnings
The sketch does not start¶
Nothing happens, or "never started"¶
Your sketch has a draw() function but never started. Add f.run() as the last line.
An animated sketch needs f.run() as its last line. Without it, Python reads the file, defines
your functions and stops. funground prints the message above when you run the file from a terminal.
In IDLE or Thonny you may see nothing at all. A script (no draw()) needs f.show() instead if you
want to look at it.
def draw():
f.circle(100, 100, 50)
f.run() # the last line
The window opens and closes at once¶
Usually one of these:
- The file is a script (no
draw()) and has nof.show()at the end. It draws, saves, and ends. Addf.show()as the last line to keep the window open. draw()stops itself withf.stop()orf.exit(), or the sketch hasf.run(max_frames=...).- An error happened. Look in the terminal for a message: the window closes when the sketch stops.
- You ran it from an editor that shows only a short flash of output. Run it from a terminal with
python my_sketch.pyand read what is printed.
This file mixes the two styles¶
This file mixes the two styles: it draws at the top level (a script) and also calls f.run() (an
animated sketch). Pick one. For an animation, move the drawing into draw(). For a script, remove
f.run() and end with f.show().
A file is either a script (lines run from top to bottom, ending with f.show()) or an
animated sketch (setup() and draw() and f.run()). Chapter 2 explains both.
Drawing at the top level and calling f.run() is mixing them. Move those lines into draw().
f.run() found a setup() but no draw()¶
f.run() found a setup() but no draw(). To animate, add a draw() function. To draw once, remove
setup() and f.run(), write the drawing at the top level and end with f.show() (a script).
An animated sketch needs a draw(), even if it is only def draw(): pass. If you only want one
still picture, write a script instead.
No drawing window yet¶
No drawing window yet. Call f.size(...) first.
You tried to draw before there was a canvas. In a script, call f.size(width, height) before the
first drawing line. In an animated sketch, call f.size() in setup(). Do not draw at the top of
the file, outside any function, before f.run(): that is the "mixes the two styles" error above.
f.size(400, 300) # first
f.circle(200, 150, 80) # then draw
width and height must be positive¶
f.size(0, 100) and f.size(-5, 50) give ValueError: width and height must be positive.
A canvas needs a size above zero in both directions. Also check that you gave numbers: f.size("400", 300)
gives a TypeError that talks about '<=' and str.
Installing: the Cairo error on Linux¶
On Linux, pip install funground may stop with a long message about pycairo, such as
Failed building wheel for pycairo or Dependency 'cairo' not found. funground draws with the
Cairo library, and pip needs its development files to build the Python part. This is a pip message,
not a funground one. Install the system package first, then run pip again:
sudo apt install libcairo2-dev pkg-config python3-dev
python -m pip install funground
Other Linux distributions have an equivalent package (look for "cairo development files"). On Windows and macOS, pip normally finds a ready-made version and needs nothing more. See chapter 1.
No module named 'funground'¶
ModuleNotFoundError: No module named 'funground'
Python cannot find funground. Usually the virtual environment is not switched on, or you ran
pip install in a different one. Switch it on (.venv\Scripts\activate on Windows,
source .venv/bin/activate on macOS and Linux) and try again. Also check that your own file is not
called funground.py: Python would read that instead of the library.
Python errors in sketches¶
These come from Python, not from funground, but you will meet them in your first sketches.
NameError or AttributeError on an f. name¶
AttributeError: module 'funground' has no attribute 'cirle'
NameError: name 'f' is not defined
module 'funground' has no attribute 'cirle'is a typo in a name afterf.. It should bef.circle. Names are lower case with underscores:f.stroke_width, notf.strokeWidth. If you are not sure of a name, look in the Quick Reference, or ask Python:print(dir(f)).name 'f' is not definedmeans the first line is missing. Start every sketch withimport funground as f.'TextIOWrapper' object has no attribute 'circle'(or similar) meansfhas been used for something else, oftenwith open("x.txt") as f:. Use another name for your own variables.NameError: name 'circle' is not definedmeans you left off thef.: writef.circle(...).
IndentationError and SyntaxError¶
IndentationError: expected an indented block after function definition on line 4
SyntaxError: '(' was never closed
SyntaxError: expected ':'
Python uses the spaces at the start of a line to know what belongs inside def draw():. Every line
inside needs the same indent (4 spaces is usual). Do not mix tabs and spaces. A SyntaxError usually
means a missing bracket, quote or colon just before the line Python points at. Check that every
( has its ) and every def, if, for and with line ends with :.
UnboundLocalError: a variable that draw() changes¶
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
You made x at the top of the file and then changed it inside draw(). Python needs to be told:
add global x as the first line of draw(). See chapter 2.
TypeError: missing arguments¶
TypeError: circle() missing 1 required positional argument: 'diameter'
You gave a function too few numbers. f.circle(x, y, diameter) needs three. The message names the
one that is missing. Chapter 3 lists what each shape needs. Too many numbers gives
circle() takes 3 positional arguments but 5 were given, which is the same kind of mistake.
Drawing and style¶
A colour is not accepted¶
ValueError: unknown colour 'tomatoe'. Use a name like 'tomato', a tuple like (255, 99, 71) or a hex string like '#FF6347'.
ValueError: a colour tuple needs 2, 3 or 4 numbers (grey, alpha or red, green, blue[, alpha]), got 5
ValueError: colour component r=300 must be an integer from 0 to 255
TypeError: True is not a colour: True and False are not numbers here
ValueError: f.fill() and friends take more than one argument only for numbers, not 'red': ...
Each one is a small mistake in a colour:
- A name is spelt wrongly. Check it against the list of names.
- A tuple has the wrong number of values. Use
(grey, alpha),(red, green, blue)or(red, green, blue, alpha). - A number is outside 0 to 255 (unless you changed
f.color_mode()). - A name goes with other numbers:
f.fill("red", 100)is not allowed. Give a name on its own, or use numbers, or use a tuple such as(255, 0, 0, 100).
See chapter 4.
A word is not one of the choices¶
ValueError: f.stroke_cap() takes one of 'round', 'square', 'butt', not 'pointy'
ValueError: f.rect_mode() takes one of 'corner', 'corners', 'center', 'radius', not 'middle'
ValueError: f.text_align() takes one of 'left', 'center', 'right' first, not 'middle'
Some functions take a word, such as "round". The message lists every word that works. Copy
one of them. Spelling matters, and so does the American "center".
unknown page size¶
ValueError: unknown page size 'A9': use one of A3, A4, A5, B5, Letter, Legal, Tabloid, Square
(add "Landscape" to turn it on its side, e.g. "A4Landscape")
Page names are listed in chapter 13. Or give a width
and a height in pixels instead: f.new_page(300, 200).
Functions that need a shape, a layer or a picture¶
RuntimeError: f.end_shape() called outside a shape: call f.begin_shape() first.
RuntimeError: f.curve_vertex() called outside a shape: call f.begin_shape() first.
ValueError: f.hide_layer(): there is no layer called 'nope'. Layers so far: none yet
RuntimeError: f.layer() cannot be used inside another layer block: layers do not nest. ...
TypeError: f.image() needs a picture made with f.create_graphics(), not str (or an image file loaded with f.load_image())
f.vertex(),f.curve_vertex()andf.end_shape()belong betweenf.begin_shape()andf.end_shape(). See chapter 9.- A layer is made the first time you use its name in
with f.layer("name"):. Hide it only after that. A layer block cannot sit inside another layer block. f.image("photo.png", 0, 0)gives the TypeError above: a file name is only text. Load it first withphoto = f.load_image("photo.png"), then drawphoto.
f.update_pixels() needs f.load_pixels() first¶
RuntimeError: f.update_pixels() needs f.load_pixels() first: it copies the canvas into pixels, which you then change
Call f.load_pixels(), change f.pixels, then call f.update_pixels(), in that order. Chapter
9.
Files¶
A file is not found¶
FileNotFoundError: f.load_image(): no image file found at 'C:\sketches\photo.png' or 'C:\Users\you\photo.png'
f.load_image(), f.load_font(), f.load_sound() and f.load_svg() all give a message like this one.
It names both places funground looked: first next to your sketch file, then in the folder you ran
Python from. To fix it:
- Check the spelling and the ending (
photo.jpgis notphoto.jpeg). - Put the file in the same folder as your sketch.
- Or give the full path to the file.
A relative path such as "images/photo.png" is looked for from those same two places.
An SVG is not an image¶
ValueError: f.load_image(): 'badge.svg' is an SVG file. SVG files cannot be loaded as images; use f.load_svg() to read them as drawings
Use f.load_svg("badge.svg") for SVG files, as in chapter 9.
A system font is not installed¶
FileNotFoundError: f.system_font(): no installed font with the family name 'Nopefont Zzz'
f.system_font() finds fonts that are installed on your computer, by their family name. The name
may be spelt differently on your system. Look in your Fonts folder. Or use a font file with
f.load_font("MyFont.ttf"), which works on every computer. See chapter 6.
Saving and recording¶
The file ending is not supported¶
ValueError: cannot save 'a.jpg': use one of .png, .pdf, .svg
f.save() writes .png, .pdf and .svg (and .gif or .mp4 for several frames). It does not write
JPEG. Change the ending. See chapter 13.
save_frames needs a number marker¶
ValueError: f.save_frames() needs one run of # in the name for the number, e.g. "frames/####.png", not 'frames.png'
Put #### in the name where the frame number should go.
Animation functions in a script, and script functions in an animation¶
RuntimeError: f.no_loop() is for animated sketches, and this file is a script (it has no draw()). To animate, write a draw() function and end the file with f.run().
RuntimeError: f.show() is for scripts. An animated sketch already has its window: remove f.show() and end the file with f.run().
RuntimeError: f.new_page() is for scripts (a file with no draw()). An animated sketch has one canvas: ...
Some functions only make sense in one style:
| Only in an animated sketch | Only in a script |
|---|---|
f.no_loop(), f.loop(), f.redraw(), f.exit() |
f.show() |
f.save_frames(), f.save_gif(), f.save_movie() |
f.new_page(), f.frame_duration() |
Controls such as f.create_slider() |
Decide which style the file is, and remove the call that does not belong. See chapter 2.
A GIF or MP4 cannot be made¶
RuntimeError: f.save_gif() and saving a .gif need Pillow or ffmpeg, and neither was found. The easy way is to install Pillow with: pip install funground[extras]
RuntimeError: Saving an .mp4 needs ffmpeg, a free program, and funground cannot find it. Install it, then close and reopen your terminal. ...
A GIF needs a free Python package called Pillow: pip install funground[extras]. An MP4 needs ffmpeg:
pip install funground[video] brings its own copy. Close and reopen your terminal afterwards. See
chapter 13.
Recording sizes and pages¶
ValueError: f.save('x.gif'): every page of a GIF must be the same size. Page 1 is 200 x 120 but page 2 is ...
means a flip book has pages of different sizes. A GIF or MP4 keeps one size, so use f.new_page() with
no size to keep the same one. f.save_gif() while another recording is still running gives a
RuntimeError: wait until the first has finished.
Controls¶
Controls in draw()¶
RuntimeError: Controls are made once, in setup() (or at the top of the file), not in draw(): draw() runs every frame, so it would make a new one each time. Make the control in setup(), keep it in a variable, and read it in draw().
f.create_slider(), f.create_checkbox() and f.create_button() go in setup(), and their results go
in a variable that draw() can reach (use global). Then read them in draw():
def setup():
global size
f.size(400, 300)
size = f.create_slider(10, 120, 60)
def draw():
f.circle(200, 150, size.value())
Controls in a script¶
RuntimeError: Controls need an animated sketch, and this file is a script (it ends with f.show()). ...
A script has no loop to read a control. Rewrite the file as a sketch with setup(), draw() and
f.run(). A slider with low that is not below high gives
ValueError: a slider needs low below high. See chapter 10.
Sound and the microphone¶
A tune is not understood¶
ValueError: f.note(): 'H4' is not a note name. Try a letter A-G, an optional # or b, and an octave, like 'A4', 'C#5' or 'Bb3'
ValueError: f.melody(): bad token 'H4': 'H4' is not a note name
ValueError: f.tone(): wave must be one of sine, square, saw, triangle, soft, noise, not 'wobble'
ValueError: f.tone(): volume must be at most 1, not 2
f.melody() names the exact word it could not read (a token). Note names go from A to G, so H4
is not one. After the letter comes an optional # or b, then the octave number. The error for a
wave lists the ones you can use. Volumes go from 0 to 1. See chapter 16.
A raga or a tala is not in the table¶
ValueError: f.raga(): 'Nope' is not in funground's raga table. It has: Yaman, Bhupali, Bilawal, Khamaj, ...
ValueError: f.tala(): 'Nope' is not in funground's tala table. It has: Teentaal, Ektaal, Jhaptaal, ...
The message lists every name that works. Capital letters do not matter, but spelling does: f.ragas() and
f.talas() print the lists. See chapter 17.
No microphone¶
RuntimeError: f.microphone(): no microphone was found on this computer. Check that one is plugged in. On a Mac, allow microphone access in System Settings, Privacy & Security, Microphone.
Check that a microphone is plugged in and that it is the default input. On a Mac, allow it in System
Settings. On Windows, check Settings, Privacy, Microphone. f.microphones() lists the ones funground
can see. If you pass part of a name, such as f.microphone("USB"), and no microphone has it, you get a
similar message that lists the ones that do exist.
If your microphone is not found by your computer, no sketch can use it. Test the microphone in another program first.
A sketch with a microphone still runs where there is none, if you set FUNGROUND_HEADLESS=1: the
microphone is then silent.
The microphone needs a newer pygame¶
RuntimeError: microphone input needs pygame-ce 2.5 or newer ... Update it with: pip install --upgrade pygame-ce
Run the command in the message in your virtual environment.
The sound is silent¶
No error, but you hear nothing. Check the computer's volume and the speakers. A sound loaded with
no sound device (or with FUNGROUND_HEADLESS=1) plays in silence on purpose, and keeps time. Also
check sound.set_volume() and that you called play() or loop().
A microphone method that needs the whole sound¶
ValueError: microphone.tempo() looks at a whole sound. Use microphone.capture(seconds).tempo() to look at what was heard
A microphone has no end, so it has no tempo or key. Capture a few seconds first, and ask the capture. See chapter 16.
Warnings¶
A warning is not an error. The sketch carries on, and funground prints a note.
FungroundWarning: draw() finished with 1 f.push() call(s) still open; funground popped them for you. Add a matching f.pop(), or use `with f.saved_state():`.
FungroundWarning: f.pop() called without a matching f.push(); ignored.
FungroundWarning: draw() finished inside a shape: f.begin_shape() had no f.end_shape(), so nothing was drawn for it.
Each f.push() needs one f.pop(), and each f.begin_shape() needs an f.end_shape(). The safest way
is with f.saved_state():, which closes itself. See chapter 8.
Still stuck?¶
- Read the last line of the message again. Then read the line number above it.
- Make the sketch smaller. Delete lines until the error goes, then put the last one back.
- Print what you have:
print(x)shows a value in the terminal. - Compare with a working example in the gallery that does something close.
- Look up the name in the Quick Reference.