Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to install extra packages from extra indexes from jupyter-lite.json #158

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Carreau
Copy link

@Carreau Carreau commented Jan 10, 2025

This is in progress, but the idea is to be able to point to dev wheels on rtd or similar without having to make a custom pyidide distribution.

For example:

// jupyter-lite.json
{
  "jupyter-config-data": {
    "litePluginSettings": {
       "extraPackagesAndIndexes": [
          {
            "indexes": [
              "https://cors.carreau.workers.dev/scientific-python-nightly-wheels/simple",
              "https://pypi.org/simple"
            ],
            "package": "xarray"
          }
        ]
      }
    }
  }

Package could also be a simple url to a whl (I need to check how it works if it's a local URL), and indexes can be ommited.

WIP as I'm stuggling to have the typescript build process work.

…json<F48>

This is in progress, but the idea is to be able to point to dev wheels
on rtd or similar without having to make a custom pyidide distribution.

For example:

```
// jupyter-lite.json
{
  "jupyter-config-data": {
    "litePluginSettings": {
       "extraPackagesAndIndexes": [
          {
            "indexes": [
              "https://cors.carreau.workers.dev/scientific-python-nightly-wheels/simple",
              "https://pypi.org/simple"
            ],
            "package": "xarray"
          }
        ]
      }
    }
  }
```

Package could also be a simple url to a whl (I need to check how it
works if it's a local URL), and indexes can be ommited.

WIP as I'm stuggling to have the typescript build process work.
Copy link
Contributor

lite-badge 👈 Try it on ReadTheDocs

@Carreau
Copy link
Author

Carreau commented Jan 10, 2025

cc @agriyakhetarpal

@@ -394,5 +395,6 @@ export namespace PyodideKernel {
* The Jupyterlite content manager
*/
contentsManager: Contents.IManager;
extraPackagesAndIndexes: Array<{ package: string; indexes: string[] | null }>;
Copy link
Author

Choose a reason for hiding this comment

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

make that Array<{ package: string[]; ... }>;

/**
* List of extra url/wheel paths to load, and extra associated indexes urls (if not a wheel url)
*/
extraPackagesAndIndexes: Array<{ package: string; indexes: string[] | null }>;
Copy link
Author

Choose a reason for hiding this comment

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

same here.

}
} else {
console.info('no extra packages and indexes');
}
Copy link
Author

Choose a reason for hiding this comment

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

Maybe move that to initKernel.

Copy link
Author

Choose a reason for hiding this comment

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

And use piplite instead of micropip ?

}
} else {
console.info('no extra packages and indexes');
}

// get piplite early enough to impact pyodide-kernel dependencies
await this._pyodide.runPythonAsync(`
Copy link
Author

Choose a reason for hiding this comment

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

I think lower in initKernel the

    for (const pkgName of toLoad) {
      if (!preloaded.includes(pkgName)) {
        scriptLines.push(`await piplite.install('${pkgName}', keep_going=True)`);
      }
    }

Could be modified to be a single call to piplite.install(list), instead of repeated install calls.

@Carreau
Copy link
Author

Carreau commented Jan 10, 2025

https://cors.carreau.workers.dev/scientific-python-nightly-wheels/simple should not be used in production of course.

Comment on lines 94 to 98
if (indexes === null) {
installCmd = `import micropip\nawait micropip.install('${pkg}', keep_going=True)`;
} else {
installCmd = `import micropip\nawait micropip.install('${pkg}', index_urls=${JSON.stringify(indexes)}, keep_going=True)`;
}
Copy link
Author

Choose a reason for hiding this comment

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

In both cases, if pkg ends with whl, prepend baseurl,
and from testing, check the index urls do not end in /, otherwise it redirects and there are CORS issues.

@Carreau
Copy link
Author

Carreau commented Jan 10, 2025

and cc @gabalafou

@bollwyvl
Copy link
Contributor

Hmmmm, while I take no issue with the indexes (indeed, maybe a pipliteInstallDefaultOptions would allow for overriding all of the non-requirements micropip.install kwargs), we've been trying not to add new sources of run-time unpredictability before a user can make their first input and get useful feedback in the UI, which really should be all the kernel is on the hook for... but yeah, this is the browser, and ain't nothing easy.

As of 0.4.7, upstream's pyodide-lock.json is missing only comm, as ipython (and its 100k of vendored tests) is good to go. Pulling in a single wheel by URL might bring in many other, unpredictable wheels, which could (and it sounds like in this case, with nightly) expect to be different between two different site visits, and very possible breaking when installed against other things, and stirred together with dependencies from PyPI.

So my feeling would be: we could add hooks to allow another extension to load extra packages, run dynamic startup code, configure environment variables, write files on disk, make telemetry posts, etc. and all the other things that folk have asked for, but well after the core plumbing has loaded so that when errors happen, those messages appear, with attribution, somewhere.

@Carreau
Copy link
Author

Carreau commented Jan 11, 2025

Sure that would be fine with me, what Im really hopping is to allow most of the Python Ecosystem to be able to get interactive documentation without having to rebuild a pyodide distribution.

I'm fine if extra dependencies and breakage are up to the maintainers' using this configuration option.

I'm also happy to move this to another place in the launching process.

@Carreau
Copy link
Author

Carreau commented Jan 15, 2025

crosslinking to #60

@Carreau
Copy link
Author

Carreau commented Jan 17, 2025

Would you agree if this were change to only look at locally available wheels ?

Basically when using jupyter lite build --piplite-wheels; I don't think the users should need an extra install step;

For me including wheels in a jupyterlite build should make them immediately available to the end user, or it feels weird. I'm ok if wheels needs to be referred to in two locations.

@agriyakhetarpal
Copy link
Member

Basically when using jupyter lite build --piplite-wheels; I don't think the users should need an extra install step;

For me including wheels in a jupyterlite build should make them immediately available to the end user, or it feels weird. I'm ok if wheels needs to be referred to in two locations.

I would agree with this, as this is one of the points that I've made in sympy/live#26 and it would be nicer to see that micropip/piplite consider pre-installing only if they find all wheels locally (say, if I were to ship SymPy and all its dependencies – mpmath, together) and look at the local index at a priority over Pyodide.

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.

3 participants