Friday, March 30, 2007

Standalone Jython — ImportError: no module named awt

I've spent probably about a day figuring out what's going on here, Google being no help whatsoever, so figure I might as well publish.

Scenario -- Jython 2.2b1, installed in standalone mode i.e. all of /Lib inside the jar, and cachedir being skipped.

Now this sort of code works with Jython launched from the jar in the standard install:

import java.awt
f = java.awt.Frame()
f.title = "Hello AWT"
f.visible = True

but with Jython.jar from the standalone the code gives

C:\jython2.2b1-standalone>java -jar jython.jar
Jython 2.2b1 on java1.6.0 (JIT: null)
Type "copyright", "credits" or "license" for more information.
>>> import java.awt
Traceback (innermost last):
  File "", line 1, in ?
ImportError: no module named awt
>>> ^Z

Hunting down the error message, it is raised in org.python.core.imp, ultimately from JavaImportHelper.tryAddPackage() failing. Meanwhile, from the other direction, doing

import sys
dir(sys)

gave me that sys has a packageManager attribute. And that has a makeJavaPackage method. This lives in org.python.core.PackageManager

    /**
     * Creates package/updates statically known classes info. Uses
     * {@link PyJavaPackage#addPackage(java.lang.String, java.lang.String) },
     * {@link PyJavaPackage#addPlaceholders}.
     * 
     * @param name package name
     * @param classes comma-separated string
     * @param jarfile involved jarfile; can be null
     * @return created/updated package
     */
    public PyJavaPackage makeJavaPackage(String name, String classes,
            String jarfile) {
...

So, that seemed worth giving a try. Like

import sys
sys.packageManager.makeJavaPackage("javax.swing", "JWindow", None)
import javax.swing
f = javax.swing.JFrame()
f.title = "Jython/Swing"
f.visible = True

And that, at last, worked.

Now, you might think it would be elegant to do something like

try:
  import javax.swing
except ImportError:
  import sys
  sys.packageManager.makeJavaPackage("javax.swing", "JWindow", None)
  import javax.swing

to allow for the cases where it would work anyway; but this doesn't work -- the branch is taken, but the conditional packaging doesn't seem to stick. However, it doesn't seem to matter if you always explicitly add the package as part of the initialisation, even when not strictly needed. So stick with the simple case. It's more Pythonic that way, after all.

[Now playing - Planet Rock]

Post a Comment