@@ -509,7 +509,7 @@ def test_not_shareable(self):
509
509
interp .exec ('print(spam)' )
510
510
511
511
512
- class TestInterpreterExecSync (TestBase ):
512
+ class TestInterpreterExec (TestBase ):
513
513
514
514
def test_success (self ):
515
515
interp = interpreters .create ()
@@ -662,32 +662,223 @@ def task():
662
662
# Interpreter.exec() behavior.
663
663
664
664
665
- class TestInterpreterRun (TestBase ):
666
-
667
- def test_success (self ):
668
- interp = interpreters .create ()
669
- script , file = _captured_script ('print("it worked!", end="")' )
670
- with file :
671
- t = interp .run (script )
672
- t .join ()
673
- out = file .read ()
674
-
675
- self .assertEqual (out , 'it worked!' )
676
-
677
- def test_failure (self ):
678
- caught = False
679
- def excepthook (args ):
680
- nonlocal caught
681
- caught = True
682
- threading .excepthook = excepthook
683
- try :
684
- interp = interpreters .create ()
685
- t = interp .run ('raise Exception' )
686
- t .join ()
665
+ def call_func_noop ():
666
+ pass
667
+
668
+
669
+ def call_func_return_shareable ():
670
+ return (1 , None )
671
+
672
+
673
+ def call_func_return_not_shareable ():
674
+ return [1 , 2 , 3 ]
675
+
676
+
677
+ def call_func_failure ():
678
+ raise Exception ('spam!' )
679
+
680
+
681
+ def call_func_ident (value ):
682
+ return value
683
+
684
+
685
+ def get_call_func_closure (value ):
686
+ def call_func_closure ():
687
+ return value
688
+ return call_func_closure
689
+
690
+
691
+ class Spam :
692
+
693
+ @staticmethod
694
+ def noop ():
695
+ pass
696
+
697
+ @classmethod
698
+ def from_values (cls , * values ):
699
+ return cls (values )
700
+
701
+ def __init__ (self , value ):
702
+ self .value = value
703
+
704
+ def __call__ (self , * args , ** kwargs ):
705
+ return (self .value , args , kwargs )
706
+
707
+ def __eq__ (self , other ):
708
+ if not isinstance (other , Spam ):
709
+ return NotImplemented
710
+ return self .value == other .value
711
+
712
+ def run (self , * args , ** kwargs ):
713
+ return (self .value , args , kwargs )
714
+
715
+
716
+ def call_func_complex (op , / , value = None , * args , exc = None , ** kwargs ):
717
+ if exc is not None :
718
+ raise exc
719
+ if op == '' :
720
+ raise ValueError ('missing op' )
721
+ elif op == 'ident' :
722
+ if args or kwargs :
723
+ raise Exception ((args , kwargs ))
724
+ return value
725
+ elif op == 'full-ident' :
726
+ return (value , args , kwargs )
727
+ elif op == 'globals' :
728
+ if value is not None or args or kwargs :
729
+ raise Exception ((value , args , kwargs ))
730
+ return __name__
731
+ elif op == 'interpid' :
732
+ if value is not None or args or kwargs :
733
+ raise Exception ((value , args , kwargs ))
734
+ return interpreters .get_current ().id
735
+ elif op == 'closure' :
736
+ if args or kwargs :
737
+ raise Exception ((args , kwargs ))
738
+ return get_call_func_closure (value )
739
+ elif op == 'custom' :
740
+ if args or kwargs :
741
+ raise Exception ((args , kwargs ))
742
+ return Spam (value )
743
+ elif op == 'custom-inner' :
744
+ if args or kwargs :
745
+ raise Exception ((args , kwargs ))
746
+ class Eggs (Spam ):
747
+ pass
748
+ return Eggs (value )
749
+ else if not isinstance (op , str ):
750
+ raise TypeError (op )
751
+ else :
752
+ raise NotImplementedError (op )
753
+
754
+
755
+ class TestInterpreterCall (TestBase ):
756
+
757
+ # signature
758
+ # - blank
759
+ # - args
760
+ # - kwargs
761
+ # - args, kwargs
762
+ # return
763
+ # - nothing (None)
764
+ # - simple
765
+ # - closure
766
+ # - custom
767
+ # ops:
768
+ # - do nothing
769
+ # - fail
770
+ # - echo
771
+ # - do complex, relative to interpreter
772
+ # scope
773
+ # - global func
774
+ # - local closure
775
+ # - returned closure
776
+ # - callable type instance
777
+ # - type
778
+ # - classmethod
779
+ # - staticmethod
780
+ # - instance method
781
+ # exception
782
+ # - builtin
783
+ # - custom
784
+ # - preserves info (e.g. SyntaxError)
785
+ # - matching error display
786
+
787
+ def test_call (self ):
788
+ interp = interpreters .create ()
789
+
790
+ for i , ((callable , args , kwargs ), expected ) in enumerate ([
791
+ ((call_func_noop , (), {}),
792
+ None ),
793
+ ((call_func_return_shareable , (), {}),
794
+ (1 , None )),
795
+ ((call_func_return_not_shareable , (), {}),
796
+ [1 , 2 , 3 ]),
797
+ ((call_func_ident , ('spamspamspam' ,), {}),
798
+ 'spamspamspam' ),
799
+ ((get_call_func_closure , (42 ,), {}),
800
+ ...),
801
+ ((get_call_func_closure (42 ), (), {}),
802
+ 42 ),
803
+ ((Spam .noop , (), {}),
804
+ None ),
805
+ ((Spam .from_values , (), {}),
806
+ None ),
807
+ ((Spam .from_values , (1 , 2 , 3 ), {}),
808
+ Spam ((1 , 2 , 3 )),
809
+ ((Spam , ('???' ), {}),
810
+ Spam ('???' )),
811
+ ((Spam (101 ), (), {}),
812
+ 101 ),
813
+ ((Spam (10101 ).run , (), {}),
814
+ 10101 ),
815
+ ((call_func_complex , ('ident' , 'spam' ), {}),
816
+ 'spam' ),
817
+ ((call_func_complex , ('full-ident' , 'spam' ), {}),
818
+ ('spam' , (), {})),
819
+ ((call_func_complex , ('full-ident' , 'spam' , 'ham' ), {'eggs' : '!!!' }),
820
+ ('spam' , ('ham' ,), {'eggs' : '!!!' })),
821
+ ((call_func_complex , ('globals' ,), {}),
822
+ 'test.test_interpreters.test_api' ),
823
+ ((call_func_complex , ('interpid' ,), {}),
824
+ interp .id ),
825
+ ((call_func_complex , ('closure' ,), {'value' : '~~~' }),
826
+ '~~~' ),
827
+ ((call_func_complex , ('custom' , 'spam!' ), {}),
828
+ Spam ('spam!' )),
829
+ ((call_func_complex , ('custom-inner' , 'eggs!' ), {}),
830
+ ...),
831
+ ]):
832
+ with self .subTest (f'success case #{ i + 1 } ' ):
833
+ res = interp .call (callable , args , kwargs )
834
+ self .assertEqual (res , expected )
835
+
836
+ for i , ((callable , args , kwargs ), expected ) in enumerate ([
837
+ ((call_func_failure , (), {}),
838
+ Exception ),
839
+ ((call_func_complex , ('???' ,), {exc = ValueError ('spam' )}),
840
+ ValueError ),
841
+ ]):
842
+ with self .subTest (f'failure case #{ i + 1 } ' ):
843
+ with self .assertRaises (expected ):
844
+ interp .call (callable , args , kwargs )
845
+
846
+ def test_call_in_thread (self ):
847
+ interp = interpreters .create ()
848
+
849
+ for i , (callable , args , kwargs ) in enumerate ([
850
+ (call_func_noop , (), {}),
851
+ (call_func_return_shareable , (), {}),
852
+ (call_func_return_not_shareable , (), {}),
853
+ (call_func_ident , ('spamspamspam' ,), {}),
854
+ (get_call_func_closure , (42 ,), {}),
855
+ (get_call_func_closure (42 ), (), {}),
856
+ (Spam .noop , (), {}),
857
+ (Spam .from_values , (), {}),
858
+ (Spam .from_values , (1 , 2 , 3 ), {}),
859
+ (Spam , ('???' ), {}),
860
+ (Spam (101 ), (), {}),
861
+ (Spam (10101 ).run , (), {}),
862
+ (call_func_complex , ('ident' , 'spam' ), {}),
863
+ (call_func_complex , ('full-ident' , 'spam' ), {}),
864
+ (call_func_complex , ('full-ident' , 'spam' , 'ham' ), {'eggs' : '!!!' }),
865
+ (call_func_complex , ('globals' ,), {}),
866
+ (call_func_complex , ('interpid' ,), {}),
867
+ (call_func_complex , ('closure' ,), {'value' : '~~~' }),
868
+ (call_func_complex , ('custom' , 'spam!' ), {}),
869
+ (call_func_complex , ('custom-inner' , 'eggs!' ), {}),
870
+ ]):
871
+ with self .subTest (f'success case #{ i + 1 } ' ):
872
+ t = interp .call_in_thread (callable , args , kwargs )
873
+ t .join ()
687
874
688
- self .assertTrue (caught )
689
- except BaseException :
690
- threading .excepthook = threading .__excepthook__
875
+ for i , (callable , args , kwargs ) in enumerate ([
876
+ (call_func_failure , (), {}),
877
+ (call_func_complex , ('???' ,), {exc = ValueError ('spam' )}),
878
+ ]):
879
+ with self .subTest (f'failure case #{ i + 1 } ' ):
880
+ t = interp .call_in_thread (callable , args , kwargs )
881
+ t .join ()
691
882
692
883
693
884
class TestIsShareable (TestBase ):
0 commit comments