From f710ac56e81e71dc1dd057e39704bcad8acce159 Mon Sep 17 00:00:00 2001 From: Young Ryul Bae Date: Fri, 24 May 2019 21:55:48 +0900 Subject: [PATCH 1/7] add dunder __dir__ for java methods For readable / usable propose, added __dir__ to JavaMethod & JavaMultipleMethod. It is more human readable than JNI signatures. --- jnius/jnius_export_class.pxi | 6 +++ jnius/jnius_utils.pxi | 76 ++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/jnius/jnius_export_class.pxi b/jnius/jnius_export_class.pxi index 3c56505d..89e48525 100644 --- a/jnius/jnius_export_class.pxi +++ b/jnius/jnius_export_class.pxi @@ -682,6 +682,9 @@ cdef class JavaMethod(object): self.j_cls = NULL self.j_self = None + def __dir__(self): + return list([readable_sig(self.definition, self.is_varargs)]) + def __init__(self, definition, **kwargs): super(JavaMethod, self).__init__() self.definition = definition @@ -961,6 +964,9 @@ cdef class JavaMultipleMethod(object): cdef bytes name cdef bytes classname + def __dir__(self): + return [readable_sig(args, is_varargs) for args, static, is_varargs in self.definitions] + def __cinit__(self, definition, **kwargs): self.j_self = None diff --git a/jnius/jnius_utils.pxi b/jnius/jnius_utils.pxi index a6e1cc0d..2f9516c7 100644 --- a/jnius/jnius_utils.pxi +++ b/jnius/jnius_utils.pxi @@ -402,3 +402,79 @@ cdef int calculate_score(sign_args, args, is_varargs=False) except *: # a method with a better signature so we don't # change this method score return score + +cdef readable_sig(sig, is_var): + """ + Converts JNI signature to easily readable Signature. + :param sig: JNI signature string + :param is_var: if the function has varargs + :return:([arg], rtn) + """ + dic = {'Z': 'boolean', + 'B': 'byte', + 'C': 'char', + 'D': 'double', + 'F': 'float', + 'I': 'int', + 'J': 'long', + 'S': 'short', + 'V': 'void', + '[': 'array', + 'L': 'fqs'} + + splt = sig.split(')') + # remove first '(' + args_str = splt[0][1:] + args = [] + is_array = False + i = 0 + while i < len(args_str): + c = args_str[i] + type_ = dic[c] + if type_ == 'array': + is_array = True + i += 1 + elif type_ == 'fqs': + cls_n = '' + for fqs_i in range(i+1, len(args_str)): + if args_str[fqs_i] == ';': + i = fqs_i + 1 + break + else: + cls_n += args_str[fqs_i] + args.append(cls_n + '[]' if is_array else cls_n) + is_array = False + else: + args.append(dic[c] + '[]' if is_array else dic[c]) + is_array = False + i += 1 + + # last element of args is array and function has Varargs + if len(args) > 0 and args[-1][-2:] == '[]' and is_var: + args[-1] = args[-1][:-2] + '...' + + rtn_str = splt[1] + rtn = '' + i = 0 + is_array = False + while i < len(rtn_str): + c = rtn_str[i] + type_ = dic[c] + if type_ == 'array': + is_array = True + i += 1 + elif type_ == 'fqs': + cls_n = '' + for fqs_i in range(i + 1, len(rtn_str)): + if rtn_str[fqs_i] == ';': + i = fqs_i + 1 + break + else: + cls_n += rtn_str[fqs_i] + rtn = cls_n + '[]' if is_array else cls_n + else: + rtn = dic[c] + '[]' if is_array else dic[c] + i += 1 + + return args, rtn + From e515e002ddc0dbfbeed394f987a5c298c93eca10 Mon Sep 17 00:00:00 2001 From: Young Ryul Bae Date: Sun, 7 Jul 2019 20:42:32 +0900 Subject: [PATCH 2/7] test added --- tests/test_dir.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/test_dir.py diff --git a/tests/test_dir.py b/tests/test_dir.py new file mode 100644 index 00000000..325720fe --- /dev/null +++ b/tests/test_dir.py @@ -0,0 +1,43 @@ +from __future__ import print_function +from __future__ import division +from __future__ import absolute_import +import unittest +from jnius.reflect import autoclass + +class DirTest(unittest.TestCase): + + def test_varargs_dir(self): + cls = autoclass("java.lang.System") + assert isinstance(dir(cls.out.printf), list) + #[(['java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream'), + # (['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream')] + for f in dir(cls.out.printf): + assert isinstance(f, tuple) + + def test_array_dir(self): + cls = autoclass("java.util.List") + assert isinstance(dir(cls.toArray), list) + #[([], 'java/lang/Object[]'), + # (['java/lang/Object[]'], 'java/lang/Object[]')] + for f in dir(cls.toArray): + assert isinstance(f, tuple) + + def test_dir(self): + cls = autoclass("java.lang.String") + assert isinstance(dir(cls.valueOf), list) + # [(['boolean'], 'java/lang/String'), + # (['char'], 'java/lang/String'), + # (['char[]'], 'java/lang/String'), + # (['char[]', 'int', 'int'], 'java/lang/String'), + # (['double'], 'java/lang/String'), + # (['float'], 'java/lang/String'), + # (['int'], 'java/lang/String'), + # (['java/lang/Object'], 'java/lang/String'), + # (['long'], 'java/lang/String')] + for f in dir(cls.charAt): + assert isinstance(f, tuple) + + + + + From 1ee5d2958706bdce2f818136792cd6d55b5aec20 Mon Sep 17 00:00:00 2001 From: Young Ryul Bae Date: Sun, 15 Dec 2019 14:41:51 +0900 Subject: [PATCH 3/7] add more comments and typo fix --- jnius/jnius_utils.pxi | 2 +- tests/test_dir.py | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/jnius/jnius_utils.pxi b/jnius/jnius_utils.pxi index 2f9516c7..a5684bfb 100644 --- a/jnius/jnius_utils.pxi +++ b/jnius/jnius_utils.pxi @@ -405,7 +405,7 @@ cdef int calculate_score(sign_args, args, is_varargs=False) except *: cdef readable_sig(sig, is_var): """ - Converts JNI signature to easily readable Signature. + Converts JNI signature to easily readable signature. :param sig: JNI signature string :param is_var: if the function has varargs :return:([arg], rtn) diff --git a/tests/test_dir.py b/tests/test_dir.py index 325720fe..8b94a761 100644 --- a/tests/test_dir.py +++ b/tests/test_dir.py @@ -7,24 +7,32 @@ class DirTest(unittest.TestCase): def test_varargs_dir(self): + # >>> from jnius import autoclass + # >>> cls = autoclass('java.lang.System') + # >>> dir(cls.out.printf) + # [(['java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream'), + # (['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream')] cls = autoclass("java.lang.System") assert isinstance(dir(cls.out.printf), list) - #[(['java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream'), - # (['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream')] for f in dir(cls.out.printf): assert isinstance(f, tuple) def test_array_dir(self): + # >>> from jnius import autoclass + # >>> cls = autoclass('java.util.List') + # >>> dir(cls.toArray) + # [([], 'java/lang/Object[]'), + # (['java/lang/Object[]'], 'java/lang/Object[]')] cls = autoclass("java.util.List") assert isinstance(dir(cls.toArray), list) - #[([], 'java/lang/Object[]'), - # (['java/lang/Object[]'], 'java/lang/Object[]')] + for f in dir(cls.toArray): assert isinstance(f, tuple) def test_dir(self): - cls = autoclass("java.lang.String") - assert isinstance(dir(cls.valueOf), list) + # >>> from jnius import autoclass + # >>> cls = autoclass('java.lang.String') + # >>> dir(cls.valueOf) # [(['boolean'], 'java/lang/String'), # (['char'], 'java/lang/String'), # (['char[]'], 'java/lang/String'), @@ -34,6 +42,8 @@ def test_dir(self): # (['int'], 'java/lang/String'), # (['java/lang/Object'], 'java/lang/String'), # (['long'], 'java/lang/String')] + cls = autoclass("java.lang.String") + assert isinstance(dir(cls.valueOf), list) for f in dir(cls.charAt): assert isinstance(f, tuple) From 601dfa15fba863f5e7772134dad4ca40d4033ec2 Mon Sep 17 00:00:00 2001 From: Gabriel Pettier Date: Sun, 15 Dec 2019 10:50:45 +0100 Subject: [PATCH 4/7] make tests more useful --- tests/test_dir.py | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/tests/test_dir.py b/tests/test_dir.py index 8b94a761..dbe57ac0 100644 --- a/tests/test_dir.py +++ b/tests/test_dir.py @@ -12,10 +12,15 @@ def test_varargs_dir(self): # >>> dir(cls.out.printf) # [(['java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream'), # (['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream')] + cls = autoclass("java.lang.System") - assert isinstance(dir(cls.out.printf), list) - for f in dir(cls.out.printf): - assert isinstance(f, tuple) + result = dir(cls.out.printf) + + assert isinstance(result, list) + assert all(isinstance(f, tuple) for f in result) + + assert (['java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream') in result + assert (['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream') in result def test_array_dir(self): # >>> from jnius import autoclass @@ -23,11 +28,15 @@ def test_array_dir(self): # >>> dir(cls.toArray) # [([], 'java/lang/Object[]'), # (['java/lang/Object[]'], 'java/lang/Object[]')] + cls = autoclass("java.util.List") - assert isinstance(dir(cls.toArray), list) + result = dir(cls.toArray) + + assert isinstance(result, list) + assert all(isinstance(f, tuple) for f in result) - for f in dir(cls.toArray): - assert isinstance(f, tuple) + assert ([], 'java/lang/Object[]') in result + assert (['java/lang/Object[]'], 'java/lang/Object[]') in result def test_dir(self): # >>> from jnius import autoclass @@ -42,12 +51,21 @@ def test_dir(self): # (['int'], 'java/lang/String'), # (['java/lang/Object'], 'java/lang/String'), # (['long'], 'java/lang/String')] - cls = autoclass("java.lang.String") - assert isinstance(dir(cls.valueOf), list) - for f in dir(cls.charAt): - assert isinstance(f, tuple) - - + cls = autoclass("java.lang.String") + result = dir(cls.valueOf) + assert isinstance(result, list) + assert all(isinstance(f, tuple) for f in result) + assert result == [ + (['boolean'], 'java/lang/String'), + (['char'], 'java/lang/String'), + (['char[]'], 'java/lang/String'), + (['char[]', 'int', 'int'], 'java/lang/String'), + (['double'], 'java/lang/String'), + (['float'], 'java/lang/String'), + (['int'], 'java/lang/String'), + (['java/lang/Object'], 'java/lang/String'), + (['long'], 'java/lang/String') + ] From a5d3bb4069c268ce618ac6124d763bd24b85cef4 Mon Sep 17 00:00:00 2001 From: Gabriel Pettier Date: Sun, 15 Dec 2019 11:01:10 +0100 Subject: [PATCH 5/7] expose the signatures as a signature object instead of `__dir__` --- jnius/jnius_export_class.pxi | 4 ++-- jnius/jnius_utils.pxi | 2 +- tests/test_dir.py | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/jnius/jnius_export_class.pxi b/jnius/jnius_export_class.pxi index 89e48525..53e8e15e 100644 --- a/jnius/jnius_export_class.pxi +++ b/jnius/jnius_export_class.pxi @@ -682,7 +682,7 @@ cdef class JavaMethod(object): self.j_cls = NULL self.j_self = None - def __dir__(self): + def signatures(self): return list([readable_sig(self.definition, self.is_varargs)]) def __init__(self, definition, **kwargs): @@ -964,7 +964,7 @@ cdef class JavaMultipleMethod(object): cdef bytes name cdef bytes classname - def __dir__(self): + def signatures(self): return [readable_sig(args, is_varargs) for args, static, is_varargs in self.definitions] def __cinit__(self, definition, **kwargs): diff --git a/jnius/jnius_utils.pxi b/jnius/jnius_utils.pxi index a5684bfb..55cbc255 100644 --- a/jnius/jnius_utils.pxi +++ b/jnius/jnius_utils.pxi @@ -403,6 +403,7 @@ cdef int calculate_score(sign_args, args, is_varargs=False) except *: # change this method score return score + cdef readable_sig(sig, is_var): """ Converts JNI signature to easily readable signature. @@ -477,4 +478,3 @@ cdef readable_sig(sig, is_var): i += 1 return args, rtn - diff --git a/tests/test_dir.py b/tests/test_dir.py index dbe57ac0..e5fff699 100644 --- a/tests/test_dir.py +++ b/tests/test_dir.py @@ -6,15 +6,15 @@ class DirTest(unittest.TestCase): - def test_varargs_dir(self): + def test_varargs_signatures(self): # >>> from jnius import autoclass # >>> cls = autoclass('java.lang.System') - # >>> dir(cls.out.printf) + # >>> cls.out.printf.signatures() # [(['java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream'), # (['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream')] cls = autoclass("java.lang.System") - result = dir(cls.out.printf) + result = cls.out.printf.signatures() assert isinstance(result, list) assert all(isinstance(f, tuple) for f in result) @@ -22,15 +22,15 @@ def test_varargs_dir(self): assert (['java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream') in result assert (['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/io/PrintStream') in result - def test_array_dir(self): + def test_array_signatures(self): # >>> from jnius import autoclass # >>> cls = autoclass('java.util.List') - # >>> dir(cls.toArray) + # >>> cls.toArray.signatures() # [([], 'java/lang/Object[]'), # (['java/lang/Object[]'], 'java/lang/Object[]')] cls = autoclass("java.util.List") - result = dir(cls.toArray) + result = cls.toArray.signatures() assert isinstance(result, list) assert all(isinstance(f, tuple) for f in result) @@ -38,10 +38,10 @@ def test_array_dir(self): assert ([], 'java/lang/Object[]') in result assert (['java/lang/Object[]'], 'java/lang/Object[]') in result - def test_dir(self): + def test_signatures(self): # >>> from jnius import autoclass # >>> cls = autoclass('java.lang.String') - # >>> dir(cls.valueOf) + # >>> cls.valueOf.signatures() # [(['boolean'], 'java/lang/String'), # (['char'], 'java/lang/String'), # (['char[]'], 'java/lang/String'), @@ -53,7 +53,7 @@ def test_dir(self): # (['long'], 'java/lang/String')] cls = autoclass("java.lang.String") - result = dir(cls.valueOf) + result = cls.valueOf.signatures() assert isinstance(result, list) assert all(isinstance(f, tuple) for f in result) From c355b74a8aec9338304c5afaf236943b9633c70f Mon Sep 17 00:00:00 2001 From: Gabriel Pettier Date: Sun, 15 Dec 2019 11:04:42 +0100 Subject: [PATCH 6/7] sort signatures in test --- tests/test_dir.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_dir.py b/tests/test_dir.py index e5fff699..323635c9 100644 --- a/tests/test_dir.py +++ b/tests/test_dir.py @@ -58,7 +58,7 @@ def test_signatures(self): assert isinstance(result, list) assert all(isinstance(f, tuple) for f in result) - assert result == [ + assert sorted(result) == sorted([ (['boolean'], 'java/lang/String'), (['char'], 'java/lang/String'), (['char[]'], 'java/lang/String'), @@ -68,4 +68,4 @@ def test_signatures(self): (['int'], 'java/lang/String'), (['java/lang/Object'], 'java/lang/String'), (['long'], 'java/lang/String') - ] + ]) From 27c544e9bb644a6ae4ad7685d6aad46fa4d5a534 Mon Sep 17 00:00:00 2001 From: Gabriel Pettier Date: Sun, 15 Dec 2019 11:44:09 +0100 Subject: [PATCH 7/7] document `signatures` method in readme. --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 17173340..ef512761 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,17 @@ for x in xrange(20): sleep(.1) ``` +You can use the `signatures` method of `JavaMethod` and `JavaMultipleMethod`, to inspect the discovered signatures of a method of an object + +```python +>>> String = autoclass('java.lang.String') +>>> dir(String) +['CASE_INSENSITIVE_ORDER', '__class__', '__cls_storage', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__javaclass__', '__javaconstructor__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__pyx_vtable__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'charAt', 'checkBounds', 'clone', 'codePointAt', 'codePointBefore', 'codePointCount', 'compareTo', 'compareToIgnoreCase', 'concat', 'contains', 'contentEquals', 'copyValueOf', 'empty', 'endsWith', 'equals', 'equalsIgnoreCase', 'finalize', 'format', 'getBytes', 'getChars', 'getClass', 'hashCode', 'indexOf', 'indexOfSupplementary', 'intern', 'isEmpty', 'join', 'lastIndexOf', 'lastIndexOfSupplementary', 'length', 'matches', 'nonSyncContentEquals', 'notify', 'notifyAll', 'offsetByCodePoints', 'regionMatches', 'registerNatives', 'replace', 'replaceAll', 'replaceFirst', 'split', 'startsWith', 'subSequence', 'substring', 'toCharArray', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'valueOf', 'wait'] +>>> String.format.signatures() +[(['java/util/Locale', 'java/lang/String', 'java/lang/Object...'], 'java/lang/String'), (['java/lang/String', 'java/lang/Object...'], 'java/lang/String')] +``` +Each pair contains the list of accepted arguments types, and the returned type. + Troubleshooting ---------------