Skip to content

Add lockfileContents option to loadPyodide()#5764

Merged
hoodmane merged 19 commits intopyodide:mainfrom
hoodmane:lockfile-contents
Jul 31, 2025
Merged

Add lockfileContents option to loadPyodide()#5764
hoodmane merged 19 commits intopyodide:mainfrom
hoodmane:lockfile-contents

Conversation

@hoodmane
Copy link
Copy Markdown
Member

@hoodmane hoodmane commented Jul 14, 2025

And also packageBaseUrl option:

  1. If lockfileContents is provided and not packageBaseUrl, then in the browser attempting to load a lock entry with a relative path fails.
  2. In Node, packageBaseUrl is used in place of jsdelivr as the cdn url if passed.

See discussion in #5736.

  • Add a CHANGELOG entry
  • Add / update tests
  • Add new / update outdated documentation

@hoodmane hoodmane force-pushed the lockfile-contents branch from 02d380a to 7de7090 Compare July 14, 2025 13:42
And also `packageBaseUrl` option:
1. If `lockfileContents` is provided and not `packageBaseUrl`, then
   in the browser attempting to load a lock entry with a relative path
   fails.
2. In Node, `packageBaseUrl` is used in place of jsdelivr as the cdn
   url if passed.
@hoodmane hoodmane force-pushed the lockfile-contents branch from 9613447 to df050ea Compare July 14, 2025 13:45
@ryanking13 ryanking13 self-requested a review July 15, 2025 09:41
Copy link
Copy Markdown
Member

@ryanking13 ryanking13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Ideally, I would like to deprecate LockFileURL instead of having two different options doing the same thing. WDYT?

@hoodmane
Copy link
Copy Markdown
Member Author

Thanks for the review @ryanking13!

@hoodmane
Copy link
Copy Markdown
Member Author

I would like to deprecate LockFileURL instead of having two different options doing the same thing.

I don't think it's worth the churn to deprecate this since it causes no extra maintenance burden.

@WebReflection
Copy link
Copy Markdown
Contributor

WebReflection commented Jul 22, 2025

If lockfileContents is provided and not packageBaseUrl, then in the browser attempting to load a lock entry with a relative path fails.

does it mean that with content created via micropip.freeze() we still need to create an object URL to pass as packageBaseURL ?

I am trying to implement the dance that must work on any pyodide version and this detail seems to be very important to understand properly ... I am not sure micropip.freeze() does, or will, provide relative paths internally so it'd be great to understand if our JSON Blob artifact is needed at all with lockfileContents, thank you!

@ryanking13
Copy link
Copy Markdown
Member

@WebReflection

Here are some changes related to the lockfile.

  • Before 0.28.0: We assumed that the Pyodide runtime and packages are always served from the same place. So if the lockfile has relative URLs in it, it always loads the packages from the indexURL + filename.

  • Pyodide 0.28.0 (micropip 0.10.0): This assumption has changed and we now allow loading Pyodide runtime and packages in different places. Therefore, we changed the behavior related to lockFileURL parameter. If the lockfile has relative URLs in it, and if indexURL is provided, the pacakges are loaded from parent(lockFileURL) + filename.

  • Pyodide 0.28.1 (micropip 0.10.1) (to be)

    • The behavior of micropip.freeze() has been changed. micropip.freeze() will now output the lockfile with absolute URLs. So if you generate a lockfile using micropip.freeze() and serve it through indexedDB, it will load the packages correctly (which was an error in Pyodide 0.28).
    • If the lockfile contains relative URLs, it will still load the packages from parent(lockFileURL) + filename.
    • This PR adds lockFileContents and packageBaseURL.
      • If lockFileContents is provided without packageBaseURL and if the lockfile has no absolute URLs, we fail (we don't know where to load packages)
      • If packageBaseURL is provided, then we load from packageBaseURL + filename.

So...

does it mean that with content created via micropip.freeze() we still need to create an object URL to pass as packageBaseURL ?

In Pyodide 0.28.1, no. micropip.freeze() will output absolute URLs for all the packages in the lockfile, so packageBaseURL will not be necessary.

I am not sure micropip.freeze() does, or will, provide relative paths internally so it'd be great to understand if our JSON Blob artifact is needed at all with lockfileContents, thank you!

micropip.freeze() will generate absolute URLs by default from 0.10.1 (Pyodide 0.28.1). And you'll be able to provide it directly to lockfileContents. Otherwise, creating the Blob URL and passing it to lockfileURL will also work.

@WebReflection
Copy link
Copy Markdown
Contributor

@ryanking13 crystal clear, thank you!

@hoodmane hoodmane added this to the 0.28.1 milestone Jul 29, 2025
@hoodmane hoodmane force-pushed the lockfile-contents branch from eee6723 to f124a78 Compare July 29, 2025 10:13
Copy link
Copy Markdown
Member

@ryanking13 ryanking13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. There is a test failure, otherwise looks good to me.

Comment on lines +265 to +267
options_.cdnUrl =
options_.packageBaseUrl ??
`https://cdn.jsdelivr.net/pyodide/v${version}/full/`;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it always be https://cdn.jsdelivr.net/pyodide/v${version}/full/, as we use this only for a fallback?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure. But:

  • the caching system only works if file_name is relative, otherwise we will try to download the url every time and won't do any caching
  • if the user has a custom lock file, then any additional packages definitely won't be available on jsdelivr

So if they are to have any chance of using the caching mechanism with their own lock file, they need to be able to adjust the cdnURL.

const emscriptenSettings = createSettings(config);
const API = emscriptenSettings.API;
API.lockFilePromise = loadLockFile(config.lockFileURL);
API.lockFilePromise = Promise.resolve(options_.lockFileContents);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit confusing to have all of config, option, and option_ here. But I guess I'll be able clean it up in #5746.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well options_ and options are identical things just with different types.

@hoodmane
Copy link
Copy Markdown
Member Author

The failing test doesn't actually pass for me on the main branch...

@hoodmane
Copy link
Copy Markdown
Member Author

Maybe my micropip is out of date...

@hoodmane hoodmane merged commit 427d2b1 into pyodide:main Jul 31, 2025
38 of 40 checks passed
@hoodmane hoodmane deleted the lockfile-contents branch July 31, 2025 10:01
hoodmane added a commit to hoodmane/pyodide that referenced this pull request Jul 31, 2025
And also `packageBaseUrl` option:
1. If `lockfileContents` is provided and not `packageBaseUrl`, then in the browser attempting to
   load a lock entry with a relative path fails.
2. In Node, `packageBaseUrl` is used in place of jsdelivr as the cdn url if passed.

See discussion in pyodide#5736.
@ryanking13
Copy link
Copy Markdown
Member

Thanks!

hoodmane added a commit to hoodmane/pyodide that referenced this pull request Jul 31, 2025
And also `packageBaseUrl` option:
1. If `lockfileContents` is provided and not `packageBaseUrl`, then in the browser attempting to
   load a lock entry with a relative path fails.
2. In Node, `packageBaseUrl` is used in place of jsdelivr as the cdn url if passed.

See discussion in pyodide#5736.
@WebReflection
Copy link
Copy Markdown
Contributor

any eta for a new release? we're going on vacation and we'd love to be able to bring in latest Pyodide before doing that, so that anyone playing around our project could benefit from its latest/greatest, thank you!

hoodmane added a commit to hoodmane/pyodide that referenced this pull request Aug 4, 2025
And also `packageBaseUrl` option:
1. If `lockfileContents` is provided and not `packageBaseUrl`, then in the browser attempting to
   load a lock entry with a relative path fails.
2. In Node, `packageBaseUrl` is used in place of jsdelivr as the cdn url if passed.

See discussion in pyodide#5736.
hoodmane added a commit to hoodmane/pyodide that referenced this pull request Aug 4, 2025
And also `packageBaseUrl` option:
1. If `lockfileContents` is provided and not `packageBaseUrl`, then in the browser attempting to
   load a lock entry with a relative path fails.
2. In Node, `packageBaseUrl` is used in place of jsdelivr as the cdn url if passed.

See discussion in pyodide#5736.
@ryanking13 ryanking13 mentioned this pull request Aug 7, 2025
2 tasks
Drranny pushed a commit to Drranny/pyodide that referenced this pull request Feb 15, 2026
And also `packageBaseUrl` option:
1. If `lockfileContents` is provided and not `packageBaseUrl`, then in the browser attempting to
   load a lock entry with a relative path fails.
2. In Node, `packageBaseUrl` is used in place of jsdelivr as the cdn url if passed.

See discussion in pyodide#5736.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants