3737import java .util .concurrent .locks .ReentrantLock ;
3838import java .util .function .Supplier ;
3939
40+ import org .graalvm .nativeimage .ImageInfo ;
4041import org .graalvm .options .OptionValues ;
4142
4243import com .oracle .graal .python .PythonLanguage ;
4546import com .oracle .graal .python .builtins .objects .cext .PythonNativeClass ;
4647import com .oracle .graal .python .builtins .objects .common .HashingStorage ;
4748import com .oracle .graal .python .builtins .objects .dict .PDict ;
49+ import com .oracle .graal .python .builtins .objects .list .PList ;
4850import com .oracle .graal .python .builtins .objects .module .PythonModule ;
51+ import com .oracle .graal .python .builtins .objects .str .PString ;
52+ import com .oracle .graal .python .nodes .SpecialAttributeNames ;
4953import com .oracle .graal .python .runtime .AsyncHandler .AsyncAction ;
5054import com .oracle .graal .python .runtime .exception .PException ;
5155import com .oracle .truffle .api .Assumption ;
@@ -234,17 +238,50 @@ public boolean isInitialized() {
234238
235239 public void initialize () {
236240 core .initialize (this );
237- setupRuntimeInformation ();
241+ setupRuntimeInformation (false );
238242 core .postInitialize ();
239243 }
240244
241245 public void patch (Env newEnv ) {
242246 setEnv (newEnv );
243- setupRuntimeInformation ();
247+ setupRuntimeInformation (true );
244248 core .postInitialize ();
245249 }
246250
247- private void setupRuntimeInformation () {
251+ /**
252+ * During pre-initialization, we're also loading code from the Python standard library. Since
253+ * some of those modules may be packages, they will have their __path__ attribute set to the
254+ * absolute path of the package on the build system. We use this function to patch the paths
255+ * during build time and after starting up from a pre-initialized context so they point to the
256+ * run-time package paths.
257+ */
258+ private void patchPackagePaths (String from , String to ) {
259+ for (Object v : sysModules .getDictStorage ().values ()) {
260+ if (v instanceof PythonModule ) {
261+ Object path = ((PythonModule ) v ).getAttribute (SpecialAttributeNames .__PATH__ );
262+ if (path instanceof PList ) {
263+ Object [] paths = ((PList ) path ).getSequenceStorage ().getCopyOfInternalArray ();
264+ for (int i = 0 ; i < paths .length ; i ++) {
265+ Object pathElement = paths [i ];
266+ String strPath ;
267+ if (pathElement instanceof PString ) {
268+ strPath = ((PString ) pathElement ).getValue ();
269+ } else if (pathElement instanceof String ) {
270+ strPath = (String ) pathElement ;
271+ } else {
272+ continue ;
273+ }
274+ if (strPath .startsWith (from )) {
275+ paths [i ] = strPath .replace (from , to );
276+ }
277+ }
278+ ((PythonModule ) v ).setAttribute (SpecialAttributeNames .__PATH__ , core .factory ().createList (paths ));
279+ }
280+ }
281+ }
282+ }
283+
284+ private void setupRuntimeInformation (boolean isPatching ) {
248285 PythonModule sysModule = core .lookupBuiltinModule ("sys" );
249286 sysModules = (PDict ) sysModule .getAttribute ("modules" );
250287
@@ -256,6 +293,18 @@ private void setupRuntimeInformation() {
256293
257294 sysModules .setItem (__MAIN__ , mainModule );
258295
296+ final String stdLibPlaceholder = "!stdLibHome!" ;
297+ final String stdLibHome = PythonCore .getStdlibHome (getEnv ());
298+ if (ImageInfo .inImageBuildtimeCode ()) {
299+ // Patch any pre-loaded packages' paths if we're running
300+ // pre-initialization
301+ patchPackagePaths (stdLibHome , stdLibPlaceholder );
302+ } else if (isPatching && ImageInfo .inImageRuntimeCode ()) {
303+ // Patch any pre-loaded packages' paths to the new stdlib home if
304+ // we're patching a pre-initialized context
305+ patchPackagePaths (stdLibPlaceholder , stdLibHome );
306+ }
307+
259308 currentException = null ;
260309 isInitialized = true ;
261310 }
0 commit comments