2424from inspect import CO_COROUTINE
2525from itertools import product
2626from textwrap import dedent
27- from types import AsyncGeneratorType , FunctionType
27+ from types import AsyncGeneratorType , FunctionType , CellType
2828from operator import neg
2929from test import support
3030from test .support import (swap_attr , maybe_get_event_loop_policy )
@@ -94,7 +94,7 @@ def write(self, line):
9494 ('' , ValueError ),
9595 (' ' , ValueError ),
9696 (' \t \t ' , ValueError ),
97- # (str(br'\u0663\u0661\u0664 ','raw-unicode-escape'), 314), XXX RustPython
97+ (str (br'\u0663\u0661\u0664 ' ,'raw-unicode-escape' ), 314 ),
9898 (chr (0x200 ), ValueError ),
9999]
100100
@@ -116,7 +116,7 @@ def write(self, line):
116116 ('' , ValueError ),
117117 (' ' , ValueError ),
118118 (' \t \t ' , ValueError ),
119- # (str(br'\u0663\u0661\u0664 ','raw-unicode-escape'), 314), XXX RustPython
119+ (str (br'\u0663\u0661\u0664 ' ,'raw-unicode-escape' ), 314 ),
120120 (chr (0x200 ), ValueError ),
121121]
122122
@@ -161,7 +161,7 @@ def test_import(self):
161161 __import__ ('string' )
162162 __import__ (name = 'sys' )
163163 __import__ (name = 'time' , level = 0 )
164- self .assertRaises (ImportError , __import__ , 'spamspam' )
164+ self .assertRaises (ModuleNotFoundError , __import__ , 'spamspam' )
165165 self .assertRaises (TypeError , __import__ , 1 , 2 , 3 , 4 )
166166 self .assertRaises (ValueError , __import__ , '' )
167167 self .assertRaises (TypeError , __import__ , 'sys' , name = 'sys' )
@@ -403,6 +403,10 @@ def test_compile_top_level_await_no_coro(self):
403403
404404 # TODO: RUSTPYTHON
405405 @unittest .expectedFailure
406+ @unittest .skipIf (
407+ support .is_emscripten or support .is_wasi ,
408+ "socket.accept is broken"
409+ )
406410 def test_compile_top_level_await (self ):
407411 """Test whether code some top level await can be compiled.
408412
@@ -523,6 +527,9 @@ def test_delattr(self):
523527 sys .spam = 1
524528 delattr (sys , 'spam' )
525529 self .assertRaises (TypeError , delattr )
530+ self .assertRaises (TypeError , delattr , sys )
531+ msg = r"^attribute name must be string, not 'int'$"
532+ self .assertRaisesRegex (TypeError , msg , delattr , sys , 1 )
526533
527534 # TODO: RUSTPYTHON
528535 @unittest .expectedFailure
@@ -748,11 +755,7 @@ def test_exec_globals(self):
748755 self .assertRaises (TypeError ,
749756 exec , code , {'__builtins__' : 123 })
750757
751- # no __build_class__ function
752- code = compile ("class A: pass" , "" , "exec" )
753- self .assertRaisesRegex (NameError , "__build_class__ not found" ,
754- exec , code , {'__builtins__' : {}})
755-
758+ def test_exec_globals_frozen (self ):
756759 class frozendict_error (Exception ):
757760 pass
758761
@@ -769,12 +772,51 @@ def __setitem__(self, key, value):
769772 self .assertRaises (frozendict_error ,
770773 exec , code , {'__builtins__' : frozen_builtins })
771774
775+ # no __build_class__ function
776+ code = compile ("class A: pass" , "" , "exec" )
777+ self .assertRaisesRegex (NameError , "__build_class__ not found" ,
778+ exec , code , {'__builtins__' : {}})
779+ # __build_class__ in a custom __builtins__
780+ exec (code , {'__builtins__' : frozen_builtins })
781+ self .assertRaisesRegex (NameError , "__build_class__ not found" ,
782+ exec , code , {'__builtins__' : frozendict ()})
783+
772784 # read-only globals
773785 namespace = frozendict ({})
774786 code = compile ("x=1" , "test" , "exec" )
775787 self .assertRaises (frozendict_error ,
776788 exec , code , namespace )
777789
790+ def test_exec_globals_error_on_get (self ):
791+ # custom `globals` or `builtins` can raise errors on item access
792+ class setonlyerror (Exception ):
793+ pass
794+
795+ class setonlydict (dict ):
796+ def __getitem__ (self , key ):
797+ raise setonlyerror
798+
799+ # globals' `__getitem__` raises
800+ code = compile ("globalname" , "test" , "exec" )
801+ self .assertRaises (setonlyerror ,
802+ exec , code , setonlydict ({'globalname' : 1 }))
803+
804+ # builtins' `__getitem__` raises
805+ code = compile ("superglobal" , "test" , "exec" )
806+ self .assertRaises (setonlyerror , exec , code ,
807+ {'__builtins__' : setonlydict ({'superglobal' : 1 })})
808+
809+ def test_exec_globals_dict_subclass (self ):
810+ class customdict (dict ): # this one should not do anything fancy
811+ pass
812+
813+ code = compile ("superglobal" , "test" , "exec" )
814+ # works correctly
815+ exec (code , {'__builtins__' : customdict ({'superglobal' : 1 })})
816+ # custom builtins dict subclass is missing key
817+ self .assertRaisesRegex (NameError , "name 'superglobal' is not defined" ,
818+ exec , code , {'__builtins__' : customdict ()})
819+
778820 def test_exec_redirected (self ):
779821 savestdout = sys .stdout
780822 sys .stdout = None # Whatever that cannot flush()
@@ -786,6 +828,84 @@ def test_exec_redirected(self):
786828 finally :
787829 sys .stdout = savestdout
788830
831+ def test_exec_closure (self ):
832+ def function_without_closures ():
833+ return 3 * 5
834+
835+ result = 0
836+ def make_closure_functions ():
837+ a = 2
838+ b = 3
839+ c = 5
840+ def three_freevars ():
841+ nonlocal result
842+ nonlocal a
843+ nonlocal b
844+ result = a * b
845+ def four_freevars ():
846+ nonlocal result
847+ nonlocal a
848+ nonlocal b
849+ nonlocal c
850+ result = a * b * c
851+ return three_freevars , four_freevars
852+ three_freevars , four_freevars = make_closure_functions ()
853+
854+ # "smoke" test
855+ result = 0
856+ exec (three_freevars .__code__ ,
857+ three_freevars .__globals__ ,
858+ closure = three_freevars .__closure__ )
859+ self .assertEqual (result , 6 )
860+
861+ # should also work with a manually created closure
862+ result = 0
863+ my_closure = (CellType (35 ), CellType (72 ), three_freevars .__closure__ [2 ])
864+ exec (three_freevars .__code__ ,
865+ three_freevars .__globals__ ,
866+ closure = my_closure )
867+ self .assertEqual (result , 2520 )
868+
869+ # should fail: closure isn't allowed
870+ # for functions without free vars
871+ self .assertRaises (TypeError ,
872+ exec ,
873+ function_without_closures .__code__ ,
874+ function_without_closures .__globals__ ,
875+ closure = my_closure )
876+
877+ # should fail: closure required but wasn't specified
878+ self .assertRaises (TypeError ,
879+ exec ,
880+ three_freevars .__code__ ,
881+ three_freevars .__globals__ ,
882+ closure = None )
883+
884+ # should fail: closure of wrong length
885+ self .assertRaises (TypeError ,
886+ exec ,
887+ three_freevars .__code__ ,
888+ three_freevars .__globals__ ,
889+ closure = four_freevars .__closure__ )
890+
891+ # should fail: closure using a list instead of a tuple
892+ my_closure = list (my_closure )
893+ self .assertRaises (TypeError ,
894+ exec ,
895+ three_freevars .__code__ ,
896+ three_freevars .__globals__ ,
897+ closure = my_closure )
898+
899+ # should fail: closure tuple with one non-cell-var
900+ my_closure [0 ] = int
901+ my_closure = tuple (my_closure )
902+ self .assertRaises (TypeError ,
903+ exec ,
904+ three_freevars .__code__ ,
905+ three_freevars .__globals__ ,
906+ closure = my_closure )
907+
908+
789909 def test_filter (self ):
790910 self .assertEqual (list (filter (lambda c : 'a' <= c <= 'z' , 'Hello World' )), list ('elloorld' ))
791911 self .assertEqual (list (filter (None , [1 , 'hello' , [], [3 ], '' , None , 9 , 0 ])), [1 , 'hello' , [3 ], 9 ])
@@ -819,17 +939,21 @@ def test_filter_pickle(self):
819939
820940 def test_getattr (self ):
821941 self .assertTrue (getattr (sys , 'stdout' ) is sys .stdout )
822- self .assertRaises (TypeError , getattr , sys , 1 )
823- self .assertRaises (TypeError , getattr , sys , 1 , "foo" )
824942 self .assertRaises (TypeError , getattr )
943+ self .assertRaises (TypeError , getattr , sys )
944+ msg = r"^attribute name must be string, not 'int'$"
945+ self .assertRaisesRegex (TypeError , msg , getattr , sys , 1 )
946+ self .assertRaisesRegex (TypeError , msg , getattr , sys , 1 , 'spam' )
825947 self .assertRaises (AttributeError , getattr , sys , chr (sys .maxunicode ))
826948 # unicode surrogates are not encodable to the default encoding (utf8)
827949 self .assertRaises (AttributeError , getattr , 1 , "\uDAD1 \uD51E " )
828950
829951 def test_hasattr (self ):
830952 self .assertTrue (hasattr (sys , 'stdout' ))
831- self .assertRaises (TypeError , hasattr , sys , 1 )
832953 self .assertRaises (TypeError , hasattr )
954+ self .assertRaises (TypeError , hasattr , sys )
955+ msg = r"^attribute name must be string, not 'int'$"
956+ self .assertRaisesRegex (TypeError , msg , hasattr , sys , 1 )
833957 self .assertEqual (False , hasattr (sys , chr (sys .maxunicode )))
834958
835959 # Check that hasattr propagates all exceptions outside of
@@ -1216,7 +1340,7 @@ def test_open_default_encoding(self):
12161340 del os .environ [key ]
12171341
12181342 self .write_testfile ()
1219- current_locale_encoding = locale .getpreferredencoding ( False )
1343+ current_locale_encoding = locale .getencoding ( )
12201344 with warnings .catch_warnings ():
12211345 warnings .simplefilter ("ignore" , EncodingWarning )
12221346 fp = open (TESTFN , 'w' )
@@ -1226,7 +1350,7 @@ def test_open_default_encoding(self):
12261350 os .environ .clear ()
12271351 os .environ .update (old_environ )
12281352
1229- @unittest . skipIf ( sys . platform == 'win32' , 'TODO: RUSTPYTHON Windows' )
1353+ @support . requires_subprocess ( )
12301354 def test_open_non_inheritable (self ):
12311355 fileobj = open (__file__ , encoding = "utf-8" )
12321356 with fileobj :
@@ -1478,8 +1602,11 @@ def test_bug_27936(self):
14781602 def test_setattr (self ):
14791603 setattr (sys , 'spam' , 1 )
14801604 self .assertEqual (sys .spam , 1 )
1481- self .assertRaises (TypeError , setattr , sys , 1 , 'spam' )
14821605 self .assertRaises (TypeError , setattr )
1606+ self .assertRaises (TypeError , setattr , sys )
1607+ self .assertRaises (TypeError , setattr , sys , 'spam' )
1608+ msg = r"^attribute name must be string, not 'int'$"
1609+ self .assertRaisesRegex (TypeError , msg , setattr , sys , 1 , 'spam' )
14831610
14841611 # test_str(): see test_unicode.py and test_bytes.py for str() tests.
14851612
@@ -1998,10 +2125,6 @@ def test_envar_ignored_when_hook_is_set(self):
19982125 breakpoint ()
19992126 mock .assert_not_called ()
20002127
2001- def test_runtime_error_when_hook_is_lost (self ):
2002- del sys .breakpointhook
2003- with self .assertRaises (RuntimeError ):
2004- breakpoint ()
20052128
20062129@unittest .skipUnless (pty , "the pty and signal modules must be available" )
20072130class PtyTests (unittest .TestCase ):
@@ -2279,10 +2402,8 @@ def test_type_name(self):
22792402 self .assertEqual (A .__module__ , __name__ )
22802403 with self .assertRaises (ValueError ):
22812404 type ('A\x00 B' , (), {})
2282- # TODO: RUSTPYTHON (https://github.com/RustPython/RustPython/issues/935)
2283- with self .assertRaises (AssertionError ):
2284- with self .assertRaises (ValueError ):
2285- type ('A\udcdc B' , (), {})
2405+ with self .assertRaises (UnicodeEncodeError ):
2406+ type ('A\udcdc B' , (), {})
22862407 with self .assertRaises (TypeError ):
22872408 type (b'A' , (), {})
22882409
@@ -2298,13 +2419,9 @@ def test_type_name(self):
22982419 with self .assertRaises (ValueError ):
22992420 A .__name__ = 'A\x00 B'
23002421 self .assertEqual (A .__name__ , 'C' )
2301- # TODO: RUSTPYTHON (https://github.com/RustPython/RustPython/issues/935)
2302- with self .assertRaises (AssertionError ):
2303- with self .assertRaises (ValueError ):
2304- A .__name__ = 'A\udcdc B'
2305- self .assertEqual (A .__name__ , 'C' )
2306- # TODO: RUSTPYTHON: the previous __name__ set should fail but doesn't: reset it
2307- A .__name__ = 'C'
2422+ with self .assertRaises (UnicodeEncodeError ):
2423+ A .__name__ = 'A\udcdc B'
2424+ self .assertEqual (A .__name__ , 'C' )
23082425 with self .assertRaises (TypeError ):
23092426 A .__name__ = b'A'
23102427 self .assertEqual (A .__name__ , 'C' )
0 commit comments