@@ -402,3 +402,393 @@ end
402
402
@test pyeq (Bool, pybuiltins. eval (ans, pydict ()), 7 )
403
403
end
404
404
end
405
+
406
+ @testitem " import" begin
407
+ sys = pyimport (" sys" )
408
+ os = pyimport (" os" )
409
+ @test pyeq (Bool, sys. __name__, " sys" )
410
+ @test pyeq (Bool, os. __name__, " os" )
411
+ sysos = pyimport (" sys" , " os" )
412
+ @test sysos isa Tuple{Py, Py}
413
+ @test pyis (sysos[1 ], sys)
414
+ @test pyis (sysos[2 ], os)
415
+ ver = pyimport (" sys" => " version" )
416
+ @test pyis (ver, sys. version)
417
+ path = pyimport (" sys" => " path" )
418
+ @test pyis (path, sys. path)
419
+ verpath = pyimport (" sys" => (" version" , " path" ))
420
+ @test verpath isa Tuple{Py, Py}
421
+ @test pyis (verpath[1 ], ver)
422
+ @test pyis (verpath[2 ], path)
423
+ end
424
+
425
+ @testitem " consts" begin
426
+ @test pybuiltins. None isa Py
427
+ @test pystr (String, pybuiltins. None) == " None"
428
+ end
429
+
430
+ @testitem " str" begin
431
+ @test pyisinstance (pystr (" foo" ), pybuiltins. str)
432
+ @test pyeq (Bool, pystr (pystr (" foo" )), pystr (" foo" ))
433
+ @test pyeq (Bool, pystr (SubString (" foobarbaz" , 4 : 6 )), pystr (" bar" ))
434
+ @test pyeq (Bool, pystr (' x' ), pystr (" x" ))
435
+ @test pystr (String, pybuiltins. None) === " None"
436
+ @test pystr (String, pyint (123 )) === " 123"
437
+ @test pystr (String, pystr (" foo" )) === " foo"
438
+ end
439
+
440
+ @testitem " bytes" begin
441
+ @test pyisinstance (pybytes (UInt8[1 ,2 ,3 ]), pybuiltins. bytes)
442
+ @test pyeq (Bool, pybytes (pylist ([1 ,2 ,3 ])), pybytes (UInt8[1 ,2 ,3 ]))
443
+ @test pyeq (Bool, pybytes (b " foo" ), pystr (" foo" ). encode (" ascii" ))
444
+ @test pyeq (Bool, pybytes (codeunits (SubString (" foobarbaz" , 4 : 6 ))), pystr (" bar" ). encode (" ascii" ))
445
+ @test pybytes (Vector, pylist ([1 ,2 ,3 ])) == UInt8[1 ,2 ,3 ]
446
+ @test pybytes (Vector{UInt8}, pylist ([1 ,2 ,3 ])) == UInt8[1 ,2 ,3 ]
447
+ @test pybytes (Base. CodeUnits, pystr (" foo" ). encode (" ascii" )) == b " foo"
448
+ @test pybytes (Base. CodeUnits{UInt8,String}, pystr (" bar" ). encode (" ascii" )) == b " bar"
449
+ end
450
+
451
+ @testitem " tuple" begin
452
+ z = pytuple ()
453
+ @test pyisinstance (z, pybuiltins. tuple)
454
+ @test pylen (z) == 0
455
+ x = pytuple ((1 ,2 ,3 ))
456
+ @test pyisinstance (x, pybuiltins. tuple)
457
+ @test pylen (x) == 3
458
+ @test pyeq (Bool, pygetitem (x, 0 ), 1 )
459
+ @test pyeq (Bool, pygetitem (x, 1 ), 2 )
460
+ @test pyeq (Bool, pygetitem (x, 2 ), 3 )
461
+ @test pyeq (Bool, pytuple ([1 ,2 ,3 ]), x)
462
+ @test pyeq (Bool, pytuple (i+ 1 for i in 0 : 10 if i< 3 ), x)
463
+ @test pyeq (Bool, pytuple (pytuple ((1 ,2 ,3 ))), x)
464
+ @test pyeq (Bool, pytuple (pylist ([1 ,2 ,3 ])), x)
465
+ end
466
+
467
+ @testitem " list" begin
468
+ z = pylist ()
469
+ @test pyisinstance (z, pybuiltins. list)
470
+ @test pylen (z) == 0
471
+ x = pylist ((1 ,2 ,3 ))
472
+ @test pyisinstance (x, pybuiltins. list)
473
+ @test pylen (x) == 3
474
+ @test pyeq (Bool, pygetitem (x, 0 ), 1 )
475
+ @test pyeq (Bool, pygetitem (x, 1 ), 2 )
476
+ @test pyeq (Bool, pygetitem (x, 2 ), 3 )
477
+ @test pyeq (Bool, pylist ([1 ,2 ,3 ]), x)
478
+ @test pyeq (Bool, pylist (i+ 1 for i in 0 : 10 if i< 3 ), x)
479
+ @test pyeq (Bool, pylist (pylist ((1 ,2 ,3 ))), x)
480
+ @test pyeq (Bool, pylist (pytuple ([1 ,2 ,3 ])), x)
481
+ @test pyeq (Bool, pycollist ([1 ,2 ,3 ]), pylist ([1 ,2 ,3 ]))
482
+ @test pyeq (Bool, pycollist ([1 2 ; 3 4 ]), pylist ((pylist ([1 ,3 ]), pylist ([2 ,4 ]))))
483
+ @test pyeq (Bool, pyrowlist ([1 ,2 ,3 ]), pylist ([1 ,2 ,3 ]))
484
+ @test pyeq (Bool, pyrowlist ([1 2 ; 3 4 ]), pylist ((pylist ([1 ,2 ]), pylist ([3 ,4 ]))))
485
+ end
486
+
487
+ @testitem " dict" begin
488
+ z = pydict ()
489
+ @test pyisinstance (z, pybuiltins. dict)
490
+ @test pylen (z) == 0
491
+ x = pydict (foo= 1 , bar= 2 )
492
+ @test pyisinstance (x, pybuiltins. dict)
493
+ @test pylen (x) == 2
494
+ @test pyeq (Bool, pygetitem (x, " foo" ), 1 )
495
+ @test pyeq (Bool, pygetitem (x, " bar" ), 2 )
496
+ @test pyeq (Bool, pydict ([" foo" => 1 , " bar" => 2 ]), x)
497
+ @test pyeq (Bool, pydict ([(" foo" => 1 ), (" bar" => 2 )]), x)
498
+ @test pyeq (Bool, pydict (Dict (" foo" => 1 , " bar" => 2 )), x)
499
+ @test pyeq (Bool, pydict ((foo= 1 , bar= 2 )), x)
500
+ @test pyeq (Bool, pydict (x), x)
501
+ end
502
+
503
+ @testitem " bool" begin
504
+ @test pyis (pybool (), pybuiltins. False)
505
+ @test pyis (pybool (false ), pybuiltins. False)
506
+ @test pyis (pybool (true ), pybuiltins. True)
507
+ @test pyis (pybool (0.0 ), pybuiltins. False)
508
+ @test pyis (pybool (- 1.2 ), pybuiltins. True)
509
+ @test pyis (pybool (pybuiltins. None), pybuiltins. False)
510
+ @test pyis (pybool (pylist ()), pybuiltins. False)
511
+ @test pyis (pybool (pylist ([1 ,2 ,3 ])), pybuiltins. True)
512
+ end
513
+
514
+ @testitem " int" begin
515
+ @test pyisinstance (pyint (), pybuiltins. int)
516
+ @test pystr (String, pyint ()) == " 0"
517
+ x = 123
518
+ y = pyint (x)
519
+ @test pyisinstance (y, pybuiltins. int)
520
+ @test pystr (String, y) == string (x)
521
+ x = BigInt (123 ) << 200
522
+ y = pyint (x)
523
+ @test pyisinstance (y, pybuiltins. int)
524
+ @test pystr (String, y) == string (x)
525
+ x = UInt (123 )
526
+ y = pyint (x)
527
+ @test pyisinstance (y, pybuiltins. int)
528
+ @test pystr (String, y) == string (x)
529
+ x = UInt128 (123 ) << 100
530
+ y = pyint (x)
531
+ @test pyisinstance (y, pybuiltins. int)
532
+ @test pystr (String, y) == string (x)
533
+ @test pyeq (Bool, pyint (pyint (123 )), pyint (123 ))
534
+ @test pyeq (Bool, pyint (pyfloat (12.3 )), pyint (12 ))
535
+ end
536
+
537
+ @testitem " float" begin
538
+ y = pyfloat ()
539
+ @test pyisinstance (y, pybuiltins. float)
540
+ @test pyeq (Bool, y, pyint (0 ))
541
+ x = 123
542
+ y = pyfloat (x)
543
+ @test pyisinstance (y, pybuiltins. float)
544
+ @test pyeq (Bool, y, pyint (x))
545
+ x = 0.25
546
+ y = pyfloat (x)
547
+ @test pyisinstance (y, pybuiltins. float)
548
+ @test pyeq (Bool, y, pytruediv (1 , 4 ))
549
+ x = 1 // 4
550
+ y = pyfloat (x)
551
+ @test pyisinstance (y, pybuiltins. float)
552
+ @test pyeq (Bool, y, pyfloat (float (x)))
553
+ @test pyeq (Bool, pyfloat (pyfloat (12.3 )), pyfloat (12.3 ))
554
+ @test pyeq (Bool, pyfloat (pyint (123 )), pyfloat (123 ))
555
+ end
556
+
557
+ @testitem " complex" begin
558
+ y = pycomplex ()
559
+ @test pyisinstance (y, pybuiltins. complex)
560
+ @test pyeq (Bool, y, pyint (0 ))
561
+ x = 12.3
562
+ y = pycomplex (x)
563
+ @test pyisinstance (y, pybuiltins. complex)
564
+ @test pyeq (Bool, y, pyfloat (x))
565
+ xr, xi = 12 , 34
566
+ y = pycomplex (xr, xi)
567
+ @test pyisinstance (y, pybuiltins. complex)
568
+ @test pyeq (Bool, y. real, pyfloat (xr))
569
+ @test pyeq (Bool, y. imag, pyfloat (xi))
570
+ x = Complex (12 , 34 )
571
+ y = pycomplex (x)
572
+ @test pyisinstance (y, pybuiltins. complex)
573
+ @test pyeq (Bool, y. real, pyfloat (real (x)))
574
+ @test pyeq (Bool, y. imag, pyfloat (imag (x)))
575
+ @test pyeq (Bool, pycomplex (y), y)
576
+ @test pyeq (Bool, pycomplex (pyint (12 ), pyint (34 )), y)
577
+ end
578
+
579
+ @testitem " set" begin
580
+ y = pyset ()
581
+ yf = pyfrozenset ()
582
+ @test pyisinstance (y, pybuiltins. set)
583
+ @test pylen (y) == 0
584
+ @test pyisinstance (yf, pybuiltins. frozenset)
585
+ @test pylen (yf) == 0
586
+ @test pyeq (Bool, y, yf)
587
+ x = [1 ,2 ,3 ,2 ,1 ]
588
+ y = pyset (x)
589
+ yf = pyfrozenset (x)
590
+ @test pyisinstance (y, pybuiltins. set)
591
+ @test pylen (y) == 3
592
+ @test pycontains (y, 1 )
593
+ @test pycontains (y, 2 )
594
+ @test pycontains (y, 3 )
595
+ @test pyeq (Bool, pyset (y), y)
596
+ @test pyisinstance (yf, pybuiltins. frozenset)
597
+ @test pylen (yf) == 3
598
+ @test pycontains (yf, 1 )
599
+ @test pycontains (yf, 2 )
600
+ @test pycontains (yf, 3 )
601
+ @test pyeq (Bool, pyfrozenset (y), y)
602
+ @test pyeq (Bool, y, yf)
603
+ end
604
+
605
+ @testitem " slice" begin
606
+ x = pyslice (12 )
607
+ @test pyisinstance (x, pybuiltins. slice)
608
+ @test pyeq (Bool, x. start, pybuiltins. None)
609
+ @test pyeq (Bool, x. stop, 12 )
610
+ @test pyeq (Bool, x. step, pybuiltins. None)
611
+ x = pyslice (12 , 34 )
612
+ @test pyisinstance (x, pybuiltins. slice)
613
+ @test pyeq (Bool, x. start, 12 )
614
+ @test pyeq (Bool, x. stop, 34 )
615
+ @test pyeq (Bool, x. step, pybuiltins. None)
616
+ x = pyslice (12 , 34 , 56 )
617
+ @test pyisinstance (x, pybuiltins. slice)
618
+ @test pyeq (Bool, x. start, 12 )
619
+ @test pyeq (Bool, x. stop, 34 )
620
+ @test pyeq (Bool, x. step, 56 )
621
+ end
622
+
623
+ @testitem " range" begin
624
+ x = pyrange (123 )
625
+ @test pyisinstance (x, pybuiltins. range)
626
+ @test pyeq (Bool, x. start, 0 )
627
+ @test pyeq (Bool, x. stop, 123 )
628
+ @test pyeq (Bool, x. step, 1 )
629
+ x = pyrange (12 , 123 )
630
+ @test pyisinstance (x, pybuiltins. range)
631
+ @test pyeq (Bool, x. start, 12 )
632
+ @test pyeq (Bool, x. stop, 123 )
633
+ @test pyeq (Bool, x. step, 1 )
634
+ x = pyrange (12 , 123 , 3 )
635
+ @test pyisinstance (x, pybuiltins. range)
636
+ @test pyeq (Bool, x. start, 12 )
637
+ @test pyeq (Bool, x. stop, 123 )
638
+ @test pyeq (Bool, x. step, 3 )
639
+ end
640
+
641
+ @testitem " none" begin
642
+ # TODO
643
+ end
644
+
645
+ @testitem " type" begin
646
+ x = pytype (pyint ())
647
+ @test pyisinstance (x, pybuiltins. type)
648
+ @test pyis (x, pybuiltins. int)
649
+ x = pytype (pybuiltins. type)
650
+ @test pyisinstance (x, pybuiltins. type)
651
+ @test pyis (x, pybuiltins. type)
652
+ x = pytype (" Foo" , (), [" foo" => 1 , " bar" => 2 ])
653
+ @test pyisinstance (x, pybuiltins. type)
654
+ @test pyeq (Bool, x. __name__, " Foo" )
655
+ @test pyeq (Bool, x. foo, 1 )
656
+ @test pyeq (Bool, x. bar, 2 )
657
+ end
658
+
659
+ @testitem " fraction" begin
660
+ # TODO
661
+ end
662
+
663
+ @testitem " method" begin
664
+ # TODO
665
+ end
666
+
667
+ @testitem " datetime" begin
668
+ using Dates
669
+ dt = pyimport (" datetime" )
670
+ x1 = pydate (2001 , 2 , 3 )
671
+ @test pyisinstance (x1, dt. date)
672
+ @test pyeq (Bool, x1, dt. date (2001 , 2 , 3 ))
673
+ x2 = pydate (Date (2002 , 3 , 4 ))
674
+ @test pyisinstance (x2, dt. date)
675
+ @test pyeq (Bool, x2, dt. date (2002 , 3 , 4 ))
676
+ x3 = pytime (12 , 3 , 4 , 5 )
677
+ @test pyisinstance (x3, dt. time)
678
+ @test pyeq (Bool, x3, dt. time (12 , 3 , 4 , 5 ))
679
+ x4 = pytime (Time (23 , 4 , 5 , 0 , 6 ))
680
+ @test pyisinstance (x4, dt. time)
681
+ @test pyeq (Bool, x4, dt. time (23 , 4 , 5 , 6 ))
682
+ x5 = pydatetime (2001 , 2 , 3 , 4 , 5 , 6 , 7 )
683
+ @test pyisinstance (x5, dt. datetime)
684
+ @test pyeq (Bool, x5, dt. datetime (2001 , 2 , 3 , 4 , 5 , 6 , 7 ))
685
+ x6 = pydatetime (Date (2007 , 8 , 9 ))
686
+ @test pyisinstance (x6, dt. datetime)
687
+ @test pyeq (Bool, x6, dt. datetime (2007 , 8 , 9 ))
688
+ x7 = pydatetime (DateTime (2001 , 2 , 3 , 4 , 5 , 6 , 7 ))
689
+ @test pyisinstance (x7, dt. datetime)
690
+ @test pyeq (Bool, x7, dt. datetime (2001 , 2 , 3 , 4 , 5 , 6 , 7000 ))
691
+ end
692
+
693
+ @testitem " code" begin
694
+ # check for ArgumentError when inputs are mixed up
695
+ @test_throws ArgumentError pyeval (Main, " 1+1" )
696
+ @test_throws ArgumentError pyeval (Main, Main)
697
+ @test_throws ArgumentError pyeval (" 1+1" , " 1+1" )
698
+ @test_throws ArgumentError pyexec (Main, " 1+1" )
699
+ @test_throws ArgumentError pyexec (Main, Main)
700
+ @test_throws ArgumentError pyexec (" 1+1" , " 1+1" )
701
+ # basic code execution
702
+ m = Module (:test )
703
+ g = pydict ()
704
+ @test pyeq (Bool, pyeval (" 1+1" , m), 2 )
705
+ @test pyeq (Bool, pyeval (" 1+1" , g), 2 )
706
+ @test pyeq (Bool, pyeval (pystr (" 1+1" ), g), 2 )
707
+ @test pyexec (" 1+1" , m) === nothing
708
+ @test pyexec (" 1+1" , g) === nothing
709
+ @test pyexec (pystr (" 1+1" ), g) === nothing
710
+ # check the globals are what we think they are
711
+ @test pyis (pyeval (" globals()" , g), g)
712
+ mg = pyeval (" globals()" , m)
713
+ @test pyisinstance (mg, pybuiltins. dict)
714
+ # these automatically gain 1 item, __builtins__
715
+ @test length (g) == 1
716
+ @test length (mg) == 1
717
+ @test pycontains (g, " __builtins__" )
718
+ @test pycontains (mg, " __builtins__" )
719
+ # code should fail when x does not exist
720
+ @test_throws PyException pyeval (" x+1" , g)
721
+ @test_throws PyException pyeval (" x+1" , g)
722
+ # now set x and try again
723
+ g[" x" ] = 1
724
+ @test pyeq (Bool, pyeval (" x+1" , g), 2 )
725
+ # set x using pyexec this time
726
+ pyexec (" x=2" , g)
727
+ @test pyeq (Bool, g[" x" ], 2 )
728
+ @test pyeq (Bool, pyeval (" x+1" , g), 3 )
729
+ # now use locals
730
+ # check empty locals have no effect
731
+ l = pydict ()
732
+ @test pyeq (Bool, pyeval (" x+1" , g, l), 3 )
733
+ @test pyeq (Bool, pyeval (" x+1" , g, Dict ()), 3 )
734
+ # now set x locally
735
+ l[" x" ] = 3
736
+ @test pyeq (Bool, pyeval (" x+1" , g, l), 4 )
737
+ @test pyeq (Bool, pyeval (" x+1" , g, Dict ()), 3 )
738
+ @test pyeq (Bool, pyeval (" x+1" , g, Dict (" x" => 0 )), 1 )
739
+ @test pyeq (Bool, pyeval (" x+1" , g, (x= 1 ,)), 2 )
740
+ # check pyexec runs in local scope
741
+ pyexec (" x=4" , g, l)
742
+ @test pyeq (Bool, g[" x" ], 2 )
743
+ @test pyeq (Bool, l[" x" ], 4 )
744
+ # check global code runs in global scope
745
+ pyexec (" global y; y=x+1" , g, l)
746
+ @test pyeq (Bool, g[" y" ], 5 )
747
+ @test ! pycontains (l, " y" )
748
+ # check pyeval converts types correctly
749
+ @test pyeval (Int, " 1+1" , g) === 2
750
+ @test pyeval (Nothing, " None" , g) === nothing
751
+ end
752
+
753
+ @testitem " @pyconst" begin
754
+ f () = @pyconst " hello"
755
+ g () = @pyconst " hello"
756
+ @test f () === f ()
757
+ @test f () === f ()
758
+ @test g () === g ()
759
+ @test g () != = f ()
760
+ @test f () isa Py
761
+ @test pyeq (Bool, f (), " hello" )
762
+ end
763
+
764
+ @testitem " Base.jl" begin
765
+ @testset " broadcast" begin
766
+ # Py always broadcasts as a scalar
767
+ x = [1 2 ; 3 4 ] .+ Py (1 )
768
+ @test isequal (x, [Py (2 ) Py (3 ); Py (4 ) Py (5 )])
769
+ x = Py (" foo" ) .* [1 2 ; 3 4 ]
770
+ @test isequal (x, [Py (" foo" ) Py (" foofoo" ); Py (" foofoofoo" ) Py (" foofoofoofoo" )])
771
+ # this previously treated the list as a shape (2,) object
772
+ # but now tries to do `1 + [1, 2]` which properly fails
773
+ @test_throws PyException [1 2 ; 3 4 ] .+ pylist ([1 , 2 ])
774
+ end
775
+ end
776
+
777
+ @testitem " pywith" begin
778
+ @testset " no error" begin
779
+ tdir = pyimport (" tempfile" ). TemporaryDirectory ()
780
+ tname = pyconvert (String, tdir. name)
781
+ @test isdir (tname)
782
+ pywith (tdir) do name
783
+ @test pyconvert (String, name) == tname
784
+ end
785
+ @test ! isdir (tname)
786
+ end
787
+ @testset " error" begin
788
+ tdir = pyimport (" tempfile" ). TemporaryDirectory ()
789
+ tname = pyconvert (String, tdir. name)
790
+ @test isdir (tname)
791
+ @test_throws PyException pywith (name -> name. invalid_attr, tdir)
792
+ @test ! isdir (tname)
793
+ end
794
+ end
0 commit comments