Skip to content

Commit ec51478

Browse files
committed
Add functions to reason about Java numeric types
1 parent 5c6de23 commit ec51478

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

src/scyjava/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
jclass,
120120
jinstance,
121121
jstacktrace,
122+
numeric_bounds,
122123
)
123124
from ._versions import ( # noqa: F401
124125
compare_version,

src/scyjava/_types.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,38 @@ def isjava(data) -> bool:
140140
return isinstance(data, jpype.JClass) or isinstance(data, jpype.JObject)
141141

142142

143+
def is_jbyte(the_type: type) -> bool:
144+
return _is_jtype(the_type, "java.lang.Byte")
145+
146+
147+
def is_jshort(the_type: type) -> bool:
148+
return _is_jtype(the_type, "java.lang.Short")
149+
150+
151+
def is_jinteger(the_type: type) -> bool:
152+
return _is_jtype(the_type, "java.lang.Integer")
153+
154+
155+
def is_jlong(the_type: type) -> bool:
156+
return _is_jtype(the_type, "java.lang.Long")
157+
158+
159+
def is_jfloat(the_type: type) -> bool:
160+
return _is_jtype(the_type, "java.lang.Float")
161+
162+
163+
def is_jdouble(the_type: type) -> bool:
164+
return _is_jtype(the_type, "java.lang.Double")
165+
166+
167+
def is_jboolean(the_type: type) -> bool:
168+
return _is_jtype(the_type, "java.lang.Boolean")
169+
170+
171+
def is_jcharacter(the_type: type) -> bool:
172+
return _is_jtype(the_type, "java.lang.Character")
173+
174+
143175
def is_jarray(data: Any) -> bool:
144176
"""Return whether the given data object is a Java array."""
145177
if mode == Mode.JEP:
@@ -246,3 +278,50 @@ def jarray(kind, lengths: Sequence):
246278
for i in range(len(arr)):
247279
arr[i] = jarray(kind, lengths[1:])
248280
return arr
281+
282+
283+
def numeric_bounds(the_type: type) -> Union[Tuple[int, int], Tuple[float, float], Tuple[None, None]]:
284+
"""
285+
Get the minimum and maximum values for the given numeric type.
286+
For example, a Java long returns (int(Long.MIN_VALUE), int(Long.MAX_VALUE)),
287+
whereas a Java double returns (float("-inf"), float("inf")).
288+
289+
:param the_type: The type whose minimum and maximum values are needed.
290+
:return:
291+
The minimum and maximum values as a two-element tuple of int or float,
292+
or a two-element tuple of None if no known bounds.
293+
"""
294+
if is_jbyte(the_type):
295+
Byte = jimport("java.lang.Byte")
296+
return int(Byte.MIN_VALUE), int(Byte.MAX_VALUE)
297+
298+
if is_jshort(the_type):
299+
Short = jimport("java.lang.Short")
300+
return int(Short.MIN_VALUE), int(Short.MAX_VALUE)
301+
302+
if is_jinteger(the_type):
303+
Integer = jimport("java.lang.Integer")
304+
return int(Integer.MIN_VALUE), int(Integer.MAX_VALUE)
305+
306+
if is_jlong(the_type):
307+
Long = jimport("java.lang.Long")
308+
return int(Long.MIN_VALUE), int(Long.MAX_VALUE)
309+
310+
if is_jfloat(the_type) or is_jdouble(the_type):
311+
return float("-inf"), float("inf")
312+
313+
return None, None
314+
315+
316+
def _is_jtype(the_type: type, class_name: str) -> bool:
317+
"""
318+
Test if the given type object is *exactly* the specified Java type.
319+
320+
:param the_type: The type object to check.
321+
:param class_name: The fully qualified Java class name in string form.
322+
:returns: True iff the type is exactly that Java type.
323+
"""
324+
# NB: Stringify the type to support both bridge modes. Ex:
325+
# * JPype: <java class 'java.lang.Integer'>
326+
# * Jep: <class 'java.lang.Integer'>
327+
return f"class '{class_name}'" in str(the_type)

tests/test_types.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import scyjava
2+
from scyjava import to_java, numeric_bounds
3+
4+
5+
class TestTypes(object):
6+
"""
7+
Test Java-type-related functions.
8+
"""
9+
10+
def test_numeric_bounds(self):
11+
v_byte = to_java(1, type='byte')
12+
v_short = to_java(2, type='short')
13+
v_int = to_java(3, type='int')
14+
v_long = to_java(4, type='long')
15+
v_bigint = to_java(5, type='bigint')
16+
v_float = to_java(6.7, type='float')
17+
v_double = to_java(7.8, type='double')
18+
v_bigdec = to_java(8.9, type='bigdec')
19+
20+
assert (-128, 127) == numeric_bounds(type(v_byte))
21+
assert (-32768, 32767) == numeric_bounds(type(v_short))
22+
assert (-2147483648, 2147483647) == numeric_bounds(type(v_int))
23+
assert (-9223372036854775808, 9223372036854775807) == numeric_bounds(type(v_long))
24+
assert (None, None) == numeric_bounds(type(v_bigint))
25+
assert (float("-inf"), float("inf")) == numeric_bounds(type(v_float))
26+
assert (float("-inf"), float("inf")) == numeric_bounds(type(v_double))
27+
assert (None, None) == numeric_bounds(type(v_bigdec))

0 commit comments

Comments
 (0)