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

master
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"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="src" path="src/main/java"/> <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="src" path="src/example/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="JYTHON_HOME/jython.jar" sourcepath="/JYTHON_HOME/src"/> <classpathentry kind="var" path="JYTHON_HOME/jython.jar" sourcepath="/JYTHON_HOME/src"/>

View File

@ -2,6 +2,9 @@
<?eclipse-pydev version="1.0"?> <?eclipse-pydev version="1.0"?>
<pydev_project> <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_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> </pydev_project>

View File

@ -8,6 +8,18 @@ import org.junit.Test;
public class DependentTest { 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 Employee Employee_ = JyWrapper.wrap(Employee.class, "person.Employee");
private final Dependent Dependent_ = JyWrapper.wrap(Dependent.class, "person.Dependent"); 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.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import net.abhinavsarkar.jywrapper.JyWrapper; import net.abhinavsarkar.jywrapper.JyWrapper;
import org.junit.Test; import org.junit.Test;
public class EmployeeTest { 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 Employee Employee_ = JyWrapper.wrap(Employee.class, "person.Employee");
private final Dependent Dependent_ = JyWrapper.wrap(Dependent.class, "person.Dependent"); 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 static net.abhinavsarkar.jywrapper.Messages._;
import java.net.URI;
import net.abhinavsarkar.jywrapper.annotation.Wraps; import net.abhinavsarkar.jywrapper.annotation.Wraps;
import net.abhinavsarkar.jywrapper.exception.PythonImportNotFoundException; import net.abhinavsarkar.jywrapper.exception.PythonImportNotFoundException;
import org.python.core.Py;
import org.python.core.PyClass; import org.python.core.PyClass;
import org.python.core.PyFunction; import org.python.core.PyFunction;
import org.python.core.PyModule; import org.python.core.PyModule;
import org.python.core.PyObject; import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PySystemState;
import org.python.core.PyType; 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. * @param <T> The type of the java class to wrap the Python class/module with.
*/ */
public final class JyWrapper { public final class JyWrapper {
private JyWrapper() { private JyWrapper() {
} }
@ -27,20 +30,20 @@ public final class JyWrapper {
if (annotation == null) { if (annotation == null) {
throw new PythonImportNotFoundException(_("JyWrapper.7", javaClass)); //$NON-NLS-1$ throw new PythonImportNotFoundException(_("JyWrapper.7", javaClass)); //$NON-NLS-1$
} }
return wrap(javaClass, annotation.value()); return wrap(javaClass, annotation.value());
} }
/** /**
* @param pyImportName The full import name of the Python class/module * @param pyImportName The full import name of the Python class/module
* to wrap. * to wrap.
* @return An instance of {@link UninitedPyObjectWrapper}, ready to be * @return An instance of {@link UninitedPyObjectWrapper}, ready to be
* initialized. * initialized.
* @throws IllegalStateException Thrown if the java Class to be used to * @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)}. * calling {@link JyWrapper#with(Class)}.
* @throws IllegalArgumentException Thrown if the pyImportName parameter * @throws IllegalArgumentException Thrown if the pyImportName parameter
* is null. * is null.
*/ */
public static <T> T wrap(final Class<T> javaClass, final String pyImportName) { public static <T> T wrap(final Class<T> javaClass, final String pyImportName) {
if (javaClass == null) { if (javaClass == null) {
@ -49,24 +52,24 @@ public final class JyWrapper {
if (pyImportName == null) { if (pyImportName == null) {
throw new IllegalArgumentException(_("JyWrapper.6", "pyImportName")); //$NON-NLS-1$ //$NON-NLS-2$ throw new IllegalArgumentException(_("JyWrapper.6", "pyImportName")); //$NON-NLS-1$ //$NON-NLS-2$
} }
final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName); final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName);
if (!(pyImport instanceof PyType if (!(pyImport instanceof PyType
|| pyImport instanceof PyModule || pyImport instanceof PyModule
|| pyImport instanceof PyClass)) { || pyImport instanceof PyClass)) {
throw new IllegalArgumentException(_("JyWrapper.5", pyImportName)); //$NON-NLS-1$ throw new IllegalArgumentException(_("JyWrapper.5", pyImportName)); //$NON-NLS-1$
} }
return Util.py2Java(pyImport, javaClass); 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 pyImportName The full import name of the Python function to wrap.
* @param returnType The class of the return type. * @param returnType The class of the return type.
* @return An instance of {@link PyCallable} which wraps the * @return An instance of {@link PyCallable} which wraps the
* Python function given in parameter. * Python function given in parameter.
* @throws IllegalArgumentException Thrown if the any of the parameters * @throws IllegalArgumentException Thrown if the any of the parameters
* supplied are null or if the pyImportName parameter supplied does not * supplied are null or if the pyImportName parameter supplied does not
* correspond to a Python function. * correspond to a Python function.
*/ */
public static <T> PyCallable<T> wrapPyFunction( public static <T> PyCallable<T> wrapPyFunction(
@ -77,16 +80,33 @@ public final class JyWrapper {
if (returnType == null) { if (returnType == null) {
throw new IllegalArgumentException(_("JyWrapper.6", "returnType")); //$NON-NLS-1$ //$NON-NLS-2$ throw new IllegalArgumentException(_("JyWrapper.6", "returnType")); //$NON-NLS-1$ //$NON-NLS-2$
} }
final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName); final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName);
if (!(pyImport instanceof PyFunction)) { if (!(pyImport instanceof PyFunction)) {
throw new IllegalArgumentException(_("JyWrapper.0", pyImportName)); //$NON-NLS-1$ throw new IllegalArgumentException(_("JyWrapper.0", pyImportName)); //$NON-NLS-1$
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final PyCallable<T> newInstance = PyObjectProxy.newInstance( final PyCallable<T> newInstance = PyObjectProxy.newInstance(
pyImport, PyCallable.class); pyImport, PyCallable.class);
return newInstance; 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.Py;
import org.python.core.PyException; import org.python.core.PyException;
import org.python.core.PyObject; import org.python.core.PyObject;
import org.python.core.PySystemState;
/** /**
* @author AbhinavSarkar * @author AbhinavSarkar
@ -17,8 +16,8 @@ import org.python.core.PySystemState;
*/ */
public final class PyImportLoader { public final class PyImportLoader {
private static final PyObject importer = new PySystemState().getBuiltins() private static final PyObject importer =
.__getitem__(Py.newString("__import__")); //$NON-NLS-1$ Py.getSystemState().getBuiltins().__getitem__(Py.newString("__import__"));
private static final ConcurrentHashMap<String, PyObject> loadedPyImports = private static final ConcurrentHashMap<String, PyObject> loadedPyImports =
new ConcurrentHashMap<String, PyObject>(); new ConcurrentHashMap<String, PyObject>();
@ -35,7 +34,7 @@ public final class PyImportLoader {
throws PythonImportNotFoundException { throws PythonImportNotFoundException {
if (!loadedPyImports.containsKey(fullImportName)) { if (!loadedPyImports.containsKey(fullImportName)) {
final int i = fullImportName.lastIndexOf('.'); 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; PyObject pyImport;
if (i == -1) { if (i == -1) {
final String pyModuleName = fullImportName; final String pyModuleName = fullImportName;
@ -59,4 +58,5 @@ public final class PyImportLoader {
} }
return loadedPyImports.get(fullImportName); return loadedPyImports.get(fullImportName);
} }
} }

View File

@ -2,6 +2,10 @@ package net.abhinavsarkar.jywrapper;
import static net.abhinavsarkar.jywrapper.Messages._; 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.Py;
import org.python.core.PyClass; import org.python.core.PyClass;
import org.python.core.PyFunction; 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$ 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.13=Can''t set attribute: {0}
JyWrapper.14=Trying to set instance attribute "{0}" in a python class JyWrapper.14=Trying to set instance attribute "{0}" in a python class
JyWrapper.15=No {0} named "{1}" in the backing Python Type {2} 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}