tags:

views:

421

answers:

1

I'm having a similar problem to that described in ".cgi problem with web server", although I reviewed and tested the previously suggested solutions without success.

I'm running the same program on Mac OS X 10.5.8, Apache 2.2.13, using Python 2.6.4. I can successfully run the code in the python shell and the terminal command-line, but I get <type 'exceptions.ImportError'>: No module named MySQLdb when I try to run it at "http://localhost/cgi-bin/test.cgi". It successfully runs if I comment out import MySQLdb.

#!/usr/bin/env python
import cgitb
cgitb.enable() 
import MySQLdb

print "Content-Type: text/html"
print
print "<html><head><title>Books</title></head>"
print "<body>"
print "<h1>Books</h1>"
print "<ul>"

connection = MySQLdb.connect(user='me', passwd='letmein', db='my_db')
cursor = connection.cursor()
cursor.execute("SELECT name FROM books ORDER BY pub_date DESC LIMIT 10")

for row in cursor.fetchall():
    print "<li>%s</li>" % row[0]

print "</ul>"
print "</body></html>"

connection.close()

[edit] Based on the first answer:

If I modify test.cgi as specified and run it from the terminal command-line, the directory of MySQLdb is shown in sys.path. However, when I run it via the web server, I get the same error. If I comment out import MySQLdb in test.cgi with the new for-loop, the page fails to open.

How do I set Apache's PYTHONPATH? At the python shell, I tried:

import MySQLdb
import os
print os.path.dirname(MySQLdb.__file__)

Then, based on other posts, I tried to add the resultant path in the original test.cgi:

import sys
sys.path.append('/Library/Frameworks/Python.framework/Versions/6.0.0/lib/python2.6/site-packages/MySQL_python-1.2.3c1-py2.6-macosx-10.5-i386.egg/')

but this produced the same error.


[edit]

Unfortunately, neither solution worked. Adding the path to sys.path gave me the same error as before. Hard-coding the path to the python binary #!/Library/Frameworks/Python.framework/Versions/Current/bin/python produced a lengthy error, part of which is shown:

A problem occurred in a Python script. Here is the sequence of function calls leading up to the error, in the order they occurred.

 /Library/WebServer/CGI-Executables/test.cgi in ()
   15 #sys.path.append('/Library/Frameworks/Python.framework/Versions/6.0.0/lib/python2.6/site-packages/')
   16 
   17 import MySQLdb
   18 #import _mysql
   19 
MySQLdb undefined
 /Library/WebServer/CGI-Executables/build/bdist.macosx-10.5-i386/egg/MySQLdb/__init__.py in ()
 /Library/WebServer/CGI-Executables/build/bdist.macosx-10.5-i386/egg/_mysql.py in ()
 /Library/WebServer/CGI-Executables/build/bdist.macosx-10.5-i386/egg/_mysql.py in __bootstrap__()
 /Library/Frameworks/Python.framework/Versions/6.0.0/lib/python2.6/site-packages/pkg_resources.py in resource_filename(self=<pkg_resources.ResourceManager instance at 0x3c8a80>, package_or_requirement='_mysql', resource_name='_mysql.so')
  848         """Return a true filesystem path for specified resource"""
  849         return get_provider(package_or_requirement).get_resource_filename(
  850             self, resource_name
  851         )
  852 
self = <pkg_resources.ResourceManager instance at 0x3c8a80>, resource_name = '_mysql.so'

...

<class 'pkg_resources.ExtractionError'>: Can't extract file(s) to egg cache The following error occurred while trying to extract file(s) to the Python egg cache: [Errno 13] Permission denied: '/Library/WebServer/.python-eggs' The Python egg cache directory is currently set to: /Library/WebServer/.python-eggs Perhaps your account does not have write access to this directory? You can change the cache directory by setting the PYTHON_EGG_CACHE environment variable to point to an accessible directory. 
      args = ("Can't extract file(s) to egg cache\n\nThe followin...nt\nvariable to point to an accessible directory.\n",) 
      cache_path = '/Library/WebServer/.python-eggs' 
      manager = <pkg_resources.ResourceManager instance at 0x3c8a80> 
      message = "Can't extract file(s) to egg cache\n\nThe followin...nt\nvariable to point to an accessible directory.\n" 
      original_error = OSError(13, 'Permission denied')

This error seems to imply that it may have something to do with setting PYTHON_EGG_CACHE and/or permissions...


[edit] Solution:

To test which version of Python that Apache was using, I added the following code:

import sys
version = sys.version
path = sys.path

...

print "<h1>%s</h1>" % version                                                                  
print "<h1>%s</h1>" % path

which indicated that Apache was indeed using the manufacturer-installed Python 2.5.1, and not Python 2.6.4 with the associated MySQLdb module. Thus, adding the following code to the original test.cgi fixed the problem:

import os
os.environ['PYTHON_EGG_CACHE'] = '/tmp'
import sys
sys.path.append('/Library/Frameworks/Python.framework/Versions/6.0.0/lib/python2.6/site-packages/MySQL_python-1.2.3c1-py2.6-macosx-10.5-i386.egg')

There is possibly a systematic fix by altering the PYTHONPATH in APACHE's httpd.conf, but I haven't yet figured it out.

+1  A: 

Make sure the python binary that Apache is using has MySQLdb in its PYTHONPATH.

Confirm it by checking the location of MySQLdb in the working script:

import os
print os.path.dirname(MySQLdb.__file__)

And comparing that to the output of sys.path inside of test.cgi:

import sys
for p in sys.path: 
    print p + "<br/>"

If the directory of MySQLdb from the working scripting is not in sys.path on the broken script, there is your problem.

Edit:

Based on the update to the OP, it looks like the directory that you need to add to your PYTHONPATH is /Library/Frameworks/Python.framework/Versions/6.0.0/lib/python2.6/site-packages/. The other path you used:

/Library/Frameworks/Python.framework/Versions/6.0.0/lib/python2.6/site-packages/MySQL_python-1.2.3c1-py2.6-macosx-10.5-i386.egg/

... is the location of the .egg that was installed. I hate .egg installs for this reason because it can be confusing, especially to people who are relatively new to Python.

The other option is to hard-code the path to the Python binary in your test.cgi to the same one you have confirmed you are using from the command-line. In your script you have /usr/bin/env python, which is a good practice. However, when you're running into environment and path problems like you are, it might be a good idea to hard-code the python binary until you can get past this hurdle.

From the command-line perform a which python, to determine which python binary the CLI is referencing:

% which python
/opt/local/bin/python 

The path to my python binary is /opt/local/bin/python. So if that were yours, replace /usr/bin/env python with that in test.cgi:

#!/opt/local/bin/python
import cgitb
# ... and so on ...

After doing that, are you still receiving the ImportError? If so, you've narrowed down the problem. Adding /Library/Frameworks/Python.framework/Versions/6.0.0/lib/python2.6/site-packages/ to sys.path may solve your problem without having to hard-code the path to the python binary.

jathanism