Chapter 5. Modules and Packages

Modules and Packages

In Jython, one must manage Jython modules and packages, as well as Java packages and classes. Jython imports and uses all such items, but imports from where? Java uses the classpath to locate Java packages and classes while Python has the sys.path to locate and load its modules. Jython’s appeal is that it uses both. This becomes an interesting quagmire when implementing both such mechanisms, but what appears to be hairy behind the scenes, merely creates choices for the Jython user.

The study of these choices begins with the import statement, followed by a quick comparison of Java and Python conventions. The middle section of this chapter is in two parts: Python packages and modules, and Java packages and classes. Working interactively or maybe even working with dynamically generated code means modules can change after being imported. Jython’s “reload” facility assists in these situations and is discussed at the end of this chapter.

The import Statement

The import statement appears in four permutations. If the variables X,Y, and Z replace module and package names, these four permutations look like this:

import X 
import X as Y 
from X import Y 
from X import Y as Z 

import X

This is the first of the basic forms of the import statement. This is similar to Java’s import statement in appearance, but it binds the leftmost name. This is opposite of Java’s import which binds the rightmost name in the dotted package. class hierarchy. An example Java import could be:

import java.awt.TextComponent; 

This Java import statement allows you to directly use the name TextComponent, or the rightmost name, without any package names qualifying it. In Jython, however, a similar import binds the name java within the namespace in which the import occurred so that all following references to TextComponent must be qualified with java.awt. Inspecting the namespace with the dir() function shows how the name binding works in Jython:

>>> import java.awt.TextComponent 
>>> dir() 
['__doc__', '__name__', 'java'] 

If a module named b existed within package A, its import statement could be as follows:

import A.b 

The name bound, however, is the name A. The use of module b would require the package name A to qualify b. This means function c within module b is referenced as follows:

import A.b 
A.b.c() # call function c 

The module sys is a Jython module that is not part of a package, so it does not require any dot notation during import:

>>> import sys 

After the module sys is imported, you access contents with dot notation. This means accessing the variable path requires the following:

>>> import sys 
>>> sys.path 
['', '.', '/jython/Lib'] 

The sys.path variable is the Python version of Java’s classpath. This example also serves as an opportunity to check your sys.path variable. The sys.path does depend on your installation directory and is most likely different from the results above.

This form of the import statement also accepts a comma-separated list of modules or packages to import. The modules os and sys are Jython modules, while java is the root package of Java proper. To import these on one line, use a comma-separated list like the following:

>>> import os, sys, java 

import X as Y

Adding the word “as” to the simple import statement allows you to specify the name used to reference the imported item, and allows a direct binding to the rightmost element of the import. Specifying the name is an advantage in that you can avoid naming conflicts. Binding to the rightmost element eliminates the dot-notation required to qualify name.

Let’s look at importing the sys module again, only this time as bound to the name sys_module to avoid naming conflicts with a previously defined variable:

>>> sys = "A variable that creates a name conflict with module sys" 
>>> import sys as sys_module 
>>> dir() 
['__doc__', '__name__', 'sys_module', 'sys'] 
>>> sys 
'A variable that creates a name conflict with module sys' 
>>> s 
sys module 

Let’s revisit the A. b. c scenario stated earlier, where function c is within module b, which resides in package A. To bind module b to a new name, use the import X as Y syntax. This syntax binds the rightmost element of X to the name Y, so binding module b to a new name looks like this:

>>> import A.b as mod_b 
>>> dir(mod_b) 
['__doc__', '__file__', '__name__', 'c'] 
>>>mod_b.c() # call function c 

from X import Y

To extend control beyond packages and modules to actually control selective imports of module contents, you can use the from x import y syntax. This is not restricted to importing only module content—it works equally well with packages, modules, and classes. This syntax allows the import of sub-elements similar to the rightmost binding used with the as modifier, but in addition to sub-elements like sub-packages and sub-modules, it also allows importing selective contents of modules themselves.

Revisiting the A. b. c scenario yet again, you can bind module b by using the following:

from A import b 
b.c() # call function c 

To selectively import variables, functions, or classes from within a module using the from X import Y syntax, add the module name to X and include the desired module contents to Y. This means importing function c from module b, which resides in package A, uses the following:

from A.b import c 
c() # call function c 

As with the simple import statement, a comma-separated list is allowed. You can import multiple sub-elements with the following:

from A.b import c, d, e, f, etc 

Importing module-internal names such as the path variable within the sys module looks like this:

>>> from sys import path 

To import two names from the sys module, use the following:

>>> from sys import path, prefix 

The from X import Y syntax also allows an asterisk in the Y location. The asterisk designates the import of all available items (the definition of all is pliant and is described later). The use of the asterisk in imports is strongly discouraged in Jython—it has historically created numerous problems (such as when using import * with Java packages), so it is best to assume this option doesn’t really exist.

from X import Y as Z

The syntax of the last form of import is as follows:

from X import Y as Z 

Where X is a fully qualified package or module, Y is a package, module, or module-global name, and Z is an arbitrary, user-specified name that Y is bound to. Importing function c as myFunc from module b in package A, looks like this:

from A.b import c as myFunc 

A Comparison of Jython and Java

Java has packages, which can contain other packages or classes. Java packages are associated with directories containing files whereas classes are the results of compiling such files. Jython has packages, which can contain other packages or modules, but not classes. Class definitions occur only within Python modules. Both languages, however, use the same dot notation to traverse their hierarchy. In Java, if you wish to import class B from package A you would use an import statement that looks like this:

import A.B; 

This package.class hierarchy translates as a package.module hierarchy for Jython modules. A similar import statement in Jython would look like this:

import A.B 

This import statement results in the import of package A, followed by the import of module, or package B. This is an important distinction between Jython and Java. Jython imports each parent package as part of the import process. Additionally, Jython packages are functionally similar to modules after being imported.

Python’s package.module Hierarchy

This section reviews the Python convention for making, locating and loading Python packages and modules. This entails a study of the sys.path variable as well as descriptions of modules and packages. The Python language is rich with special variables. These are the variables beginning and ending with two underscores. Packages and modules contain special variables and, therefore, these variables are also described in this section.

The sys.path Variable

Locating Python modules depends on the sys.path variable. The directories within the sys.path list tell Jython where to search for modules. Trying to import a * . py file that does not reside anywhere in the sys.path raises an ImportError exception. Within this sys.path list is Jython’s Lib directory. This is where Jython’s installed module library resides. To inspect the sys.path variable for your Jython installation, use the following:

>>> import sys 
>>> print sys.path 
['', 'C:\WINDOWS\Desktop\.', 'C:\jython 2.1\Lib', 'C:\jython 2.1'] 

To add a path to the sys.path list, import the sys module and append the required path. To load modules located in the directory /usr/local/jython_work (on *nix), you must add this directory to the sys.path like:

>>> import sys 
>>> sys.path.append("/usr/local/jython_work") 

For the Windows directory C:jython_work, use this code:

>>> import sys 
>>> sys.path.append("c:\jython_work") # notice the double-backslash 
['', 'C:\WINDOWS\Desktop\.', 'C:\jython 2.1a1\Lib', 'C:\jython 
2.1a1', 'c:\jython 2.1a1\Lib\site-python', 'c:\jython_work'] 

Again note that sys.path is installation specific, so the contents of your sys.path may appear different than those in the book.

The backslash designates special characters like tab ( ) and newline ( ), as well as literal characters such as quotations (""") or a literal backslash (\). It is safest to use the double-backslash in windows paths to ensure the backslash is interpreted as a literal backslash rather than the start of a special character. However, in most cases the front slash, /, can be used as a directory separator on Windows within Jython code.

There are other ways to add to the sys.path variable. Jython has a file named registry that is located in Jython’s installation directory. The registry file contains a number of variables, including python.path and python.prepath, which both affect the contents of Jython’s sys.path list. To add the path /usr/local/jython_work to the sys.path without having to explicitly append this path in each module that uses it, just add it to the python.path or python.prepath variable. The difference between these two variables is that python.path appends the path at the end of sys.path, whereas python.prepath pre-pends the designated path before the rest of items in sys.path. The respective *nix and Windows registry entries look like this:

# for windows, use the double-backslash, and the semi-colon 
# path separator. 
python.path = c:\first_directory;d:\another_directory 

# For *nix, use the forward-slash, and the colon path separator 
python.path = /first/directory/to/add:/usr/local/secondDir/ 

Jython and Python also use a file called site.py to help with system paths. The site.py file is a module in Jython’s lib directory that is automatically loaded at Jython’s startup. One important feature of the site.py module is that it automatically looks for and imports the file sitecustomize.py. The sitecustomize.py module is not installed as part of Jython; it is a file that you author and is usually placed in Jython’s Lib directory. The automatic execution of sitecustomize.py at startup makes it useful for site-specific information such as extra library paths. Suppose you have Jython installed in the directory /usr/local/jython-2.1 on a Solaris machine, and you wish to organize user-defined modules in the directory /usr/local/jython-2.1/Lib/site-python. To add this extra directory to sys.path, you can create a sitecustomize.py file in the directory /usr/local/jython-2.1/Lib that includes the following code:

# file sitecustomize.py 
import sys 
sys.path.append(sys.prefix + "/Lib/site-python") 

The sys.prefix variable is a string representing the path to Jython’s installation directory. Actually, it’s the value of the python.home variable, which can be any arbitrary path and is discussed later, but for now it is most practically thought of as the path in which Jython is installed. Jython’s Lib directory is determined as sys.prefix + Lib. When import problems occur, it is often most instructive to print sys.prefix and sys.path to confirm their accuracy.

What Is a Module?

A module is a file that contains Jython code and has a .py extension. There are no other special syntax or directives required to make it a module. During any previous examples where you placed Jython code within a *.py file, you were actually creating a module. Modules also appear as .class files, or files containing Java bytecode, with names like modulename$py.class. These are the compiled version of modules that have been imported. Subsequent imports use these byte-compile files as an optimization if their associated .py has not changed. Modules are byte-compiled when they are imported or by using Jython’s compiler, jythonc, or by running the module compileall.py (found in Jython’s Lib directory).

Numerous modules are included with the Jython distribution, and they are located in Jython’s Lib directory. These modules are mostly Python modules originally included in the CPython distribution and a part of CPython’s documentation set. Not all of CPython’s modules work with Jython, however. Some of the modules in CPython rely on code written in C. Jython currently cannot make use of modules written in languages other than Java or Python, so these C-dependant modules will not work. Documentation for most of Jython’s modules is in the Python Library Reference currently located at http://www.python.org/doc/current/lib/lib.html, and available in the book Python Essential Reference by David Beazley (New Riders Publishing). Those modules that are unique or missing in Jython have descriptions in Appendix C of that book.

User-defined modules are those *.py files that you or others have written, and are not included in the distribution. These files could be placed in Jython’s Lib directory in order for them to be found and loaded; however, that usually makes it frustrating to upgrade Jython versions. A separate location for these files is more desirable, and a separate location requires an additional item in sys.path. For the remainder of this chapter, it is assumed that newly written modules are placed in a location in the sys.path list. The easiest would be the current working directory, which is automatically in the sys.path. Otherwise, in the directory sys.prefix + /Lib/site-python, which would require that you have added this to the sys.path list as described earlier.

Special Module Variables

Modules have special variables or “magic” variables. Magic is a colloquial term often ascribed to variables in Jython, and Python, that have two leading and trailing underscores.The magic variables in a module are __doc__, __file__, __name__, and __all__.

The __doc__ variable in a module is similar to the __doc__ string of functions. If a module begins with a string literal, that string literal becomes the module’s __doc__ attribute. This is part of Jython’s self-documentation mechanism. Suppose you need to create a directory-syncing tool. You would likely start out by documenting your intentions in a module’s __doc__ attribute:

# file: dirsync.py 
"""This module provides tools to sync a slave directory to a master 
directory.""" 

After placing the dirsync.py file in somewhere in the sys.path, you can look at the results of this string in the interactive interpreter:

>>> import dirsync 
>>> print dirsync.__doc__ 
This module provides tools to sync a slave directory to a master 
directory. 

The __name__ attribute of a module is the module name. The exception to this is the __main__ module. When Jython starts with a module name supplied as a command-line argument, such as jython test.py, the module supplied on the command line is considered the __main__ module. This introduces an important and useful convention in Jython modules.

Listing 5.1 shows a more complete version of the dirsync.py file. It doesn’t actually sync files, but Listing 5.1 calculates the work required to do so. The final if statement in Listing 5.1 is the useful module convention. First, examine Listing 5.1, beginning with explaining a couple of functions used:

  • os.path.join: Adds multiple path elements into a legal path.

  • os.path.isfile: Returns 1 if a path points to a file, 0 otherwise.

  • os.path.isdir: Returns 1 if a path points to a directory, 0 otherwise.

  • os.listdir: Returns a list of the contents of a designated directory.

  • os.stat: Returns a ten-element list of file info.

  • stat.ST_MTIME: Is a number that designates which element of a stat list is the modification time.

Example 5.1. A Module for Syncing Directories

# file: dirsync.py 
"""This module provides tools to sync a slave directory to a master 
directory.""" 

from __future__ import nested_scopes 
import os 
from stat import ST_MTIME 

def __getRequiredUpdates(master, slave): 
    """getRequiredUpdates(master, slave) -> list of files that are old or 
        missing from the slave directory""" 

    needUpdate = [] # holds results 
    def walk(mpath): # recursive function that does the work 
        if os.path.isfile(mpath): 
            spath = mpath.replace(master, slave) 
            if (not os.path.exists(spath) or 
               (os.stat(mpath)[ST_MTIME] > os.stat(spath)[ST_MTIME)): 
                needUpdate.append(mpath.replace(master, "")) 
        if os.path.isdir(mpath): 
            for item in os.listdir(mpath): 
                walk(os.path.join(mpath, item)) 
    walk(master) 
    return needUpdate 

def __getExtraneousFiles(master, slave): 
    """getExtraneousFiles(master, slave) -> list of files in the slave 
        directory which do not exist in the master directory""" 

    extraneous = [] # holds results 
    def walk(spath): # recursive function that does the work 
        mpath = spath.replace(slave, master) 
        if not os.path.exists(mpath): 
            extraneous.append(spath) 
        if os.path.isdir(spath): 
            for item in os.listdir(spath): 
                walk(os.path.join(spath, item)) 
    walk(slave) 
    return extraneous 
def sync(master, slave): 
    updates = __getRequiredUpdates(master, slave) 
    extras = __getExtraneousFiles(master, slave) 
    for item in updates: 
        # copy those files needing updated 
        print os.path.join(master, item), "need copied to slave dir." 
    for item in extras: 
        # delete those files that are extras 
        print item, "should be deleted." 
if __name__ == '__main__': 
    from time import time 
    import sys 
    t1 = time() 
    sync(sys.argv[1], sys.argv[2]) 
    print "Directory sync completed in %f seconds." %% (time()-t1) 

The last if statement in Listing 5.1 tests if the name of the module is __main__. If this is true, it means the module was run with the command jython dirsync.py and is expected to act lake the main script, or similar to what you would expect from methods with the public static void main(String args) signature in a Java program. However, if another script imports this module, __name__ is not __main__ and the associated code is not executed. Many Jython modules make use of this convention, either so that they can function as stand-alone scripts as well as modules, or so that they self-test when they are run as a stand-alone script. In the case of Listing 5.1, the script dirsync.py can be run as a standalone script to determine the work required to sync a master and slave directory that are supplied in the command-line with a command like the following:

jython dirsync.py "c:path	omasterdir" "c:path	oslavedir" 

The variable sys.argv is a list that contains all the command-line parameters used when starting Jython. The actual script running as the main script is always sys.argv[0], so in Listing 5.1, sys.argv[0] is dirsync.py, and sys.argv[1] and sys.argv[2] would be the master and slave directories, respectively. The shell command to run dirsync.py and the respective sys.argv assignments would be as follows:

jython dirsync.py c:mywork c:mybackups 
        argv[0]    argv[1]    argv[2] 

Listing 5.1 introduces another special naming convention: functions that begin with two underscores. Identifiers that begin with two underscores are special in that they are not imported when the from X import * syntax is used. Actually, in Jython 2.1, this should apply to those identifiers starting with one or two underscores, but those with one underscore didn’t work properly at the time this was written, so Listing 5.1 uses two underscores. To test this with the dirsync.py module in Listing 5.1, first ensure that it is in the sys.path, then type:

>>> from dirsync import * 
>>> dir() # look to see which names where imported 
['ST_MTIME', '__doc__', '__name__', 'nested_scopes', 'os', 'sync'] 

The results of the dir() function confirm that no names that begin with two underscores were imported.

The magic variable __all__ further controls the list of names imported from a module.The variable __all__ is a list that contains which names a module exports. If Listing 5.1 had a line like the following, the only name appearing after a from dirsync import * statement would be the name sync.:

__all__ = ['sync'] 

What Are Packages?

A Python package is a hierarchy of modules contained in a directory tree. The concept is the same as Java packages, except the contents of Python packages are modules, not classes. An excellent example of the package system is Jython’s pawt package found in Jython’s Lib directory.

Figure 5.1 is the directory listing of a Jython installation on a Windows machine. Note that depending on your version of Jython and whether or not you created the site-python directory discussed earlier, your directory, contents could differ. The Lib directory within C:jython-2.1 is where modules and packages distributed with Jython are stored. Within this directory, you’ll find the directory called pawt. It is not just another directory however—it is a Jython package. What makes it a package? It contains a file that initializes it as a package. This file is __init__.py.

The pawt Package.

Figure 5.1. The pawt Package.

When a package is imported, its __init__.py file is executed. Because pawt is a package, you can import its contents with any of the following statements:

>>> import pawt.colors 

>>> import pawt.swing 

>>> from pawt import colors, swing 

>>> from pawt import * 

You can also import the package itself with this statement:

>>> import pawt 

The unique thing about Python packages is that an import statement actually initializes all parent packages. This means if you have a hierarchy such that package A contains package B, which contains module C, the actual import of module C runs A.__init__.py, then runs B.__init__.py, and then imports module C. Listing 5.2 shows the implementation of this scenario. Three files, A.__init__.py, B.__init__.py, and moduleC, each merely print a message to announce the point of their evaluation. Listing 5.2 continues this example in the interactive interpreter by importing moduleC. The messages printed to the screen confirms the initialization of parent packages.

Example 5.2. Package Initialization

# file sys.prefix/site-python/A/__init__.py 
"""Root package in a nested package demonstration""" 
print "Initializing package A" 

# file sys.prefix/site-python/A/B/__init__.py 
print "Initializing package B" 


# file sys.prefix/site-python/A/B/moduleC.py 
print "Executing module 'moduleC'" 
import moduleD 

# file sys.prefix/site-python/A/B/moduleD.py 
print "Executing module 'moduleD'" 

>>> # examine packages A, B, and moduleC interactively 
>>> import A.B.moduleC 
Initializing package A 
Initializing package B 
Executing module 'moduleC' 
Executing 'moduleD' 

Listing 5.2 also includes a moduleD.py file to demonstrate how a module can import package-sibling modules without the fully qualified name, meaning moduleC can import moduleD with just its name. Modules in different packages must be qualified, however.

Jython’s self documentation conventions extend to packages in that if a package’s __init__.py file begins with a string literal, the package’s __doc__ attribute is assigned that string as a value. Notice that the file sys.prefix/site-python/A/__init__.py in Listing 5.2 has a string literal. If we revisit this package, we can see how the __doc__ attribute is assigned in this package. Note that you have to restart the interpreter between Listing 5.2 and the following in order for the package initialization to work as shown:

>>> import A 
Initializing package A 
>>> A.__doc__ 
'Root package in a nested package demonstration' 

A package’s __init__.py file can also contain the magic variable __all__, which designates the names that package exports when the from package import * statement is used.

An imported package is similar to a module except that a package has one additional special variable: __path__. The __path__ variable is just as you might guess: the system path to the specified package. Examining the pawt package demonstrates the __path__ variable:

>>> import pawt 
>>> pawt.__path__ 
['C:\jython 2.1a1\Lib\pawt'] 

Java’s package.class Hierarchy

The loading of Java packages and classes uses the same syntax as importing Python modules, but there is some extra information required to fully understand Java loading. Java uses the classpath to locate and load packages and classes. Jython’s import mechanism does inspect the Java classpath. When running Jython, the classpath is taken from the classpath environment variable. To add the jar file zxJDBC.jar to the classpath that Jython uses, you can set the classpath environment variable before starting Jython with shell commands like these:

# for Windows users at a dos prompt, or within a *.bat file 
>set CLASSPATH=c:path	ozxJDBC.jar 
>jython 

# for *nix users at the bash prompt 
>export CLASSPATH=/path/to/zxJDBC.jar 
>jython 

On either platform, make sure that the paths in the classpath follow the platform-specific guidelines for paths: and ; for Windows, and / and : for *nix.

All four permutations of Jython’s import statement work with Java classes and packages and even class contents. Name binding rules remain the same for imports when importing Java items. This means that import java.util.Vector still binds the leftmost name, java, instead of the Java behavior of binding the rightmost name. This also means that the from X import Y syntax can import contents of X that are not classes or packages.

Listing 5.3 shows a number of import statements that import Java classes, and even class contents to demonstrate how the import behavior works with Java elements. Note that Listing 5.3 requires Java 1.2 (only tested with Sun JDK).

Example 5.3. Importing and Using Java Items

>>> import java.applet 
>>> # inspect name with dir() to show leftmost binding 
>>> dir() 
['__doc__', '__name__', 'java'] 
>>> 
>>> import java as j 
>>> dir() 
['__doc__', '__name__', 'j', 'java'] 
>>> 
>>> # 'from X import y' even works on class contents such as.... 
>>> from java.security.AlgorithmParameters import getInstance 
>>> from java.applet.Applet import newAudioClip as nac 
>>> dir() 
['__doc__c', '__name__', 'getInstance', 'j', 'java', 'nac'] 

You can see that not only does Jython’s import flexibility apply to Java classes and packages, but it also allows selective importing of class contents.

The classpath is not the only path used to locate and load Java classes and packages. They can also be located and loaded from the sys.path. In Jython, the sys.path acts as an extension of Java’s classpath. This creates some problems in determining which items are Java and which are Python, and in that packages spread across the classpath and sys.path do not see themselves as package siblings.

Listing 5.4 shows a minimal Java class. The focus of this example is to show how a Java class loads from the Python sys.path. The first half of Listing 5.4 is the Java class mjc (for minimal Java class). To try the example in Listing 5.4, save the Java mjc class to the file mjc.java and compile it with javac. Then place the compiled mjc.class file in the user-defined module directory this chapter has been using (sys.prefix/Lib/site-python). The interactive interpreter section of Listing 5.4 prints Java’s classpath to confirm mjc.class is not within it, then prints sys.path followed by importing mjc. In this case, the Java class is located and loaded from the sys. path.

Example 5.4. Loading Java Classes from sys.path

// file mjc.java 
public class mjc {
    String message = "This is all I do- return a string."; 
    public mjc() {} 

    public String doSomething() {
        return message; 
    } 
} 

>>> from java.lang import System 
>>> System.getProperty("java.class.path") 
'C:\jython 2.1a1\jython.jar;c:\windows\desktop' 
>>> import sys 
>>> print sys.path 
['', 'C:\WINDOWS\Desktop\.', 'C:\jython 2.1a1\Lib', 'C:\jython 2.1a1', 
'c:\jython 2.1a1\Lib\site-python'] 
>>> import mjc 
>>> m = mjc() 
>>> m.doSomething() 
'This is all I do- return a string.' 

Things are not always that simple, though. *.jar and *.zip files do not load from the sys.path at the time of this writing. There are also cases where Java packages are not recognized properly. One instance of misrecognition is when a jar or zip file’s extension is not all lowercased. This will be corrected at some point, but for Jython versions 2.1a1 and earlier, those files should be renamed with lowercased extensions. The loading of *.jar and *.zip files from the sys.path will eventually be added as well.

Listing 5.5 makes use of the Java loading facility to play a network audio resource. Note that some firewall setups create problems for Listing 5.4.

Example 5.5. Using Java Classes Within Jython to Play a Sound

>>> from java import net 
>>> from java.applet.Applet import newAudioClip 
>>> 
>>> url = net.URL("http://www.digisprings.com/test.wav") 
>>> audio = newAudioClip(url) 
>>> audio.play() 

Java manages dynamic loading with the Class.forName method. This is still available in Jython, and the only catch is that most people forget that the content of java.lang is not imported by default in Jython. With the explicit import of Class, or even the static method forName, this dynamic loading functions the same. Here is an example that imports the java.util.Hashtable class:

>>> from java.lang.Class import forName 
>>> forName("java.util.Hashtable") 
<jclass java.util.Hashtable at 2105495> 
>>> 
>>> # OR 
>>> from java.lang import Class 
>>> Class.forName("java.util.Hashtable") 
<jclass java.utilc.Hashtable at 2105495> 

Reloading

If you imported a module, but that module has since changed, you can reload that module with the built-in reload function. This is most useful when working within the interactive interpreter and editing a module at the same time. The syntax for the reload function is as follows:

reload(modulename) 

Whereas the import statement allows the import of module-global entities with the from x import Y syntax, the reload function does not. Reload only works for modules and packages. Here are a few example reload lines to demonstrate:

>>> from pawt import colors 
>>> reload(colors) 
<module pawt.colors at 860800> 
>>> import dumbdbm 
>>> reload(dumbdbm) 
<module dumbdbm at 5654181> 

Reloading Java packages and classes is trickier. Samuele Pedroni is a programmer and Jython project member who has contributed an experimental package to the Jython project that allows the reloading of Java entities. Samuele’s jreload module is what enables Java reloading. Java packages and classes imported as part of a jreload load set are the only ones that are re-loadable. This is very different than other imports because all package and class access is via the load set instance.

To make a load set you must use the jreload.makeLoadSet function. This function requires two arguments: The first is a name, which is any arbitrary string you want assigned to the load set. The second argument must be a PyList, which contains a list of strings representing classpath entries of items you wish to include in the load set. Suppose you have the jar file for the javax.servlet packages located in C:web omcatlibservlet.jar (this jar does not come with the JDK; it must be downloaded separately—usually as part of the Tomcat web server located at http://jakarta.apache.org). Creating a load set for the packages contained within the servlet.jar file looks like this:

>>> import jreload 
>>> ls = jreload.makeLoadSet("servlet classes", 
["c:\web\tomcat\lib\servlet.jar"]) 
>>> dir(ls.javax) 
["__name__", "servlet"] 

If you want to reload packages and classes from this load set, possibly because you have re-created the servlet.jar file with newer files, use the following:

>>> ls = reload(ls) 

While this example is specific to the packages within the servlet.jar file, jreload works with any class or package not already on the classpath or sys.path. To try another package or class with jreload, you must change the second argument to the makeLoadSet method to include the location of the package you intend to import. Changing the first argument to makeLoadSet is also a good idea, but it is just an arbitrary name for the set and doesn’t affect its functionality. The classpath -like list in the second argument of makeLoadSet is the essential part of the jreload mechanism.

There are some caveats to jreload. First, the list of classpath -like entries supplied to the makeLoadSet function (the second argument) should not be entries already found in sys.path or the classpath. Second, Java inner classes produce unexpected results.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset