VPython Common Errors and Troubleshooting: Difference between revisions

From Physics Book
Jump to navigation Jump to search
No edit summary
 
(18 intermediate revisions by 2 users not shown)
Line 1: Line 1:
(Lucas Christian, page 1 of 2)
Programming languages can often generate obscure and confusing error messages, and VPython is no exception.  This reference lists out the most common types of errors students encounter, with a brief explanation of why they happen and how to fix them.
 
This reference lists out some common errors I've seen students encounter while working in VPython.  Programming languages can often generate obscure and confusing error messages, and VPython is no exception.


==System/Environment Errors==
==System/Environment Errors==
Line 61: Line 59:
== Syntax Errors ==
== Syntax Errors ==


(work in progress; will cover common syntax errors)
A syntax error means Python cannot figure out what your program is asking it to do because you did not follow its grammar. VIDLE will highlight where the error occurred, but sometimes this highlight is misleading.
 
===Make sure parenthesis match up ===
 
Consider the following code (asterisks were placed around the part that where IDLE reported the syntax error):
 
## objects
particle = sphere(pos=vector(1e-10,0,0), radius=2e-11, color=color.red
## initial values
***obslocation*** = vector(3.1e-10, -2.1e-10, 0)  <- Error at word "obslocation"
 
You can look at that line all you want, but there is no error there.  Instead, look at the end of the <code>particle = sphere(...</code> line.  Notice there is no closing parenthesis.
 
## objects
particle = sphere(pos=vector(1e-10,0,0), radius=2e-11, color=color.red  <- Actual problem is HERE
## initial values
***obslocation*** = vector(3.1e-10, -2.1e-10, 0)  <- Python reports error at word "obslocation"
 
To fix this error, change the line to:
 
particle = sphere(pos=vector(1e-10,0,0), radius=2e-11, color=color.red)    <- closing parenthesis added
 
===Rules for variable names===
 
When Python is reading your code, it has to be able to identify when you are referring to a variable, as opposed to some other language construct, such as a literal number.  Here are a few rules to keep in mind:
 
* Variable names cannot contain spaces
* Variable names cannot start with a number
* Variable names cannot contain dashes (-), but underscores (_) are allowed
* Variable must not have the same name as built-in functions, statements, etc.
 
===While Loop Indentation===
 
In Python, while loops and if statements rely on indentation to define where they start and end.  When you're working with a while loop, '''every line of code inside the loop should have the same number of spaces in front of it'''.
 
while t <= 3.0:
    rate(3500)      ## slow down motion to make animation look nicer
    # Calculate Fgrav btwn. craft and the Earth
    rCraftEarth = Craft.pos - Earth.pos    <- Error: incorrect indentation
    fMagG1 = (G * mCraft * mEarth)/(mag(rCraftEarth) * mag(rCraftEarth))
 
If you fail to indent a line in the middle of a loop, Python is quite good about reporting it.  If you fail to indent a line at the end of a loop, Python assumes you meant for it to be outside of the loop, which does not generate any error but can cause your code to work incorrectly.
 
while t <= 3.0:
    rate(3500)      ## slow down motion to make animation look nicer
    (...)
t = t + deltat    <- This line should be in the loop, but it is not.
 
What belongs in the loop?  The hard and fast answer is '''anything that need to happen over and over again'''.  That's what the loop does: it runs the same code over and over again until its condition tells it to stop.  If you're animating an object that is experiencing a gravitational force, obviously we need to calculate the force over and over again.  We also need to update the particle's position and update the arrow each time as well.
 
Anything outside of the loop is executed only once.  In the example above, we left updating the time out of the loop.  Obviously, we meant for the time to increase with each run of the loop, but by leaving it out, this doesn't happen (n this particular example, because the loop depends on the time to know when to stop, the program would loop infinitely and our particle would never stop moving).


== Runtime Errors ==
== Runtime Errors ==
Line 150: Line 203:


Hence, when you see these kind of errors, always inspect the arguments you pass to the function, and if any of them are a variable, '''look back at how the variable was defined'''.  If all else fails, try placing each argument into a <code>print()</code> statement separately and make sure what prints out is the type you expect.
Hence, when you see these kind of errors, always inspect the arguments you pass to the function, and if any of them are a variable, '''look back at how the variable was defined'''.  If all else fails, try placing each argument into a <code>print()</code> statement separately and make sure what prints out is the type you expect.
=== TypeError: '*' object is not callable ===
In Python, function names are variables too, and are not protected in any way.  Because of this, it is totally legal to write:
vector = vector(5, 4, 3)
Here, we just replaced the vector function with, well, an actual vector.  When we try to create another vector later, we're actually attempting to call our vector variable as if it were a function.
'''Make sure you do not name a variable the same name as a function'''!
Also resist the temptation to create a sphere named sphere:
sphere = sphere(pos=(1,0,0), radius=2e-11, color=color.red)  // Our "sphere" just replaced the "sphere" function
If you do this, the error will not show up until you try to use the <code>sphere()</code> function later, which may be several lines after the actual mistake.  Instead, simply name you <code>sphere</code> something like <code>mySphere</code> or even better, use a precise name such as <code>sphereA</code> or <code>electron</code> (assuming the sphere represents an electron).  Remember, the name of variables is just a name—'''you can name your variables whatever you want (provided it is valid syntax), ''just don't name it after an existing function'''''.
[[Category:VPython]]

Latest revision as of 01:51, 22 October 2019

Programming languages can often generate obscure and confusing error messages, and VPython is no exception. This reference lists out the most common types of errors students encounter, with a brief explanation of why they happen and how to fix them.

System/Environment Errors

If your system is not set up correctly, or the environment you are running VPython code is incorrect, a number of mysterious errors can result.

VPython does not start or immediately freezes

Make sure you are running your code in VIDLE (not the identical-looking IDLE).

Use VIDLE instead of IDLE to avoid errors and crashes.

With the most current releases of VPython, code compiles and launches fine in IDLE, but the graphics window comes up grey and hangs. This is because of a bug in the way regular IDLE executes code, it has difficulty with programs that keep running in a loop, as VPython does so you can drag and zoom the display.

Note that if you double-click a .py file in Windows Explorer or Finder, it may open up in the regular IDLE instead of VIDLE. To check if your code is open in VIDLE, click the "Help" menu and look for the "VPython" menu item. Regular IDLE does not have a "VPython" item in the Help menu.

ImportError: No module named *

Traceback (most recent call last):
  File "/my/documents/folder/vectors.py", line 1
    from future import division
ImportError: No module named future

Python has only a small number of built-in functions. The rest are stored in "modules" that you can load when you need them. The from (blank) import (blank) lines tell Python to import the named functions from a specific module. When you import a module, Python searches various folders on your computer to find the requested module. If it cannot find a module with that name, you get an ImportError.

Cause #1: You made a typo in the module name.

The basic boilerplate for VPython programs written in this class:

from __future__ import division
from visual import *

Often missed are the two underscores ( _ _ ) not separated by a space before and after future. Check that this is correct, or copy-and-paste from above.

Cause #2: VPython is not installed correctly.

It is possible the module actually does not exist on your system. The VPython installer should install all the needed modules into the module folder for Python 2.7. If you have a different version of Python installed, it will not be able to find the modules. Make sure to follow the instructions on the VPython website, and install Python 2.7 from python.org as suggested.

NameError: name 'gdisplay' is not defined

This is often indicative of a missing import statement. Make sure your code begins with the boilerplate code above.

If you are using the graph functions, you will also need:

from visual.graph import *

"The function ‘CGContextErase’ is obsolete"

Users on Mac OS X may see this message printed whenever they run a VPython program:

The function ‘CGContextErase’ is obsolete and will be removed in an upcoming update.
Unfortunately, this application, or a library it uses, is using this obsolete function, 
and is thereby contributing to an overall degradation of system performance.

This message can be ignored and will have no impact on the running of your program.

Syntax Errors

A syntax error means Python cannot figure out what your program is asking it to do because you did not follow its grammar. VIDLE will highlight where the error occurred, but sometimes this highlight is misleading.

Make sure parenthesis match up

Consider the following code (asterisks were placed around the part that where IDLE reported the syntax error):

## objects
particle = sphere(pos=vector(1e-10,0,0), radius=2e-11, color=color.red

## initial values
***obslocation*** = vector(3.1e-10, -2.1e-10, 0)  <- Error at word "obslocation"

You can look at that line all you want, but there is no error there. Instead, look at the end of the particle = sphere(... line. Notice there is no closing parenthesis.

## objects
particle = sphere(pos=vector(1e-10,0,0), radius=2e-11, color=color.red  <- Actual problem is HERE

## initial values
***obslocation*** = vector(3.1e-10, -2.1e-10, 0)  <- Python reports error at word "obslocation"

To fix this error, change the line to:

particle = sphere(pos=vector(1e-10,0,0), radius=2e-11, color=color.red)    <- closing parenthesis added

Rules for variable names

When Python is reading your code, it has to be able to identify when you are referring to a variable, as opposed to some other language construct, such as a literal number. Here are a few rules to keep in mind:

  • Variable names cannot contain spaces
  • Variable names cannot start with a number
  • Variable names cannot contain dashes (-), but underscores (_) are allowed
  • Variable must not have the same name as built-in functions, statements, etc.

While Loop Indentation

In Python, while loops and if statements rely on indentation to define where they start and end. When you're working with a while loop, every line of code inside the loop should have the same number of spaces in front of it.

while t <= 3.0:
    rate(3500)       ## slow down motion to make animation look nicer

    # Calculate Fgrav btwn. craft and the Earth
   rCraftEarth = Craft.pos - Earth.pos     <- Error: incorrect indentation
    fMagG1 = (G * mCraft * mEarth)/(mag(rCraftEarth) * mag(rCraftEarth))

If you fail to indent a line in the middle of a loop, Python is quite good about reporting it. If you fail to indent a line at the end of a loop, Python assumes you meant for it to be outside of the loop, which does not generate any error but can cause your code to work incorrectly.

while t <= 3.0:
    rate(3500)       ## slow down motion to make animation look nicer

    (...)

t = t + deltat    <- This line should be in the loop, but it is not.

What belongs in the loop? The hard and fast answer is anything that need to happen over and over again. That's what the loop does: it runs the same code over and over again until its condition tells it to stop. If you're animating an object that is experiencing a gravitational force, obviously we need to calculate the force over and over again. We also need to update the particle's position and update the arrow each time as well.

Anything outside of the loop is executed only once. In the example above, we left updating the time out of the loop. Obviously, we meant for the time to increase with each run of the loop, but by leaving it out, this doesn't happen (n this particular example, because the loop depends on the time to know when to stop, the program would loop infinitely and our particle would never stop moving).

Runtime Errors

Even if Python understands the syntax of your program, it can still contain errors that pop up when it tries to run.

TypeError: unsupported operand type(s) for *

Consider this error and the line of code that produced it:

Traceback (most recent call last):
  File "/my/documents/folder/lab2.py", line 32
    E = oofpez * (qproton / (r**2)) * rhat
TypeError: unsupported operand type(s) for ** or pow(): 'vector' and 'int'

The error indicates that pow(), i.e. the exponent function, cannot operate on a vector and an int (an int is short for integer, a.k.a. a number/scalar).

r = vector(5, 4, 3) - particle.pos
rmag = sqrt(r.x**2 + r.y**2 + r.z**2)
rhat = r / rmag
E = oofpez * (qproton / (r**2)) * rhat  <-- ERROR

Looking at the code, we see that we typed r ** 2, i.e. squaring the vector r, or as we'd write it out on paper:

[math]\displaystyle{ \vec{r}^2 = \vec{r} * \vec{r} = \lt 5, 4, 3\gt * \lt 5, 4, 3\gt }[/math]

If you've taken linear algebra before, you're probably aware that multiplying vectors or matrices is very different from simply multiplying out scalars, and in fact, in this case, is undefined. The correct code here might have been:

E = oofpez * (qproton / (rmag**2)) * that

Some other operations to look out for:

  • Adding or subtracting a scalar from a vector or vice-versa
  • Divining a scalar by a vector
  • Multiplying or dividing two vectors

In VPython, there's no syntax to indicate that a variable is a vector. The easiest way to tell is look at where it was defined. For example, if we created the variable position with any of these lines of code, it would hold a vector:

position = vector(5, 4, 3)
position = (5, 4, 3)
position = arrow.pos     // arrow.pos is a vector property of the arrow object
position = arrow.pos * 5     // vector multiplied by a scalar is a vector

When tracing these errors, always look and make sure your variables hold the type of data you expect. When all else fails, you can use print(variable name) to examine the value.

ArgumentError: Python argument types in *** did not match C++ signature

If you pass the wrong type of data to a function, VPython prints all kinds of nasty jargon out.

ArgumentError: Python argument types in
    None.None(arrow, int)
did not match C++ signature:
    None(cvisual::primitive {lvalue}, cvisual::vector)

What the heck is a cvisual::primitive {lvalue}? Who knows? (it's some internal data type in the C++ code for VPython, and it's an error in VPython that we see this message instead of a nicer, more explanatory one). Our code that caused this error:

r = sqrt(5 ** 2 + 4 ** 2 + 3**2)
ea = arrow(pos=r, axis=E*scale, color=color.orange)

r was likely assumed to be a vector, but it actually appears to hold the magnitude of a vector someone calculated.

Consider another example:

Traceback (most recent call last):
  File "/my/documents/folder/lab2.py", line 33
    r = vector(x, 5, 2)
ArgumentError: Python argument types in
    vector.__init__(vector, vector, int, int)
did not match C++ signature:
    __init__(_object*, cvisual::vector)
    __init__(_object*)
    __init__(_object*, double)
    __init__(_object*, double, double)
    __init__(_object*, double, double, double)

The error points at this line:

r = vector(x, 5, 2)

Huh. That looks OK. Let's see how x is defined:

x = particle.pos
print(x)     // prints out <5, 4, 3>

Apparently x is a vector. So the line that threw the error looks like this to the computer:

r = vector(vector(5, 4, 3), 5, 2)     // This clearly doesn't make any sense

Hence, when you see these kind of errors, always inspect the arguments you pass to the function, and if any of them are a variable, look back at how the variable was defined. If all else fails, try placing each argument into a print() statement separately and make sure what prints out is the type you expect.

TypeError: '*' object is not callable

In Python, function names are variables too, and are not protected in any way. Because of this, it is totally legal to write:

vector = vector(5, 4, 3)

Here, we just replaced the vector function with, well, an actual vector. When we try to create another vector later, we're actually attempting to call our vector variable as if it were a function.

Make sure you do not name a variable the same name as a function!

Also resist the temptation to create a sphere named sphere:

sphere = sphere(pos=(1,0,0), radius=2e-11, color=color.red)  // Our "sphere" just replaced the "sphere" function

If you do this, the error will not show up until you try to use the sphere() function later, which may be several lines after the actual mistake. Instead, simply name you sphere something like mySphere or even better, use a precise name such as sphereA or electron (assuming the sphere represents an electron). Remember, the name of variables is just a name—you can name your variables whatever you want (provided it is valid syntax), just don't name it after an existing function.