> We're getting this error from some of the python submits during rendering
> on some of our new machines:
>
> RuntimeError: Bad magic number in .pyc file
Yes, this happens if you have a mixed network of machines with old and new
versions of python with incompatible .pyc file formats.
For instance, mixing python 2.6 and 2.7 can cause this problem.
SIMPLE SOLUTION
===============
There are several possible solutions (see below), but all have caveats.
The easiest one is:
Remove all the *.pyc files from the submit script directory,
make the directory "read-only" to the render users
(e.g. writable only to root) so python can't re-create them.
Python will then operate normally with just the .py files,
and will work correctly across python versions old + new.
PROBLEM DESCRIPTION (IN DEPTH)
==============================
When python loads a .py file, it first "compiles" it into
a byte code format that it can then run.
As an optimization, someone on the python dev team decided it was a good
idea to have python try to save the compiled byte code in a .pyc file so
the next time someone runs the script, it can just load the .pyc file,
skipping the byte code compile step.
The way this was implemented:
When python is told to run a .py file, it first checks if there's
already a .pyc version of the file.
If the .pyc exists and has a newer date stamp than the .py,
python runs it.
If the .pyc /doesn't/ exist, or is older than the .py file,
python falls back to loading the .py file, compiles it to ram,
and attempts to write the compiled byte code out to a .pyc file
for next time, then runs the compiled code from ram.
If it can't write the .pyc file (due to e.g. write permissions),
it just runs the compiled .py file from ram.
Trouble is, if the pyc file's byte code format is incompatible,
then e.g. python 2.6 doesn't do the fallback to the .py file,
making this "Bad magic" problem fatal to running the script
(instead of an invisible skipped step)
This whole issue is raised in this python bug:
http://bugs.python.org/issue20794
One of the developers writes:
".pyc and .pyo files are in general not compatible across Python versions"
Great -- an easy situation to have if you have a mix of machines with
different default python versions all running the same .py script,
and no easy way to disable creation of.pyc files.
The .pyc file is supposed to be an optional optimization.
But python (e.g. 2.6) doesn't fall back to loading the .py file
if the .pyc exists but can't be loaded due to this error.
ALTERNATE SOLUTIONS TO THIS PROBLEM
===================================
There are other ways to avoid this problem without making the directory
read only, but all have annoying caveats.
In order of preference:
1. You can change the scripts to all invoke "python -B" which prevents
newer versions of python from writing out the .pyc files, side stepping
the problem.
Trouble is, some older versions of python don't support -B flag,
and fail to run the script if -B is specified.
But if your network has python versions that all support -B,
this could be your best solution.
One problem though is Windows: if a user clicks on a python script,
it may run it without the -B flag, generating the pyc.
You probably have to change the .py file association on all machines
to make sure the -B flag is included. Good luck with that.
This also means any time the script wants to invoke itself, it has
to include the -B flag, e.g. os.system("python -B /path/to/script.py -arg..")
2. You can set the PYTHONDONTWRITEBYTECODE environment variable;
if set, python won't try to write out the .pyc file.
But this is hard in practice.
The variable must be set BEFORE the python script runs, as the .pyc
is generated before the script runs. So you can't, for instance,
try setting the variable in the script.
And universally setting environment variables for the desktop environment
can be hard on some platforms (Mac, Linux).
All it takes is one guy to run the script without the variable set,
and the .pyc file will be created and cause trouble for everyone again.
3. Standardize on one version of python, and make it the default
on all machines, avoiding compatibility issues.
Trouble with that is you can break OS scripts that depend on specific
versions of python. Python has become a popular enough language that
operating systems now use it (e.g. in crontabs) to maintain the system.
Breaking those scripts can cause the OS to misbehave in unexpected ways.
And again, all it takes is one guy to accidentally use the wrong version
of python from a random machine to create an incompatible .pyc.
So unless python comes along with something better, I'm thinking
removing write permission is on the script directory is the best
approach.
It'd be nice if one could put a ".nopyc" file in the same directory as
the script(s), so if python sees that, it would skip generating/using .pyc files.
Too late for that though for the current issue, as old versions of python
don't have that feature.
|