Skip to content

Commit

Permalink
Merge pull request #74 from jni/py3
Browse files Browse the repository at this point in the history
Another attempt at Python 3 support
  • Loading branch information
LeeKamentsky committed Mar 10, 2016
2 parents 61712c1 + a7ed071 commit 3eb1acc
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 110 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
language: java
env:
- PYTHON_VERSION="2.7"
- PYTHON_VERSION="3.5"
before_install:
# Get the tag if it wasn't provided. Travis doesn't provide this if it isn't a tagged build.
- if [ -z $TRAVIS_TAG ]; then TRAVIS_TAG=`git tag --contains` ; fi
Expand Down
65 changes: 41 additions & 24 deletions _javabridge.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ cimport cython
cimport _javabridge_osspecific
cimport cpython

if sys.version_info >= (3, 0, 0):
# unchir -> chr in Python 3
unichr = chr

cdef extern from "Python.h":
ctypedef int Py_intptr_t
ctypedef unsigned long Py_ssize_t
unicode PyUnicode_DecodeUTF16(char *s, Py_ssize_t size, char *errors, int *byteorder)
bint PyCObject_Check(object o)
void *PyCObject_AsVoidPtr(object o)
bint PyCapsule_CheckExact(object o)
void *PyCapsule_GetPointer(object o,char *name)

cdef extern from "stdlib.h":
ctypedef unsigned long size_t
Expand Down Expand Up @@ -601,8 +605,10 @@ cdef class JB_VM:
if args.options == NULL:
raise MemoryError("Failed to allocate JavaVMInitArgs")
options = [str(option) for option in options]
optionutf8=[] # list for temporarily storing utf-8 copies of strings
for i, option in enumerate(options):
args.options[i].optionString = option
optionutf8.append(option.encode('utf-8'))
args.options[i].optionString = optionutf8[-1]
result = CreateJavaVM(&self.vm, <void **>&env, &args)
free(args.options)
if result != 0:
Expand Down Expand Up @@ -713,10 +719,10 @@ cdef class JB_Env:
address - address as an integer representation of a string
'''
if not PyCObject_Check(capsule):
if not PyCapsule_CheckExact(capsule):
raise ValueError(
"set_env called with something other than a wrapped environment")
self.env = <JNIEnv *>PyCObject_AsVoidPtr(capsule)
self.env = <JNIEnv *>PyCapsule_GetPointer(capsule, NULL)
if not self.env:
raise ValueError(
"set_env called with non-environment capsule")
Expand All @@ -739,7 +745,7 @@ cdef class JB_Env:
version = self.env[0].GetVersion(self.env)
return (int(version / 65536), version % 65536)

def find_class(self, char *name):
def find_class(self, name):
'''Find a Java class by name
:param name: the class name with "/" as the path separator, e.g. "java/lang/String"
Expand All @@ -748,7 +754,8 @@ cdef class JB_Env:
cdef:
jclass c
JB_Class result
c = self.env[0].FindClass(self.env, name)
utf8name = name.encode('utf-8')
c = self.env[0].FindClass(self.env, utf8name)
if c == NULL:
print "Failed to get class "+name
return
Expand Down Expand Up @@ -800,7 +807,7 @@ cdef class JB_Env:
'''Clear the current exception'''
self.env[0].ExceptionClear(self.env)

def get_method_id(self, JB_Class c, char *name, char *sig):
def get_method_id(self, JB_Class c, name, sig):
'''Find the method ID for a method on a class
:param c: a class retrieved by find_class or get_object_class
Expand All @@ -814,9 +821,11 @@ cdef class JB_Env:
cdef:
jmethodID id
__JB_MethodID result
utf8name = name.encode('utf-8')
utf8sig = sig.encode('utf-8')
if c is None:
raise ValueError("Class = None on call to get_method_id")
id = self.env[0].GetMethodID(self.env, c.c, name, sig)
id = self.env[0].GetMethodID(self.env, c.c, utf8name, utf8sig)
if id == NULL:
return
result = __JB_MethodID()
Expand All @@ -825,7 +834,7 @@ cdef class JB_Env:
result.is_static = False
return result

def get_static_method_id(self, JB_Class c, char *name, char *sig):
def get_static_method_id(self, JB_Class c, name, sig):
'''Find the method ID for a static method on a class
:param c: a class retrieved by find_class or get_object_class
Expand All @@ -839,7 +848,9 @@ cdef class JB_Env:
cdef:
jmethodID id
__JB_MethodID result
id = self.env[0].GetStaticMethodID(self.env, c.c, name, sig)
utf8name = name.encode('utf-8')
utf8sig = sig.encode('utf-8')
id = self.env[0].GetStaticMethodID(self.env, c.c, utf8name, utf8sig)
if id == NULL:
return
result = __JB_MethodID()
Expand Down Expand Up @@ -896,8 +907,9 @@ cdef class JB_Env:
if m is None:
raise ValueError("Method ID is None - check your method ID call")
if m.is_static:
raise ValueError("call_method called with a static method. Use call_static_method instead")
sig = m.sig
raise ValueError("call_method called with a static method. Use"
" call_static_method instead")
sig = m.sig # m.sig should be unicode already, no need to decode
if sig[0] != '(':
raise ValueError("Bad function signature: %s"%m.sig)
arg_end = sig.find(')')
Expand Down Expand Up @@ -1060,7 +1072,7 @@ cdef class JB_Env:
free(<void *>values)
return result

def get_field_id(self, JB_Class c, char *name, char *sig):
def get_field_id(self, JB_Class c, name, sig):
'''Get a field ID for a class
:param c: class (from :py:meth:`.find_class` or similar)
Expand All @@ -1071,7 +1083,10 @@ cdef class JB_Env:
jfieldID id
__JB_FieldID jbid

id = self.env[0].GetFieldID(self.env, c.c, name, sig)
utf8name = name.encode('utf-8')
utf8sig = sig.encode('utf-8')

id = self.env[0].GetFieldID(self.env, c.c, utf8name, utf8sig)
if id == NULL:
return None
jbid = __JB_FieldID()
Expand Down Expand Up @@ -1285,7 +1300,7 @@ cdef class JB_Env:
jdouble jvalue = float(value)
self.env[0].SetDoubleField(self.env, o.o, field.id, jvalue)

def get_static_field_id(self, JB_Class c, char *name, char *sig):
def get_static_field_id(self, JB_Class c, name, sig):
'''Look up a static field ID on a class
:param c: the object's class (e.g. as retrieved from :py:meth:`.find_class`)
Expand All @@ -1298,7 +1313,9 @@ cdef class JB_Env:
jfieldID id
__JB_FieldID jbid

id = self.env[0].GetStaticFieldID(self.env, c.c, name, sig)
utf8name = name.encode('utf-8')
utf8sig = sig.encode('utf-8')
id = self.env[0].GetStaticFieldID(self.env, c.c, utf8name, utf8sig)
if id == NULL:
return None
jbid = __JB_FieldID()
Expand Down Expand Up @@ -1588,16 +1605,16 @@ cdef class JB_Env:
raise e
return jbo

def new_string_utf(self, char *s):
def new_string_utf(self, s):
'''Turn a Python string into a Java string object
:param s: a UTF-8 encoded Python string
:param s: a Python string or unicode object
:return: a Java string object
:rtype: JB_Object
'''
cdef:
jobject o
o = self.env[0].NewStringUTF(self.env, s)
o = self.env[0].NewStringUTF(self.env, s.encode('utf-8'))
if o == NULL:
raise MemoryError("Failed to allocate string")
jbo, e = make_jb_object(self, o)
Expand Down Expand Up @@ -1628,15 +1645,15 @@ cdef class JB_Env:
'''Turn a Java string object into a Python string
:param s: a Java object
:return: a UTF-8 encoded string representation of the object
:return: a string (Python 3) or unicode (Python 2) representation of s
:rtype: str
'''
cdef:
const char *chars
if <int> s.o == 0:
return None
chars = self.env[0].GetStringUTFChars(self.env, s.o, NULL)
result = str(chars)
result = chars.decode('utf-8')
self.env[0].ReleaseStringUTFChars(self.env, s.o, chars)
return result

Expand Down Expand Up @@ -1926,9 +1943,9 @@ cdef class JB_Env:
cdef:
jobject jobj
JB_Object jbo
if not PyCObject_Check(pCapsule):
if not PyCapsule_CheckExact(pCapsule):
raise ValueError("Argument must be a jobject in a capsule")
jobj = <jobject>PyCObject_AsVoidPtr(pCapsule)
jobj = <jobject>PyCapsule_GetPointer(pCapsule, NULL)
if not jobj:
raise ValueError("Capsule did not contain a jobject")
jbo = JB_Object()
Expand Down
5 changes: 3 additions & 2 deletions demo/demo_nogui.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
"""

from __future__ import print_function
import os
import javabridge

javabridge.start_vm(run_headless=True)
try:
print javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);',
dict(greetee='world'))
print(javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);',
dict(greetee='world')))
finally:
javabridge.kill_vm()
4 changes: 2 additions & 2 deletions java/org_cellprofiler_javabridge_CPython.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ static int attach_env(JNIEnv *pEnv){
javabridge.jni_enter(env)
*/

pPyEnv = PyCObject_FromVoidPtr((void *)pEnv, NULL);
pPyEnv = PyCapsule_New((void *)pEnv, NULL, NULL);
if (PyErr_Occurred()) {
throwWrappedError(pEnv, __LINE__);
return -1;
Expand Down Expand Up @@ -272,7 +272,7 @@ static PyObject *wrapJObject(JNIEnv *pEnv, jobject j) {
Py_DECREF(pJavabridge);
return NULL;
}
pCapsule = PyCObject_FromVoidPtr((void *)j, NULL);
pCapsule = PyCapsule_New((void *)j, NULL, NULL);
if (! pCapsule) {
throwWrappedError(pEnv, __LINE__);
Py_DECREF(pTheEnv);
Expand Down
Binary file added javabridge/_javabridge.cpython-34m.so
Binary file not shown.
Loading

0 comments on commit 3eb1acc

Please sign in to comment.