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

Make pyodide venv more compatible with standard virtualenv args + add tests #117

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

Conversation

agriyakhetarpal
Copy link
Member

@agriyakhetarpal agriyakhetarpal commented Mar 8, 2025

Description

This PR stems from #115 (comment) where I noticed that it is currently not possible to extend virtualenv args in order to override the virtual environment creation behaviour.

I've added a subset of the arguments listed at https://virtualenv.pypa.io/en/stable/cli_interface.html. The environment variables are already supported as we don't have much to deal with them, this PR enables passing those arguments. A warning is raised on currently and to-be-always unsupported arguments. For example, --no-pip does not make sense as we need pip to be able to install packages, and thus we always need a seeded environment.

It might be possible to add support for the --copies and --symlink-app-data flags as well, but I haven't looked into them as they seem to be a bit more complex than I expected. Also, I'm not sure if anyone will need the extra complexity.

Further steps that can be taken in the medium term are to create a virtualenv-pyodide plugin and register it with virtualenv so that we can remove venv.py out of pyodide-build altogether and maintain it separately. I would be happy to work on this, but will probably do it in a separate repository and shift it here.

Possible use cases:

  • allow installing a custom version of pip when creating the virtual environment, before it is patched up
  • disable pip version checks when creating an environment
  • embed extra packages into the environment at creation time if placed in a local directory
  • and so on

cc: @hoodmane

TODO:

  • Examine which args to add
  • Add CLI support
  • Documentation (most likely self-documented, so we don't need anything else)
  • Add some basic tests
    • Figure out how to run the slow integration tests; maybe disable isolation to let them reuse the download xbuildenv

Comment on lines +300 to +309
if virtualenv_args:
for arg in virtualenv_args:
if arg.startswith("--"):
# Check if the argument (or its prefix form) is supported.
arg_name = arg.split("=")[0] if "=" in arg else arg
if arg_name not in SUPPORTED_VIRTUALENV_OPTIONS:
msg = f"Unsupported virtualenv option: {arg_name}"
logger.warning(msg)

cli_args.extend(virtualenv_args)
Copy link
Member Author

Choose a reason for hiding this comment

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

Should we raise a warning or an error here?

Comment on lines 179 to 180
def test_pip_install(temp_venv_path, packages):
"""Test that our monkeypatched pip can install packages into the venv"""
Copy link
Member Author

Choose a reason for hiding this comment

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

Instead of checking for our SYSCONFIGDATA patches and the like, I thought it would be better to see if the end-user functionality is working, as a working pip ensures that those patches have worked.

Comment on lines +21 to +22
# "--copies", "--always-copy", FIXME: node fails to invoke Pyodide
# "--symlink-app-data", FIXME: node fails to invoke Pyodide
Copy link
Member Author

Choose a reason for hiding this comment

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

Noting for completeness: for supporting these two arguments, we'll definitely need to patch the Pyodide Python (which I need to learn more about).

@agriyakhetarpal
Copy link
Member Author

agriyakhetarpal commented Mar 9, 2025

@ryanking13, I'm facing some trouble here where the dummy_xbuildenv and dummy_xbuildenv_url fixtures that we have in conftest.py are conflicting the test fixtures I introduced in the file, which causes the tests to fail when the test suite is run as a whole, but pass when you run the tests separately using -k test_venv or similar. I'm curious if you've come across such a situation before? I know about adding multiple conftest.py files, but I wouldn't like to do that as it will move a few files without any reason.

For context, I'm trying to test the venv creation with multiple options, as I noticed that it hasn't been tested before. It is easy to split pytest in CI into two steps, but I'm looking for something more robust so that testing locally remains intact.

Edit: either way, this PR is ready for review, it is only the tests that need to be fixed.

@agriyakhetarpal agriyakhetarpal changed the title [DRAFT]: Make pyodide venv more compatible with standard virtualenv args + add tests Make pyodide venv more compatible with standard virtualenv args + add tests Mar 9, 2025
@ryanking13
Copy link
Member

I'm facing some trouble here where the dummy_xbuildenv and dummy_xbuildenv_url fixtures that we have in conftest.py are conflicting the test fixtures I introduced in the file

Hmm that's weird. Those two fixtures should create xbuildenv in a temporary directory which will be removed after the test function so I am not very sure how they can conflict each other.

Let me see if I can reproduce the error.

@ryanking13
Copy link
Member

I think I found the root cause. Let me open a PR to fix it.

ryanking13 added a commit that referenced this pull request Mar 9, 2025
Tests that create xbuildenv didn't reset the cached functions, including
the one that finds pyodide_root. It made the tests fail in
#117 (comment)

cc: @agriyakhetarpal
@agriyakhetarpal
Copy link
Member Author

Thank you for the quick fix!

@agriyakhetarpal agriyakhetarpal marked this pull request as ready for review March 9, 2025 04:35
@ryanking13
Copy link
Member

Looks like the error got different. I guess we need to create a xbuildenv first to create a venv?

@ryanking13
Copy link
Member

ryanking13 commented Mar 9, 2025

Also, please note that the dummy_xbuildenv file that I made in this repository does not contain the python script or other wasm files to run the pyodide venv to reduce the size. I think you can update the dummy file to include those files, but it would increase the repository size, so there is a tradeoff.

Some other options can be:

  1. Use mock files (with a very small or an empty file) for unittest, and instead use integration tests for testing the "real" venv functionality. In integration test, we may use the nightly xbuildenv file from the remote URL.

  2. Testing the full functionality of pyodide venv in pyodide/pyodide, as the content inside dist directory varies per Pyodide version, not by pyodide-build.

  3. Adopt pooch or other tools as you suggested in Remove binary files from repository micropip#165

@agriyakhetarpal
Copy link
Member Author

Thanks, Gyeongjae. I'm currently downloading the latest (stable) Pyodide xbuildenv for the package installation tests, which get cached/reused between the tests so that we don't download it for every test. I don't intend to add the real xbuildenv tarball to the repository with this PR – that will be large, as you mention. The CI should pass now, but if you'd like me to label the slow tests as integration tests, I can do that.

@agriyakhetarpal
Copy link
Member Author

Ah, I spoke too soon 😄 I'm not sure why it fails to find the cross-build environment for downloading. The tests are passing for me locally, though (I confirmed with a fresh state of the repository).

@agriyakhetarpal
Copy link
Member Author

Okay, almost there – just one failing test (that one also passes on my machine) :D

@agriyakhetarpal
Copy link
Member Author

The test fails because it uses the wrong Python interpreter to install packages. It, therefore, installs the macOS wheels for NumPy, and was silently passing in my case. To fix it, we need to call the Pyodide Python interpreter inside the venv (which relies on pyodide/pyodide#5448), or handle the activation/deactivation of the Pyodide venv inside that test to install the packages – I've proceeded with this approach for now in aca03ab.

I see that the rest of the pyodide venv functionality is also being tested elsewhere in Pyodide, in this file: https://github.com/pyodide/pyodide/blob/a53c17fd8ef87e79c7d3bfbb1262ca7ff6718ef2/src/tests/test_cmdline_runner.py, where the tests are more expansive. As @ryanking13 mentioned in pyodide/pyodide#5488, it makes sense to move the relevant tests from that file to pyodide-build, so that the functionality is better tested on every commit.

@agriyakhetarpal
Copy link
Member Author

Argh, this passes locally and works perfectly fine, but not in CI...

@agriyakhetarpal
Copy link
Member Author

So, it passes on macOS indeed, but it fails on Linux.

@agriyakhetarpal
Copy link
Member Author

🤔 no luck. I'm unable python -c "<...>" doesn't work on Linux. I'll probably drop this part of the test, as it is being tested elsewhere as mentioned in #117 (comment).

@hoodmane
Copy link
Member

Do we have use cases for all these features? I'm a little reluctant to add the maintenance burden until someone actually wants the missing features. Currently, pyodide venv is just good enough for cibuildwheel. In particular, I'm concerned that we might implement the wrong thing, someone might start relying on it, and then we might have to change it later. Perhaps we could mark these options as experimental and subject to breaking changes depending on real world feedback?

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