diff --git a/.travis.yml b/.travis.yml index 4ccae98..3248653 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/_javabridge.pyx b/_javabridge.pyx index 90c67a7..c9c9ae6 100644 --- a/_javabridge.pyx +++ b/_javabridge.pyx @@ -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 @@ -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, &env, &args) free(args.options) if result != 0: @@ -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 = PyCObject_AsVoidPtr(capsule) + self.env = PyCapsule_GetPointer(capsule, NULL) if not self.env: raise ValueError( "set_env called with non-environment capsule") @@ -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" @@ -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 @@ -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 @@ -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() @@ -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 @@ -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() @@ -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(')') @@ -1060,7 +1072,7 @@ cdef class JB_Env: free(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) @@ -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() @@ -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`) @@ -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() @@ -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) @@ -1628,7 +1645,7 @@ 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: @@ -1636,7 +1653,7 @@ cdef class JB_Env: if 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 @@ -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 = PyCObject_AsVoidPtr(pCapsule) + jobj = PyCapsule_GetPointer(pCapsule, NULL) if not jobj: raise ValueError("Capsule did not contain a jobject") jbo = JB_Object() diff --git a/demo/demo_nogui.py b/demo/demo_nogui.py index 22eacf1..ee7240a 100755 --- a/demo/demo_nogui.py +++ b/demo/demo_nogui.py @@ -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() diff --git a/java/org_cellprofiler_javabridge_CPython.c b/java/org_cellprofiler_javabridge_CPython.c index 14cdb59..11fcf74 100644 --- a/java/org_cellprofiler_javabridge_CPython.c +++ b/java/org_cellprofiler_javabridge_CPython.c @@ -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; @@ -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); diff --git a/javabridge/_javabridge.cpython-34m.so b/javabridge/_javabridge.cpython-34m.so new file mode 100755 index 0000000..9f7a240 Binary files /dev/null and b/javabridge/_javabridge.cpython-34m.so differ diff --git a/javabridge/jutil.py b/javabridge/jutil.py index f30e1b7..3639983 100644 --- a/javabridge/jutil.py +++ b/javabridge/jutil.py @@ -9,9 +9,9 @@ All rights reserved. ''' +from __future__ import print_function + -import codecs -import ctypes import gc import inspect import logging @@ -26,11 +26,21 @@ from .locate import find_javahome import javabridge import weakref -import uuid + + +# long and int are the same type in Py3 +if sys.version_info[0] >= 3: + long = int logger = logging.getLogger(__name__) +if sys.version_info >= (3, 0, 0): + # basestring -> str and unicode -> str in Python 3 + basestring = str + unicode = str + + class JavaError(ValueError): '''An error caused by using the Javabridge incorrectly''' def __init__(self, message=None): @@ -82,9 +92,11 @@ def _find_jvm_windows(): if os.path.isfile(os.path.join(jvm_dir, "jvm.dll")): new_path = ';'.join((os.environ['PATH'], jvm_dir, jre_bin)) if isinstance(os.environ['PATH'], str) and \ - isinstance(new_path, unicode): + isinstance(new_path, unicode) and \ + sys.version_info < (3, 0, 0): # Don't inadvertantly set an environment variable # to unicode: causes subprocess.check_call to fail + # in Python 2 new_path = new_path.encode("utf-8") os.environ['PATH'] = new_path found_jvm = True @@ -140,7 +152,7 @@ def _find_jvm(): # Has side-effect of preloading dylibs _find_jvm_mac() -import _javabridge +import javabridge._javabridge as _javabridge __dead_event = threading.Event() __kill = [False] __main_thread_closures = [] @@ -172,8 +184,8 @@ def __del__(self): class vm(): def __init__(self, *args, **kwds): - self.args = args - self.kwds = kwds + self.args = args + self.kwds = kwds def __enter__(self): start_vm(*self.args, **self.kwds) @@ -356,7 +368,7 @@ def run_script(script, bindings_in = {}, bindings_out = {}, scope = make_instance("org/mozilla/javascript/ImporterTopLevel", "(Lorg/mozilla/javascript/Context;)V", context) - for k, v in bindings_in.iteritems(): + for k, v in bindings_in.items(): call(scope, "put", "(Ljava/lang/String;Lorg/mozilla/javascript/Scriptable;" "Ljava/lang/Object;)V", k, scope, v) @@ -375,7 +387,7 @@ def run_script(script, bindings_in = {}, bindings_out = {}, "(Ljava/lang/String;" "Lorg/mozilla/javascript/Scriptable;)" "Ljava/lang/Object;", k, scope)) - except JavaException, e: + except JavaException as e: if is_instance_of(e.throwable, "org/mozilla/javascript/WrappedException"): raise JavaException(call(e.throwable, "unwrap", "()Ljava/lang/Object;")) else: @@ -649,7 +661,7 @@ def run_in_main_thread(closure, synchronous): def synchronous_closure(): try: result[0] = closure() - except Exception, e: + except Exception as e: logger.exception("Caught exception when executing closure") exception[0] = e done_event.set() @@ -672,7 +684,7 @@ def print_all_stack_traces(): for stak in stal: stakes = get_env().get_object_array_elements(stak) for stake in stakes: - print to_string(stake) + print(to_string(stake)) CLOSE_ALL_WINDOWS = """ new java.lang.Runnable() { @@ -1156,12 +1168,10 @@ def get_nice_arg(arg, sig): return make_instance('java/lang/Double', '(D)V', arg) if (sig in ('Ljava/lang/String;','Ljava/lang/Object;') and not isinstance(arg, _javabridge.JB_Object)): - if isinstance(arg, unicode): - arg, _ = codecs.utf_8_encode(arg) - elif arg is None: + if arg is None: return None else: - arg = str(arg) + arg = unicode(arg) return env.new_string_utf(arg) if sig == 'Ljava/lang/Integer;' and type(arg) in [int, long, bool]: return make_instance('java/lang/Integer', '(I)V', int(arg)) @@ -1210,7 +1220,7 @@ def get_nice_result(result, sig): if (sig == 'Ljava/lang/String;' or (sig == 'Ljava/lang/Object;' and is_instance_of(result, "java/lang/String"))): - return codecs.utf_8_decode(env.get_string_utf(result), 'replace')[0] + return env.get_string_utf(result) if sig == 'Ljava/lang/Integer;': return call(result, 'intValue', '()I') if sig == 'Ljava/lang/Long': @@ -1313,7 +1323,7 @@ def get_collection_wrapper(collection, fn_wrapper=None): for d in get_collection_wrapper(list_of_hashmaps, get_map_wrapper): # a map wrapper on the hashmap is returned - print d["Foo"] + print(d["Foo"]) ''' class Collection(object): @@ -1423,11 +1433,11 @@ def make_list(elements=[]): Examples:: >>> mylist = make_list(["Hello", "World", 2]) - >>> print "\\n".join([to_string(o) for o in mylist]) + >>> print("\\n".join([to_string(o) for o in mylist])) Hello World 2 - >>> print "%s, %s." % (mylist[0], mylist[1].lower()) + >>> print("%s, %s." % (mylist[0], mylist[1].lower())) Hello, world. >>> get_class_wrapper(mylist.o) java.util.ArrayList @@ -1496,7 +1506,7 @@ def get_map_wrapper(o): > d = get_map_wrapper(jmap) > d["Foo"] = "Bar" - > print d["Foo"] + > print(d["Foo"]) Bar ''' assert is_instance_of(o, 'java/util/Map') @@ -1540,7 +1550,7 @@ def make_map(**kwargs): Example:: > d = make_map(foo="Bar") - > print d["foo"] + > print(d["foo"]) Bar > get_class_wrapper(d.o) java.util.HashMap @@ -1548,7 +1558,7 @@ def make_map(**kwargs): public java.lang.Object java.util.HashMap.put(java.lang.Object,java.lang.Object) ''' hashmap = get_map_wrapper(make_instance('java/util/HashMap', "()V")) - for k, v in kwargs.iteritems(): + for k, v in kwargs.items(): hashmap[k] = v return hashmap @@ -1586,7 +1596,7 @@ def get_enumeration_wrapper(enumeration): >>> enum = javabridge.get_enumeration_wrapper(keys) >>> while enum.hasMoreElements(): ... if javabridge.to_string(enum.nextElement()) == 'java.vm.name': - ... print "Has java.vm.name" + ... print("Has java.vm.name") ... Has java.vm.name @@ -2008,7 +2018,7 @@ def make_run_dictionary(jobject): while jentry_set_iterator.hasNext(): entry = jentry_set_iterator.next() key, value = [o if not isinstance(o, javabridge.JWrapper) else o.o - for o in entry.getKey(), entry.getValue()] + for o in (entry.getKey(), entry.getValue())] result[to_string(key)] = value return result diff --git a/javabridge/locate.py b/javabridge/locate.py index 93be62d..851dac5 100644 --- a/javabridge/locate.py +++ b/javabridge/locate.py @@ -19,14 +19,16 @@ is_mac = sys.platform == 'darwin' is_win = sys.platform.startswith("win") is_win64 = (is_win and (os.environ["PROCESSOR_ARCHITECTURE"] == "AMD64")) -is_msvc = (is_win and sys.version_info[0] >= 2 and sys.version_info[1] >= 6) +is_msvc = (is_win and + ((sys.version_info.major == 2 and sys.version_info.minor >= 6) or + (sys.version_info.major == 3))) is_mingw = (is_win and not is_msvc) logger = logging.getLogger(__name__) def find_javahome(): """Find JAVA_HOME if it doesn't exist""" - if os.environ.has_key('JAVA_HOME'): + if 'JAVA_HOME' in os.environ: return os.environ['JAVA_HOME'] elif is_mac: # Use the "java_home" executable to find the location @@ -66,7 +68,7 @@ def get_out(cmd): o, ignore = p.communicate() if p.poll() != 0: raise Exception("Error finding javahome on linux: %s" % cmd) - o = o.strip() + o = o.strip().decode('utf-8') return o java_bin = get_out(["bash", "-c", "type -p java"]) java_dir = get_out(["readlink", "-f", java_bin]) @@ -74,20 +76,23 @@ def get_out(cmd): jdk_dir = os.path.abspath(jdk_dir) return jdk_dir elif is_win: - import _winreg + if sys.version_info.major == 2: + import _winreg as winreg + else: + import winreg java_key_path = 'SOFTWARE\\JavaSoft\\Java Runtime Environment' looking_for = java_key_path try: - kjava = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, java_key_path) + kjava = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, java_key_path) looking_for = java_key_path + "\\CurrentVersion" - kjava_values = dict([_winreg.EnumValue(kjava, i)[:2] - for i in range(_winreg.QueryInfoKey(kjava)[1])]) + kjava_values = dict([winreg.EnumValue(kjava, i)[:2] + for i in range(winreg.QueryInfoKey(kjava)[1])]) current_version = kjava_values['CurrentVersion'] looking_for = java_key_path + '\\' + current_version - kjava_current = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, + kjava_current = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, looking_for) - kjava_current_values = dict([_winreg.EnumValue(kjava_current, i)[:2] - for i in range(_winreg.QueryInfoKey(kjava_current)[1])]) + kjava_current_values = dict([winreg.EnumValue(kjava_current, i)[:2] + for i in range(winreg.QueryInfoKey(kjava_current)[1])]) return kjava_current_values['JavaHome'] except: logger.error("Failed to find registry entry: %s\n" %looking_for, @@ -97,25 +102,28 @@ def get_out(cmd): def find_jdk(): """Find the JDK under Windows""" - if os.environ.has_key('JDK_HOME'): + if 'JDK_HOME' in os.environ: return os.environ['JDK_HOME'] if is_mac: return find_javahome() if is_win: - import _winreg - import exceptions + if sys.version_info.major == 2: + import _winreg as winreg + from exceptions import WindowsError + else: + import winreg try: jdk_key_path = 'SOFTWARE\\JavaSoft\\Java Development Kit' - kjdk = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, jdk_key_path) - kjdk_values = dict([_winreg.EnumValue(kjdk, i)[:2] - for i in range(_winreg.QueryInfoKey(kjdk)[1])]) + kjdk = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, jdk_key_path) + kjdk_values = dict([winreg.EnumValue(kjdk, i)[:2] + for i in range(winreg.QueryInfoKey(kjdk)[1])]) current_version = kjdk_values['CurrentVersion'] - kjdk_current = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, + kjdk_current = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, jdk_key_path + '\\' + current_version) - kjdk_current_values = dict([_winreg.EnumValue(kjdk_current, i)[:2] - for i in range(_winreg.QueryInfoKey(kjdk_current)[1])]) + kjdk_current_values = dict([winreg.EnumValue(kjdk_current, i)[:2] + for i in range(winreg.QueryInfoKey(kjdk_current)[1])]) return kjdk_current_values['JavaHome'] - except exceptions.WindowsError as e: + except WindowsError as e: if e.errno == 2: raise RuntimeError( "Failed to find the Java Development Kit. Please download and install the Oracle JDK 1.6 or later") diff --git a/javabridge/tests/test_cpython.py b/javabridge/tests/test_cpython.py index 9314a3a..8660184 100644 --- a/javabridge/tests/test_cpython.py +++ b/javabridge/tests/test_cpython.py @@ -35,7 +35,7 @@ def fn(numerator, denominator, answer): jlocals.put("code", code) jlocals.put("answer", jref.o) self.cpython.execute(code, jlocals.o, None) - self.assertEqual(javabridge.to_string(jref.get(0)), "3") + self.assertEqual(float(javabridge.to_string(jref.get(0))), 3) def test_01_03_globals(self): jglobals = javabridge.JClassWrapper('java.util.HashMap')() @@ -51,7 +51,7 @@ def fn(): javabridge.call(answer, "add", "(Ljava/lang/Object;)Z", str(result)) fn() """, None, jglobals.o) - self.assertEqual(javabridge.to_string(jref.get(0)), "3") + self.assertEqual(float(javabridge.to_string(jref.get(0))), 3) def test_01_04_globals_equals_locals(self): jglobals = javabridge.JClassWrapper('java.util.HashMap')() @@ -69,4 +69,4 @@ def fn(): javabridge.call(answer, "add", "(Ljava/lang/Object;)Z", str(result)) fn() """, jglobals.o, jglobals.o) - self.assertEqual(javabridge.to_string(jref.get(0)), "3") \ No newline at end of file + self.assertEqual(float(javabridge.to_string(jref.get(0))), 3) \ No newline at end of file diff --git a/javabridge/tests/test_javabridge.py b/javabridge/tests/test_javabridge.py index 4a443f8..a36cf7a 100644 --- a/javabridge/tests/test_javabridge.py +++ b/javabridge/tests/test_javabridge.py @@ -41,7 +41,7 @@ def test_01_03_00_new_string_utf(self): def test_01_03_01_new_string_unicode(self): s = u"Hola ni\u00F1os" jstring = self.env.new_string(s) - self.assertEqual(self.env.get_string_utf(jstring).decode("utf-8"), s) + self.assertEqual(self.env.get_string_utf(jstring), s) def test_01_03_02_new_string_string(self): s = "Hello, world" @@ -331,13 +331,14 @@ def test_03_08_call_method_double(self): self.assertAlmostEqual(self.env.call_method(jdouble, method_id), -55.64) def test_03_09_call_method_array(self): - jstring = self.env.new_string_utf("Hello, world") + s = "Hello, world" + jstring = self.env.new_string_utf(s) klass = self.env.get_object_class(jstring) method_id = self.env.get_method_id(klass, 'getBytes', '()[B') result = self.env.call_method(jstring, method_id) self.assertTrue(isinstance(result, jb.JB_Object)) a = self.env.get_byte_array_elements(result) - self.assertEqual("Hello, world", a.tostring()) + self.assertEqual(np.array(s, "S%d" % len(s)).tostring(), a.tostring()) def test_03_10_call_method_object(self): hello = self.env.new_string_utf("Hello, ") @@ -445,7 +446,7 @@ def test_05_06_get_static_long_field(self): klass = self.env.find_class("java/security/Key") field_id = self.env.get_static_field_id(klass, "serialVersionUID", "J") result = self.env.get_static_long_field(klass, field_id) - self.assertEqual(result, 6603384152749567654l) # see http://java.sun.com/j2se/1.4.2/docs/api/constant-values.html#java.security.Key.serialVersionUID + self.assertEqual(result, 6603384152749567654) def test_05_07_get_static_float_field(self): klass = self.env.find_class("java/lang/Float") diff --git a/setup.py b/setup.py index ac83c3b..c321db7 100644 --- a/setup.py +++ b/setup.py @@ -8,6 +8,7 @@ All rights reserved. """ +from __future__ import print_function import errno import glob @@ -43,7 +44,7 @@ def in_cwd(basename): def build_cython(): """Compile the pyx files if we have them. - + The git repository has the .pyx files but not the .c files, and the source distributions that are uploaded to PyPI have the .c files and not the .pyx files. (The reason for the latter is that @@ -75,7 +76,7 @@ def get_jvm_include_dirs(): elif is_mac: where_jni_h_is_post_6 = os.path.join(java_home, 'include') if os.path.isfile(os.path.join(where_jni_h_is_post_6, "jni.h")): - + include_dirs += [where_jni_h_is_post_6, os.path.join(java_home, 'include', 'darwin')] else: @@ -83,9 +84,9 @@ def get_jvm_include_dirs(): elif is_linux: include_dirs += [os.path.join(java_home,'include'), os.path.join(java_home,'include','linux')] - + return include_dirs - + def ext_modules(): extensions = [] extra_link_args = None @@ -107,7 +108,7 @@ def ext_modules(): # Build libjvm from jvm.dll on Windows. # This assumes that we're using mingw32 for build # - cmd = ["dlltool", "--dllname", + cmd = ["dlltool", "--dllname", os.path.join(jdk_home,"jre\\bin\\client\\jvm.dll"), "--output-lib","libjvm.a", "--input-def","jvm.def", @@ -147,12 +148,12 @@ def ext_modules(): SO = ".dll" if sys.platform == 'win32' \ else ".jnilib" if sys.platform == 'darwin'\ - else sysconfig.get_config_var("SO") + else ".so" def needs_compilation(target, *sources): try: target_date = os.path.getmtime(target) - except OSError, e: + except OSError as e: if e.errno != errno.ENOENT: raise return True @@ -197,10 +198,11 @@ def run(self, *args, **kwargs): def build_jar_from_sources(self, jar, sources): if sys.platform == 'win32': sources = [source.replace("/", os.path.sep) for source in sources] - jar = self.get_ext_fullpath(jar) - jar = os.path.splitext(jar)[0] + ".jar" + jar_filename = jar.rsplit(".", 1)[1] + ".jar" + jar_dir = os.path.dirname(self.get_ext_fullpath(jar)) + jar = os.path.join(jar_dir, jar_filename) jar_command = [find_jar_cmd(), 'cf', package_path(jar)] - + javac_loc = find_javac_cmd() dirty_jar = False javac_command = [javac_loc, "-source", "6", "-target", "6"] @@ -208,7 +210,7 @@ def build_jar_from_sources(self, jar, sources): javac_command.append(package_path(source)) if needs_compilation(jar, source): dirty_jar = True - + self.spawn(javac_command) if dirty_jar: if not os.path.exists(os.path.dirname(jar)): @@ -218,11 +220,11 @@ def build_jar_from_sources(self, jar, sources): java_klass_path = klass[klass.index(os.path.sep) + 1:].replace(os.path.sep, "/") jar_command.extend(['-C', package_path('java'), java_klass_path]) self.spawn(jar_command) - + def build_java2cpython(self): sources = self.java2cpython_sources distutils.log.info("building java2cpython library") - + # First, compile the source code to object files in the library # directory. (This should probably change to putting object @@ -232,13 +234,15 @@ def build_java2cpython(self): get_jvm_include_dirs() python_lib_dir, lib_name = self.get_java2cpython_libdest() library_dirs = [python_lib_dir] - output_dir = os.path.splitext(self.get_ext_fullpath("javabridge.jars"))[0] - export_symbols = ['Java_org_cellprofiler_javabridge_CPython_exec'] + output_dir = os.path.join(os.path.dirname( + self.get_ext_fullpath("javabridge.jars")), "jars") + export_symbols = ['Java_org_cellprofiler_javabridge_CPython_exec'] objects = self.compiler.compile(sources, output_dir=self.build_temp, include_dirs=include_dirs, debug=self.debug) - extra_postargs = ["/MANIFEST"] if sys.platform == 'win32' else None + needs_manifest = sys.platform == 'win32' and sys.version_info.major == 2 + extra_postargs = ["/MANIFEST"] if needs_manifest else None self.compiler.link( CCompiler.SHARED_OBJECT, objects, lib_name, @@ -247,7 +251,7 @@ def build_java2cpython(self): library_dirs=library_dirs, export_symbols=export_symbols, extra_postargs=extra_postargs) - if sys.platform == 'win32': + if needs_manifest: temp_dir = os.path.dirname(objects[0]) manifest_name = lib_name +".manifest" lib_path = os.path.join(output_dir, lib_name) @@ -257,9 +261,9 @@ def build_java2cpython(self): out_arg = '-outputresource:%s;2' % lib_path try: self.compiler.spawn([ - 'mt.exe', '-nologo', '-manifest', manifest_file, + 'mt.exe', '-nologo', '-manifest', manifest_file, out_arg]) - except DistutilsExecError, msg: + except DistutilsExecError as msg: raise LinkError(msg) def get_java2cpython_libdest(self): @@ -272,34 +276,34 @@ def get_java2cpython_libdest(self): python_lib_dir = sysconfig.get_config_var('LIBDIR') lib_name = "libjava2cpython" + SO return python_lib_dir, lib_name - + def build_jar_from_single_source(self, jar, source): self.build_jar_from_sources(jar, [source]) - + def build_runnablequeue(self): jar = 'javabridge.jars.runnablequeue' source = 'java/org/cellprofiler/runnablequeue/RunnableQueue.java' self.build_jar_from_single_source(jar, source) - + def build_cpython(self): jar = 'javabridge.jars.cpython' sources = [ 'java/org/cellprofiler/javabridge/CPython.java', 'java/org/cellprofiler/javabridge/CPythonInvocationHandler.java'] self.build_jar_from_sources(jar, sources) - + def build_test(self): jar = 'javabridge.jars.test' source = 'java/org/cellprofiler/javabridge/test/RealRect.java' self.build_jar_from_single_source(jar, source) - + def build_java(self): self.build_runnablequeue() self.build_test() self.build_cpython() - + def get_version(): """Get version from git or file system. @@ -313,19 +317,19 @@ def get_version(): if os.path.exists(os.path.join(os.path.dirname(__file__), '.git')): import subprocess try: - git_version = subprocess.Popen(['git', 'describe'], - stdout=subprocess.PIPE).communicate()[0].strip() + git_version = subprocess.Popen(['git', 'describe'], + stdout=subprocess.PIPE).communicate()[0].strip().decode('utf-8') except: pass - version_file = os.path.join(os.path.dirname(__file__), 'javabridge', + version_file = os.path.join(os.path.dirname(__file__), 'javabridge', '_version.py') if os.path.exists(version_file): with open(version_file) as f: cached_version_line = f.read().strip() try: # From http://stackoverflow.com/a/3619714/17498 - cached_version = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", + cached_version = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", cached_version_line, re.M).group(1) except: raise RuntimeError("Unable to find version in %s" % version_file) @@ -334,7 +338,7 @@ def get_version(): if git_version and git_version != cached_version: with open(version_file, 'w') as f: - print >>f, '__version__ = "%s"' % git_version + print('__version__ = "%s"' % git_version, file=f) return git_version or cached_version @@ -356,7 +360,8 @@ def get_version(): classifiers=['Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: BSD License', 'Programming Language :: Java', - 'Programming Language :: Python :: 2 :: Only' + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3' ], license='BSD License', install_requires=['numpy'],