37
37
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38
38
# SOFTWARE.
39
39
40
+ import math
40
41
import os
42
+ import types
41
43
import unittest
42
44
from unittest import skipIf , skipUnless
43
45
@@ -106,6 +108,72 @@ class PyString(str):
106
108
107
109
@skipUnless (sys .implementation .name == "graalpy" and not __graalpython__ .is_native , "interop" )
108
110
class InteropTests (unittest .TestCase ):
111
+ # This should run first, before other tests create foreign objects which creates more foreign classes.
112
+ # We want to ensure all single-trait classes are always defined, so users can rely on them.
113
+ def test_single_trait_classes (self ):
114
+ classes = [
115
+ polyglot .ForeignObject ,
116
+ polyglot .ForeignList ,
117
+ polyglot .ForeignBoolean ,
118
+ polyglot .ForeignException ,
119
+ polyglot .ForeignExecutable ,
120
+ polyglot .ForeignDict ,
121
+ polyglot .ForeignInstantiable ,
122
+ polyglot .ForeignIterable ,
123
+ polyglot .ForeignIterator ,
124
+ polyglot .ForeignAbstractClass ,
125
+ polyglot .ForeignNone ,
126
+ polyglot .ForeignNumber ,
127
+ polyglot .ForeignString ,
128
+ ]
129
+
130
+ for c in classes :
131
+ self .assertIsInstance (c , type )
132
+ if c is polyglot .ForeignBoolean :
133
+ self .assertIs (c .__base__ , polyglot .ForeignNumber )
134
+ elif c is not polyglot .ForeignObject :
135
+ self .assertIs (c .__base__ , polyglot .ForeignObject )
136
+
137
+ def test_get_class (self ):
138
+ def wrap (obj ):
139
+ return __graalpython__ .foreign_wrapper (obj )
140
+
141
+ def t (obj ):
142
+ return type (wrap (obj ))
143
+
144
+ self .assertEqual (t (object ()), polyglot .ForeignObject )
145
+ self .assertEqual (t ([]), polyglot .ForeignList )
146
+ self .assertEqual (t (True ), polyglot .ForeignBoolean )
147
+ self .assertEqual (t (BaseException ()), polyglot .ForeignException )
148
+ self .assertEqual (t (lambda : None ), polyglot .ForeignExecutable )
149
+ self .assertEqual (t ({}), polyglot .ForeignDict )
150
+ # ForeignInstantiable
151
+ self .assertEqual (t ((e for e in [1 ])), polyglot .ForeignIteratorIterable )
152
+ self .assertEqual (t (iter ([1 ])), polyglot .ForeignIteratorIterable )
153
+ self .assertEqual (t (object ), polyglot .ForeignExecutableClass )
154
+ self .assertEqual (t (None ), polyglot .ForeignNone )
155
+ self .assertEqual (t (1 ), polyglot .ForeignNumber )
156
+ self .assertEqual (t ("abc" ), polyglot .ForeignString )
157
+
158
+ from java .lang import Object , Boolean , Integer , Throwable , Thread , Number , String
159
+ from java .util import ArrayList , HashMap , ArrayDeque
160
+ from java .math import BigInteger
161
+ null = Integer .getInteger ("something_that_does_not_exists" )
162
+
163
+ self .assertEqual (type (Object ()), polyglot .ForeignObject )
164
+ self .assertEqual (type (ArrayList ()), polyglot .ForeignList )
165
+ self .assertEqual (type (wrap (Boolean .valueOf (True ))), polyglot .ForeignBoolean )
166
+ self .assertEqual (type (Throwable ()), polyglot .ForeignException )
167
+ self .assertEqual (type (Thread ()), polyglot .ForeignExecutable ) # Thread implements Runnable
168
+ self .assertEqual (type (HashMap ()), polyglot .ForeignDict )
169
+ self .assertEqual (type (Object ), polyglot .ForeignClass ) # ForeignDictIterable
170
+ self .assertEqual (type (ArrayDeque ()), polyglot .ForeignIterable )
171
+ self .assertEqual (type (ArrayList ().iterator ()), polyglot .ForeignIterator )
172
+ self .assertEqual (type (Number ), polyglot .ForeignAbstractClass )
173
+ self .assertEqual (type (null ), polyglot .ForeignNone )
174
+ self .assertEqual (type (BigInteger .valueOf (42 )), polyglot .ForeignNumber )
175
+ self .assertEqual (type (wrap (String ("abc" ))), polyglot .ForeignString )
176
+
109
177
def test_import (self ):
110
178
def some_function ():
111
179
return "hello, polyglot world!"
@@ -403,9 +471,10 @@ def test_java_import_from_jar(self):
403
471
os .unlink (tempname )
404
472
405
473
def test_java_class (self ):
406
- from java .lang import Integer , NumberFormatException
407
- self .assertEqual (['ForeignInstantiableType' , 'foreign' , 'object' ], [t .__name__ for t in type (Integer ).mro ()])
408
- self .assertEqual (['ForeignInstantiableType' , 'foreign' , 'object' ], [t .__name__ for t in type (NumberFormatException ).mro ()])
474
+ from java .lang import Integer , Number , NumberFormatException
475
+ self .assertEqual (type (Integer ).mro (), [polyglot .ForeignClass , polyglot .ForeignInstantiable , polyglot .ForeignAbstractClass , polyglot .ForeignObject , object ])
476
+ self .assertEqual (type (Number ).mro (), [polyglot .ForeignAbstractClass , polyglot .ForeignObject , object ])
477
+ self .assertEqual (type (NumberFormatException ).mro (), [polyglot .ForeignClass , polyglot .ForeignInstantiable , polyglot .ForeignAbstractClass , polyglot .ForeignObject , object ])
409
478
410
479
def test_java_exceptions (self ):
411
480
# TODO: more tests
@@ -417,7 +486,7 @@ def test_java_exceptions(self):
417
486
418
487
assert isinstance (e , BaseException )
419
488
assert BaseException in type (e ).mro ()
420
- self .assertEqual ([' ForeignException' , ' BaseException' , 'foreign' , ' object' ], [ t . __name__ for t in type (e ).mro ()] )
489
+ self .assertEqual ([polyglot . ForeignException , BaseException , polyglot . ForeignObject , object ], type (e ).mro ())
421
490
self .assertEqual ('java.lang.NumberFormatException: For input string: \" 99\" under radix 8' , str (e ))
422
491
self .assertEqual ("ForeignException('java.lang.NumberFormatException: For input string: \" 99\" under radix 8')" , repr (e ))
423
492
assert True
@@ -503,10 +572,10 @@ def test_java_null_is_none(self):
503
572
y = Integer .getInteger ("something_that_does_not_exists2" )
504
573
z = None
505
574
506
- assert isinstance (x , type ( None ) )
575
+ assert isinstance (x , types . NoneType )
507
576
assert type (x ) == polyglot .ForeignNone , type (x )
508
577
assert type (None ) in type (x ).mro ()
509
- self .assertEqual ([' ForeignNone' , ' NoneType' , 'foreign' , ' object' ], [ t . __name__ for t in type (x ).mro ()] )
578
+ self .assertEqual ([polyglot . ForeignNone , types . NoneType , polyglot . ForeignObject , object ], type (x ).mro ())
510
579
assert repr (x ) == 'None'
511
580
assert str (x ) == 'None'
512
581
@@ -632,13 +701,23 @@ def getLevel(self):
632
701
my_lr2 = MyLogRecord (Level .FINEST , message )
633
702
assert my_lr2 .getLevel () == Level .WARNING
634
703
704
+ def test_super (self ):
705
+ from java .util import ArrayList
706
+ l = ArrayList ()
707
+ l .extend ([5 , 6 , 7 ])
708
+ l .remove (7 ) # Python list.remove
709
+ assert l == [5 , 6 ]
710
+
711
+ super (list , l ).remove (0 ) # ArrayList#remove(int index)
712
+ assert l == [6 ]
713
+
635
714
def test_java_array (self ):
636
715
import java
637
716
il = java .type ("int[]" )(20 )
638
717
639
718
assert isinstance (il , list )
640
719
assert list in type (il ).mro ()
641
- self .assertEqual ([' ForeignList' , ' list' , 'foreign' , ' object' ], [ t . __name__ for t in type (il ).mro ()] )
720
+ self .assertEqual ([polyglot . ForeignList , list , polyglot . ForeignObject , object ], type (il ).mro ())
642
721
assert repr (il ) == repr ([0 ] * 20 )
643
722
assert str (il ) == str ([0 ] * 20 )
644
723
@@ -695,7 +774,7 @@ def l(*elements):
695
774
696
775
assert isinstance (al , list )
697
776
assert list in type (al ).mro ()
698
- self .assertEqual ([' ForeignList' , ' list' , 'foreign' , ' object' ], [ t . __name__ for t in type (al ).mro ()] )
777
+ self .assertEqual ([polyglot . ForeignList , list , polyglot . ForeignObject , object ], type (al ).mro ())
699
778
assert repr (l (1 ,2 )) == repr ([1 ,2 ])
700
779
assert str (l (1 ,2 )) == str ([1 ,2 ])
701
780
@@ -850,7 +929,7 @@ def test_java_map(self):
850
929
851
930
assert isinstance (h , dict )
852
931
assert dict in type (h ).mro ()
853
- self .assertEqual ([' ForeignDict' , ' dict' , 'foreign' , ' object' ], [ t . __name__ for t in type (h ).mro ()] )
932
+ self .assertEqual ([polyglot . ForeignDict , dict , polyglot . ForeignObject , object ], type (h ).mro ())
854
933
assert repr (h ) == repr ({1 : 2 })
855
934
assert str (h ) == str ({1 : 2 }), str (h )
856
935
assert h
@@ -981,7 +1060,7 @@ def test_java_iterator(self):
981
1060
iterator_type = type (iter ([]))
982
1061
assert isinstance (itr , iterator_type )
983
1062
assert iterator_type in type (itr ).mro ()
984
- self .assertEqual ([' ForeignIterator' , 'iterator' , 'foreign' , ' object' ], [ t . __name__ for t in type (itr ).mro ()] )
1063
+ self .assertEqual ([polyglot . ForeignIterator , iterator_type , polyglot . ForeignObject , object ], type (itr ).mro ())
985
1064
assert '<polyglot.ForeignIterator object at 0x' in repr (itr ), repr (itr )
986
1065
assert '<polyglot.ForeignIterator object at 0x' in str (itr ), str (itr )
987
1066
assert bool (itr ) == True
@@ -1043,7 +1122,7 @@ def wrap(string):
1043
1122
1044
1123
assert isinstance (s , str )
1045
1124
assert str in type (s ).mro ()
1046
- self .assertEqual ([' ForeignString' , ' str' , 'foreign' , ' object' ], [ t . __name__ for t in type (s ).mro ()] )
1125
+ self .assertEqual ([polyglot . ForeignString , str , polyglot . ForeignObject , object ], type (s ).mro ())
1047
1126
assert repr (s ) == repr ("ab" )
1048
1127
assert str (s ) == str ("ab" ), str (s )
1049
1128
assert bool (s ) == True
@@ -1053,7 +1132,7 @@ def wrap(string):
1053
1132
assert not empty
1054
1133
1055
1134
c = Character .valueOf (ord ("A" ))
1056
- self .assertEqual ([' ForeignString' , ' str' , 'foreign' , ' object' ], [ t . __name__ for t in type (c ).mro ()] )
1135
+ self .assertEqual ([polyglot . ForeignString , str , polyglot . ForeignObject , object ], type (c ).mro ())
1057
1136
assert repr (c ) == repr ("A" )
1058
1137
assert str (c ) == str ("A" ), str (s )
1059
1138
assert c
@@ -1152,7 +1231,7 @@ def test_foreign_number_list(self):
1152
1231
1153
1232
assert isinstance (n , list )
1154
1233
assert list in type (n ).mro ()
1155
- self .assertEqual ([ ' ForeignNumberList' , 'ForeignNumberType' , 'list' , 'foreign' , 'object' ], [ t . __name__ for t in type ( n ). mro () ])
1234
+ self .assertEqual (type ( n ). mro (), [ polyglot . ForeignNumberList , polyglot . ForeignNumber , polyglot . ForeignList , list , polyglot . ForeignObject , object ])
1156
1235
assert repr (n ) == '42' , repr (n )
1157
1236
assert str (n ) == '42' , str (n )
1158
1237
assert n
@@ -1182,6 +1261,121 @@ def test_foreign_number_list(self):
1182
1261
assert l > n
1183
1262
assert n < l
1184
1263
1264
+ def test_foreign_number (self ):
1265
+ def wrap (obj ):
1266
+ return __graalpython__ .foreign_wrapper (obj )
1267
+
1268
+ def assertValueAndType (actual , expected ):
1269
+ self .assertEqual (expected , actual )
1270
+ self .assertEqual (type (expected ), type (actual ))
1271
+
1272
+ n = wrap (42 )
1273
+ self .assertEqual (type (n ).mro (), [polyglot .ForeignNumber , polyglot .ForeignObject , object ])
1274
+ assert repr (n ) == '42' , repr (n )
1275
+ assert str (n ) == '42' , str (n )
1276
+ assert n
1277
+
1278
+ assert wrap (2 ) + wrap (3 ) == 5
1279
+ assert wrap (2 ) - wrap (3 ) == - 1
1280
+ assert wrap (2 ) * wrap (3 ) == 6
1281
+ assert wrap (7 ) / wrap (2 ) == 3.5
1282
+ assert wrap (7 ) // wrap (2 ) == 3
1283
+ assert wrap (8 ) % wrap (3 ) == 2
1284
+ assert wrap (2 ) ** wrap (3 ) == 8
1285
+ assert wrap (1 ) << wrap (3 ) == 8
1286
+ assert wrap (8 ) >> wrap (2 ) == 2
1287
+
1288
+ # 1 and not 1.0 is unfortunate but interop does not give us a way to know if a non-primitive/wrapped 3.0 is integral or floating point
1289
+ assertValueAndType (wrap (3.0 ) // wrap (2.0 ), 1 )
1290
+ assertValueAndType (wrap (3.0 ) // 2.0 , 1.0 )
1291
+ assertValueAndType (3.0 // wrap (2.0 ), 1.0 )
1292
+
1293
+ assertValueAndType (wrap (3 ) - 2.0 , 1.0 )
1294
+ assertValueAndType (3.0 - wrap (2 ), 1.0 )
1295
+
1296
+ assert wrap (0b1110 ) & wrap (0b0111 ) == 0b0110
1297
+ assert wrap (0b1110 ) | wrap (0b0111 ) == 0b1111
1298
+ assert wrap (0b1110 ) ^ wrap (0b0111 ) == 0b1001
1299
+
1300
+ assert wrap ((1 << 65 ) - 2 ) & wrap (0b111 ) == 0b110
1301
+ assert wrap ((1 << 65 ) - 2 ) | wrap (0b111 ) == ((1 << 65 ) - 1 )
1302
+ assert wrap ((1 << 65 ) - 2 ) ^ wrap (0b1 ) == ((1 << 65 ) - 1 )
1303
+
1304
+ assert wrap (42 ).as_integer_ratio () == (42 , 1 )
1305
+ assert wrap (0b1010 ).bit_count () == 2
1306
+ assert wrap (0b1010 ).bit_length () == 4
1307
+ assert wrap (42 ).conjugate () == 42
1308
+ assert wrap (42 ).is_integer ()
1309
+ assert wrap (42.0 ).is_integer ()
1310
+ assert not wrap (42.5 ).is_integer ()
1311
+ assert wrap (42.0 ).to_bytes () == b"*"
1312
+
1313
+ assert ~ wrap (42 ) == - 43
1314
+ assert - wrap (42 ) == - 42
1315
+ assert + wrap (42 ) == 42
1316
+
1317
+ assertValueAndType (abs (wrap (- 2 )), 2 )
1318
+ assertValueAndType (float (wrap (2 )), 2.0 )
1319
+ assertValueAndType (int (wrap (2.3 )), 2 )
1320
+ assertValueAndType (math .floor (wrap (2.3 )), 2 )
1321
+ assertValueAndType (math .ceil (wrap (2.3 )), 3 )
1322
+ assertValueAndType (math .trunc (wrap (- 2.3 )), - 2 )
1323
+ assertValueAndType (round (wrap (2.3 )), 2 )
1324
+
1325
+ missing_int_methods = set (dir (int )) - set (dir (type (wrap (1 ))))
1326
+ missing_int_methods = [m for m in missing_int_methods if m .startswith ('_' ) and m != '__getnewargs__' ]
1327
+ self .assertEqual ([], missing_int_methods )
1328
+
1329
+ missing_float_methods = set (dir (float )) - set (dir (type (wrap (1.2 ))))
1330
+ missing_float_methods = [m for m in missing_float_methods if m .startswith ('_' ) and m not in ('__getnewargs__' , '__getformat__' )]
1331
+ self .assertEqual ([], missing_float_methods )
1332
+
1333
+ def test_foreign_boolean (self ):
1334
+ def wrap (obj ):
1335
+ return __graalpython__ .foreign_wrapper (obj )
1336
+
1337
+ def assertValueAndType (actual , expected ):
1338
+ self .assertEqual (expected , actual )
1339
+ self .assertEqual (type (expected ), type (actual ))
1340
+
1341
+ self .assertEqual (type (wrap (True )).mro (), [polyglot .ForeignBoolean , polyglot .ForeignNumber , polyglot .ForeignObject , object ])
1342
+ assert repr (wrap (True )) == 'True'
1343
+ assert repr (wrap (False )) == 'False'
1344
+ assert str (wrap (True )) == 'True'
1345
+ assert str (wrap (False )) == 'False'
1346
+ assert wrap (True )
1347
+ assert not wrap (False )
1348
+
1349
+ assert bool (wrap (True )) is True
1350
+ assert bool (wrap (False )) is False
1351
+
1352
+ assertValueAndType (wrap (True ) + wrap (2 ), 3 )
1353
+ assertValueAndType (wrap (False ) + wrap (2 ), 2 )
1354
+ assertValueAndType (wrap (2 ) + wrap (True ), 3 )
1355
+ assertValueAndType (wrap (2 ) + wrap (False ), 2 )
1356
+
1357
+ assertValueAndType (wrap (True ) - wrap (2 ), - 1 )
1358
+ assertValueAndType (wrap (2 ) - wrap (True ), 1 )
1359
+
1360
+ assert wrap (True ) & wrap (True ) is True
1361
+ assert wrap (True ) & wrap (False ) is False
1362
+
1363
+ assert wrap (True ) | wrap (False ) is True
1364
+ assert wrap (False ) | wrap (False ) is False
1365
+
1366
+ assert wrap (True ) ^ wrap (False ) is True
1367
+ assert wrap (False ) ^ wrap (False ) is False
1368
+
1369
+ assertValueAndType (~ wrap (True ), - 2 )
1370
+ assertValueAndType (~ wrap (False ), - 1 )
1371
+
1372
+ assertValueAndType (float (wrap (True )), 1.0 )
1373
+ assertValueAndType (int (wrap (True )), 1 )
1374
+
1375
+ missing_bool_methods = set (dir (bool )) - set (dir (type (wrap (True ))))
1376
+ missing_bool_methods = [m for m in missing_bool_methods if m .startswith ('_' ) and m != '__getnewargs__' ]
1377
+ self .assertEqual ([], missing_bool_methods )
1378
+
1185
1379
def test_foreign_repl (self ):
1186
1380
from java .util .logging import LogRecord
1187
1381
from java .util .logging import Level
0 commit comments