Skip to content

Commit

Permalink
Merge pull request #467 from kivy/signatures_in__dir__
Browse files Browse the repository at this point in the history
expose readable signatures.
  • Loading branch information
tshirtman authored Dec 15, 2019
2 parents bf17b10 + 27c544e commit 8380ee8
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
---------------

Expand Down
6 changes: 6 additions & 0 deletions jnius/jnius_export_class.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,9 @@ cdef class JavaMethod(object):
self.j_cls = NULL
self.j_self = None

def signatures(self):
return list([readable_sig(self.definition, self.is_varargs)])

def __init__(self, definition, **kwargs):
super(JavaMethod, self).__init__()
self.definition = definition
Expand Down Expand Up @@ -961,6 +964,9 @@ cdef class JavaMultipleMethod(object):
cdef bytes name
cdef bytes classname

def signatures(self):
return [readable_sig(args, is_varargs) for args, static, is_varargs in self.definitions]

def __cinit__(self, definition, **kwargs):
self.j_self = None

Expand Down
76 changes: 76 additions & 0 deletions jnius/jnius_utils.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -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
71 changes: 71 additions & 0 deletions tests/test_dir.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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_signatures(self):
# >>> from jnius import autoclass
# >>> cls = autoclass('java.lang.System')
# >>> 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 = cls.out.printf.signatures()

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_signatures(self):
# >>> from jnius import autoclass
# >>> cls = autoclass('java.util.List')
# >>> cls.toArray.signatures()
# [([], 'java/lang/Object[]'),
# (['java/lang/Object[]'], 'java/lang/Object[]')]

cls = autoclass("java.util.List")
result = cls.toArray.signatures()

assert isinstance(result, list)
assert all(isinstance(f, tuple) for f in result)

assert ([], 'java/lang/Object[]') in result
assert (['java/lang/Object[]'], 'java/lang/Object[]') in result

def test_signatures(self):
# >>> from jnius import autoclass
# >>> cls = autoclass('java.lang.String')
# >>> cls.valueOf.signatures()
# [(['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')]

cls = autoclass("java.lang.String")
result = cls.valueOf.signatures()

assert isinstance(result, list)
assert all(isinstance(f, tuple) for f in result)

assert sorted(result) == sorted([
(['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')
])

0 comments on commit 8380ee8

Please sign in to comment.