Added support for importing Python modules from paths other than Java Classpath.

This commit is contained in:
Abhinav Sarkar 2009-10-31 15:32:06 +05:30
parent 6ef5078412
commit 906e5222f3
9 changed files with 103 additions and 22 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry excluding="src/example/java/|src/main/java/" including="Lib/" kind="src" path=""/>
<classpathentry kind="src" path="src/example/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="JYTHON_HOME/jython.jar" sourcepath="/JYTHON_HOME/src"/>

View File

@ -2,6 +2,9 @@
<?eclipse-pydev version="1.0"?>
<pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">jython 2.5</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/jywrapper/Lib</path>
</pydev_pathproperty>
</pydev_project>

View File

@ -8,6 +8,18 @@ import org.junit.Test;
public class DependentTest {
private static final String PYLIB_DIR_NAME = "Lib";
static {
try {
JyWrapper.addToPythonPath(
DependentTest.class.getClassLoader()
.getResource(PYLIB_DIR_NAME).toURI());
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
private final Employee Employee_ = JyWrapper.wrap(Employee.class, "person.Employee");
private final Dependent Dependent_ = JyWrapper.wrap(Dependent.class, "person.Dependent");

View File

@ -3,12 +3,25 @@ package net.abhinavsarkar.jywrapper.example;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import net.abhinavsarkar.jywrapper.JyWrapper;
import org.junit.Test;
public class EmployeeTest {
private static final String PYLIB_DIR_NAME = "Lib";
static {
try {
JyWrapper.addToPythonPath(
DependentTest.class.getClassLoader()
.getResource(PYLIB_DIR_NAME).toURI());
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
private final Employee Employee_ = JyWrapper.wrap(Employee.class, "person.Employee");
private final Dependent Dependent_ = JyWrapper.wrap(Dependent.class, "person.Dependent");

View File

@ -2,14 +2,17 @@ package net.abhinavsarkar.jywrapper;
import static net.abhinavsarkar.jywrapper.Messages._;
import java.net.URI;
import net.abhinavsarkar.jywrapper.annotation.Wraps;
import net.abhinavsarkar.jywrapper.exception.PythonImportNotFoundException;
import org.python.core.Py;
import org.python.core.PyClass;
import org.python.core.PyFunction;
import org.python.core.PyModule;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PySystemState;
import org.python.core.PyType;
/**
@ -18,7 +21,7 @@ import org.python.core.PyType;
* @param <T> The type of the java class to wrap the Python class/module with.
*/
public final class JyWrapper {
private JyWrapper() {
}
@ -27,20 +30,20 @@ public final class JyWrapper {
if (annotation == null) {
throw new PythonImportNotFoundException(_("JyWrapper.7", javaClass)); //$NON-NLS-1$
}
return wrap(javaClass, annotation.value());
}
/**
* @param pyImportName The full import name of the Python class/module
* to wrap.
* @return An instance of {@link UninitedPyObjectWrapper}, ready to be
* @return An instance of {@link UninitedPyObjectWrapper}, ready to be
* initialized.
* @throws IllegalStateException Thrown if the java Class to be used to
* wrap the Python module/class, has not been supplied by earlier
* wrap the Python module/class, has not been supplied by earlier
* calling {@link JyWrapper#with(Class)}.
* @throws IllegalArgumentException Thrown if the pyImportName parameter
* is null.
* is null.
*/
public static <T> T wrap(final Class<T> javaClass, final String pyImportName) {
if (javaClass == null) {
@ -49,24 +52,24 @@ public final class JyWrapper {
if (pyImportName == null) {
throw new IllegalArgumentException(_("JyWrapper.6", "pyImportName")); //$NON-NLS-1$ //$NON-NLS-2$
}
final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName);
if (!(pyImport instanceof PyType
|| pyImport instanceof PyModule
if (!(pyImport instanceof PyType
|| pyImport instanceof PyModule
|| pyImport instanceof PyClass)) {
throw new IllegalArgumentException(_("JyWrapper.5", pyImportName)); //$NON-NLS-1$
}
return Util.py2Java(pyImport, javaClass);
}
/**
* @param <T> The return type of the {@link PyCallable} instance.
* @param <T> The return type of the {@link PyCallable} instance.
* @param pyImportName The full import name of the Python function to wrap.
* @param returnType The class of the return type.
* @return An instance of {@link PyCallable} which wraps the
* Python function given in parameter.
* @throws IllegalArgumentException Thrown if the any of the parameters
* supplied are null or if the pyImportName parameter supplied does not
* @throws IllegalArgumentException Thrown if the any of the parameters
* supplied are null or if the pyImportName parameter supplied does not
* correspond to a Python function.
*/
public static <T> PyCallable<T> wrapPyFunction(
@ -77,16 +80,33 @@ public final class JyWrapper {
if (returnType == null) {
throw new IllegalArgumentException(_("JyWrapper.6", "returnType")); //$NON-NLS-1$ //$NON-NLS-2$
}
final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName);
if (!(pyImport instanceof PyFunction)) {
throw new IllegalArgumentException(_("JyWrapper.0", pyImportName)); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
final PyCallable<T> newInstance = PyObjectProxy.newInstance(
pyImport, PyCallable.class);
return newInstance;
}
public static void addToPythonPath(final URI path) {
final PySystemState pySystemState = Py.getSystemState();
final PyString resolvedPath = Util.resolvePath(path);
if (resolvedPath != null && !pySystemState.path.contains(resolvedPath)) {
pySystemState.path.append(resolvedPath);
}
}
public static void removeFromPythonPath(final URI path) {
final PySystemState pySystemState = Py.getSystemState();
final PyString resolvedPath = Util.resolvePath(path);
if (resolvedPath != null && pySystemState.path.contains(resolvedPath)) {
pySystemState.path.remove(resolvedPath);
}
}
}

View File

@ -9,7 +9,6 @@ import net.abhinavsarkar.jywrapper.exception.PythonImportNotFoundException;
import org.python.core.Py;
import org.python.core.PyException;
import org.python.core.PyObject;
import org.python.core.PySystemState;
/**
* @author AbhinavSarkar
@ -17,8 +16,8 @@ import org.python.core.PySystemState;
*/
public final class PyImportLoader {
private static final PyObject importer = new PySystemState().getBuiltins()
.__getitem__(Py.newString("__import__")); //$NON-NLS-1$
private static final PyObject importer =
Py.getSystemState().getBuiltins().__getitem__(Py.newString("__import__"));
private static final ConcurrentHashMap<String, PyObject> loadedPyImports =
new ConcurrentHashMap<String, PyObject>();
@ -35,7 +34,7 @@ public final class PyImportLoader {
throws PythonImportNotFoundException {
if (!loadedPyImports.containsKey(fullImportName)) {
final int i = fullImportName.lastIndexOf('.');
final String errorMsg = _("PyImportLoader.1", fullImportName); //$NON-NLS-1$
final String errorMsg = _("PyImportLoader.1", fullImportName, Py.getSystemState().path); //$NON-NLS-1$
PyObject pyImport;
if (i == -1) {
final String pyModuleName = fullImportName;
@ -59,4 +58,5 @@ public final class PyImportLoader {
}
return loadedPyImports.get(fullImportName);
}
}

View File

@ -2,6 +2,10 @@ package net.abhinavsarkar.jywrapper;
import static net.abhinavsarkar.jywrapper.Messages._;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import org.python.core.Py;
import org.python.core.PyClass;
import org.python.core.PyFunction;
@ -83,4 +87,32 @@ final class Util {
return word.replaceAll("([A-Z])", "_$1").toLowerCase(); //$NON-NLS-1$ //$NON-NLS-2$
}
static PyString resolvePath(final URI pythonPath) {
PyString resolvedPath = null;
if (pythonPath.getScheme().equals("jar")) {
final String schemeSpecificPart = pythonPath.getSchemeSpecificPart();
final int lastIndexOf = schemeSpecificPart.lastIndexOf("!");
final String jarPath = schemeSpecificPart.substring(5, lastIndexOf);
final File file = new File(jarPath);
if (file.exists()) {
try {
resolvedPath = Py.newString(file.getCanonicalPath()
+ schemeSpecificPart.substring(lastIndexOf + 1));
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
} else if (pythonPath.getScheme().equals("file")) {
final File file = new File(pythonPath);
if (file.exists()) {
try {
resolvedPath = Py.newString(file.getCanonicalPath());
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
}
return resolvedPath;
}
}

View File

@ -14,4 +14,4 @@ JyWrapper.12=Trying to get instance attribute "{0}" from a Python Type
JyWrapper.13=Can''t set attribute: {0}
JyWrapper.14=Trying to set instance attribute "{0}" in a python class
JyWrapper.15=No {0} named "{1}" in the backing Python Type {2}
PyImportLoader.1=Python Import "{0}" not found in pythonpath
PyImportLoader.1=Python Import "{0}" not found in pythonpath {1}