Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Johnson committed Jun 6, 2012
2 parents 87bf00e + 53d5085 commit d3d3e48
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 102 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ build
dist
*.pyc
MANIFEST
.DS_Store
.idea
17 changes: 7 additions & 10 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
2012-04-09 Mike Johnson <[email protected]>
* setup.py: distutils build, pypi integration
* tests: unittesting implemented in python
* jep: added `jep` command line script for launching console.py
* exception mapping (dynamic creation of python exceptions) no longer supported
* pyjobject.c: implement richcompare using Java .equals
* pyjobject.c: missing attribute raises AttributeError
* pyjobject.c: don't change optimization flag by default
* pyjarray.c: fix for iterator, so list() works on jarrays
2012-05-05 3.1.0 - Mike Johnson <[email protected]>
* lazy load classes imported via import hook

2007-03-19 Mike Johnson <[email protected]>
2012-03-06 3.0.0 - Mike Johnson <[email protected]>
* project uses distutils now, is pip installable
* added a proper import hook

2007-03-19 Mike Johnson <[email protected]>
* pyembed.c: patch from Jon Wright to convert packed strings to float array in java.
* pyembed.c: return jarray object in invoke and getValue
* pyembed.c: throw exception if invocation object not found
Expand Down
58 changes: 21 additions & 37 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ response.

Jep is licensed zlib/libpng license to avoid linking issues.

Dependencies
------------
* Python version >= 2.6
* JNI >= 1.4

Installation
------------

Simply run ``pip install jep``.

Dependencies
------------
* Python version >= 2.6
* JNI >= 1.4

*Building on Mac OS X*

OS X requires the `Java Developer Package and Xcode
Expand All @@ -53,33 +53,30 @@ on Windows has not worked in recent years because the compilers are
not widely available. If an OpenJDK build used MinGW, that'd be
much more likely to work.

Running scripts
---------------

The ``setup.py`` script will provide a ``jep`` shortcut to make launching Java and Python easier.

::

$ jep
>>> from java.lang import System
>>> System.out.println('hello, world')
hello, world
>>>

Running on \*nix
-----------------
Due to some (common) difficulties with Java and C projects
that dlopen libraries, you may need to set LD_PRELOAD environment
variable. That's in addition to setting LD_LIBRARY_PATH if you've
installed libjep into a directory not cached by ld.so.

For example, my Tomcat startup.sh script starts with this:

::

#!/bin/sh
# force system to load python
export LD_PRELOAD=/usr/lib/libpython2.7.so
# this is where my libjep.so is.
export LD_LIBRARY_PATH=/usr/local/lib

The libpython used here is whatever you've compiled jep against. If
you don't know, try this command:
See the contents of the installed ``jep`` script for an example how to do this.
The script should have the correct values for your interpreter and virtualenv
(if present).

::

$ ldd /usr/local/lib/libjep.so | grep python
/usr/lib/libpython2.7.so (0x00007f74adfbd000)

That's the libpython you want to set in LD_PRELOAD.

Running the tests
-----------------
Expand All @@ -90,19 +87,6 @@ The tests are run from setup.py:

$ python setup.py test

Running scripts
---------------

There is a ``jep`` shell script to make launching Java and Python a little easier.

::

$ jep
>>> from java.lang import System
>>> System.out.println('hello, world')
hello, world
>>>

Support
-------

Expand Down
2 changes: 1 addition & 1 deletion commands/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ def finalize_options(self):
pass

def run(self):
spawn(['java', '-cp', 'build/java/', 'jep.Test'])
spawn(['java', '-cp', 'build/java/:tests/lib/sqlitejdbc-v056.jar', 'jep.Test'])
44 changes: 36 additions & 8 deletions jep/hook.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
from _jep import *
from _jep import findClass
import sys
import imp
from types import ModuleType


class module(ModuleType):
"""Lazy load classes not found at runtime.
Introspecting Java packages is difficult, there is not a good
way to get a list of all classes for a package. By providing
a __getattr__ implementation for modules, this class can
try to find classes manually.
Due to this Java limitation, some classes will not appear in dir()
but will import correctly.
"""

def __getattr__(self, name):
try:
return super(module, self).__getattribute__(name)
except AttributeError as ae:
try:
clazz = findClass('{0}.{1}'.format(self.__name__, name))
setattr(self, name, clazz)
return clazz
except Exception:
# should raise AttributeError, not JepException
raise ae


class JepImporter(object):
Expand All @@ -14,19 +39,22 @@ def find_module(self, fullname, path=None):

def load_module(self, fullname):
if fullname in sys.modules:
return fullname

mod = imp.new_module(fullname)
mod.__loader__ = self
return sys.modules[fullname]

mod = module(fullname)
mod.__dict__.update({
'__loader__': self,
'__path__': [],
'__file__': '<java>',
})
sys.modules[fullname] = mod
mod.__path__ = []
mod.__file__ = '<java>'

# list of classes in package
for name in self.classlist.get(fullname):
setattr(mod, name.split('.')[-1], findClass(name))
return mod


sys.meta_path = [importer for importer in sys.meta_path if isinstance(importer, JepImporter)]
sys.meta_path.append(JepImporter())

2 changes: 1 addition & 1 deletion jep/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__VERSION__ = '3.0.0'
__VERSION__ = '3.0.1'
VERSION = __VERSION__
27 changes: 14 additions & 13 deletions src/jep/pyembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ void pyembed_shutdown(void) {

intptr_t pyembed_thread_init(JNIEnv *env, jobject cl, jobject caller) {
JepThread *jepThread;
PyObject *tdict, *main_module, *globals;
PyObject *tdict, *mod_main, *globals;

if(cl == NULL) {
THROW_JEP(env, "Invalid Classloader.");
Expand All @@ -247,14 +247,14 @@ intptr_t pyembed_thread_init(JNIEnv *env, jobject cl, jobject caller) {
if(!cache_primitive_classes(env))
printf("WARNING: failed to get primitive class types.\n");

main_module = PyImport_AddModule("__main__"); /* borrowed */
if(main_module == NULL) {
mod_main = PyImport_AddModule("__main__"); /* borrowed */
if(mod_main == NULL) {
THROW_JEP(env, "Couldn't add module __main__.");
PyEval_ReleaseLock();
return 0;
}

globals = PyModule_GetDict(main_module);
globals = PyModule_GetDict(mod_main);
Py_INCREF(globals);

// init static module
Expand Down Expand Up @@ -394,7 +394,7 @@ static PyObject* pyembed_jproxy(PyObject *self, PyObject *args) {
jclass clazz;
jobject cl;
jobject classes;
int inum, i;
Py_ssize_t inum, i;
jobject proxy;

if(!PyArg_ParseTuple(args, "OO!:jproxy",
Expand Down Expand Up @@ -437,7 +437,7 @@ static PyObject* pyembed_jproxy(PyObject *self, PyObject *args) {

// now convert string list to java array

classes = (*env)->NewObjectArray(env, inum, JSTRING_TYPE, NULL);
classes = (*env)->NewObjectArray(env, (jsize) inum, JSTRING_TYPE, NULL);
if(process_java_exception(env) || !classes)
return NULL;

Expand All @@ -448,12 +448,12 @@ static PyObject* pyembed_jproxy(PyObject *self, PyObject *args) {

item = PyList_GET_ITEM(interfaces, i);
if(!PyString_Check(item))
return PyErr_Format(PyExc_ValueError, "Item %i not a string.", i);
return PyErr_Format(PyExc_ValueError, "Item %zd not a string.", i);

str = PyString_AsString(item);
jstr = (*env)->NewStringUTF(env, (const char *) str);

(*env)->SetObjectArrayElement(env, classes, i, jstr);
(*env)->SetObjectArrayElement(env, classes, (jsize) i, jstr);
(*env)->DeleteLocalRef(env, jstr);
}

Expand Down Expand Up @@ -507,7 +507,7 @@ static PyObject* pyembed_jimport(PyObject *self, PyObject *args) {
jclass clazz;
jobject cl;
JepThread *jepThread;
int len, i;
Py_ssize_t len, i;
jobjectArray jar;

char *name;
Expand Down Expand Up @@ -623,7 +623,7 @@ static PyObject* pyembed_jimport(PyObject *self, PyObject *args) {
PyObject *pclass = NULL;
PyObject *memberList = NULL;

member = (*env)->GetObjectArrayElement(env, jar, i);
member = (*env)->GetObjectArrayElement(env, jar, (jsize) i);
if(process_import_exception(env) || !member) {
(*env)->DeleteLocalRef(env, member);
continue;
Expand Down Expand Up @@ -653,7 +653,8 @@ static PyObject* pyembed_jimport(PyObject *self, PyObject *args) {
PyString_AsString(PyTuple_GET_ITEM(fromlist, 0))[0] != '*') {

PyObject *pymember;
int found, i, len;
int found;
Py_ssize_t i, len;

pymember = PyList_GET_ITEM(
memberList,
Expand Down Expand Up @@ -1177,7 +1178,7 @@ jobject pyembed_box_py(JNIEnv *env, PyObject *result) {

if(PyInt_Check(result)) {
jclass clazz;
jlong i = PyInt_AS_LONG(result);
jint i = (jint) PyInt_AS_LONG(result);

clazz = (*env)->FindClass(env, "java/lang/Integer");

Expand Down Expand Up @@ -1547,7 +1548,7 @@ static int maybe_pyc_file(FILE *fp,
/* Read only two bytes of the magic. If the file was opened in
text mode, the bytes 3 and 4 of the magic (\r\n) might not
be read as they are on disk. */
long halfmagic = PyImport_GetMagicNumber() & 0xFFFF;
unsigned int halfmagic = (unsigned int) PyImport_GetMagicNumber() & 0xFFFF;
unsigned char buf[2];
/* Mess: In case of -x, the stream is NOT at its start now,
and ungetc() was used to push back the first newline,
Expand Down
Loading

0 comments on commit d3d3e48

Please sign in to comment.