44import runpy
55from dataclasses import dataclass
66from typing import Optional
7+ from contextlib import contextmanager
78
89# local imports
910from constants import *
@@ -86,6 +87,35 @@ def debugModule(name):
8687 print ("Origin:" , spec .origin )
8788 print ("Loader:" , type (spec .loader ).__name__ )
8889
90+ import sys
91+ import os
92+ import contextlib
93+
94+ @contextlib .contextmanager
95+ def freshModules ():
96+ original_modules = sys .modules .copy ()
97+ stdlib_path = os .path .dirname (os .__file__ )
98+ whitelist = ('sys' , 'os' , 'contextlib' , 'runpy' , 'wypp' , '__main__' , '__wypp__' )
99+ def is_core (name , module ):
100+ if name in sys .stdlib_module_names or name in sys .builtin_module_names :
101+ return True
102+ module_file = getattr (module , '__file__' , None )
103+ if module_file and module_file .startswith (stdlib_path ):
104+ return True
105+ if name in whitelist :
106+ return True
107+ return False
108+
109+ try :
110+ for mod_name in list (sys .modules .keys ()):
111+ if not is_core (mod_name , sys .modules [mod_name ]):
112+ del sys .modules [mod_name ]
113+ yield
114+ finally :
115+ # 4. Restore everything
116+ sys .modules .clear ()
117+ sys .modules .update (original_modules )
118+
89119def runCode (fileToRun , globals , doTypecheck = True , extraDirs = None ) -> dict :
90120 if not extraDirs :
91121 extraDirs = []
@@ -94,7 +124,8 @@ def runCode(fileToRun, globals, doTypecheck=True, extraDirs=None) -> dict:
94124 sys .dont_write_bytecode = True
95125 if DEBUG :
96126 debugModule (modName )
97- res = runpy .run_module (modName , init_globals = globals , run_name = '__wypp__' , alter_sys = False )
127+ with freshModules ():
128+ res = runpy .run_module (modName , init_globals = globals , run_name = '__wypp__' , alter_sys = False )
98129 return res
99130
100131def runStudentCode (fileToRun , globals , onlyCheckRunnable , doTypecheck = True , extraDirs = None ) -> dict :
0 commit comments