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

Use reusable venvs #199

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

Use reusable venvs #199

wants to merge 9 commits into from

Conversation

jayvdb
Copy link
Contributor

@jayvdb jayvdb commented Nov 18, 2019

Replace pip install --target with venvs.
As setuptools breakes out of the venv to load distutils build_ext
command, first create a copy of the Python distribution and hack
it.

This also has the benefit that the venv can be used to build
extensions outside of PyOxidizer.

Also add venv_path to PipRequirementsFile, allowing the same
venv to be incrementally populated in multiple rules,
and the venv re-used across PyOxidizer build runs.

Fixes #162
Fixes #170
Closes #194

@jayvdb
Copy link
Contributor Author

jayvdb commented Nov 19, 2019

The next step IMO is to add a cli subcommand for creating a hacked venv, before running a full build. This involves splitting the build process a bit, enough to decompress the standalone Python distribution to disk so it can be used for the venvs. I was working on this, but that section of code was being heavily revised so I dropped it in order to get this PR up.

@jayvdb
Copy link
Contributor Author

jayvdb commented Nov 19, 2019

Here is the macOS failure with cryptography. It is just a build env problem, needing openssl, but that doesnt need to be solved to validate the venv changes. And there are problems with openssl specifically, as the host openssl may have different header files than used for the standalone Python build, causing link failures even on Linux. So for macOS I am using bcrypt, and I suspect the same will be needed for Windows.

@warsaw
Copy link
Contributor

warsaw commented Nov 20, 2019

While I can get farther in my problems with #202 it's not a complete solution. I have to put the same venv_path in all my packing rules. That does get me farther, but I still have mysterious, hard to debug packaging failures.

@indygreg
Copy link
Owner

I think supporting reusing a virtualenv makes sense.

But I'm going to hold off reviewing and landing this because I'm overhauling how the config files work and it will be much easier to do advanced things once that work is done. My plan is to leverage Starlark as a "scripting" language and for the config files to more resemble Python scripts than static data structures. e.g. the packaging rules will be attached to the PythonDistribution instances and will emit objects that represent resources which can be packaged - either embedded in a binary or manifested on the filesystem. In this world, we could have a PythonDistribution.create_virtualenv() API that returns a Virtualenv instance and we could call .run_pip(...) on it. This will give vastly more control and flexibility and should result in tons of feature requests being satisfied.

@jayvdb
Copy link
Contributor Author

jayvdb commented Nov 25, 2019

@indygreg , I'm almost finished getting cryptography working on all platforms, and need a bit of time to tidy up and re-push here. Please could you please avoid conflicting me by fiddling in the same part of the codebase. It causes useless merge conflicts for me, and the changes you are making do not help solve the problem. The real problems are not here -- they are indygreg/python-build-standalone#19 and indygreg/python-build-standalone#22 - I have workarounds for those, but real fixes for those are desperately needed.

@indygreg
Copy link
Owner

Don't worry about resolving the merge conflicts: I will rebase your PRs for you.

@jayvdb
Copy link
Contributor Author

jayvdb commented Nov 25, 2019

@indygreg , I'd rather do the rebasing myself, and have purple PRs in my history than lots of red ones and need to go figure out what changes you've made to my code.

@jayvdb
Copy link
Contributor Author

jayvdb commented Nov 25, 2019

I've done a quick push of what I have. There are still some bits that are no longer needed, to be removed. I'll lightly annotate it now.

- ${{ if eq(parameters.name, 'Linux') }}:
- script: |
cargo run --bin pyoxidizer -- init --pip-install cryptography ~/pyapp
cat ci/pyapp.py | cargo run --bin pyoxidizer -- run ~/pyapp
Copy link
Contributor Author

Choose a reason for hiding this comment

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

#208 is needed for all of these enhancements to the sample app CI. This approach is taken because otherwise the lines are very long, and also to avoid horrid Windows CMD quoting problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fix included in #200

displayName: Build Oxidized Application

- ${{ if eq(parameters.name, 'macOS') }}:
- script: brew install [email protected]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is unnecessary, as it is pre-installed, but it is only a few seconds. Happy to remove it though.

- ${{ if eq(parameters.name, 'Windows') }}:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.7'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is necessary because the windows job needs a functional Python, mostly due to indygreg/python-build-standalone#22

indygreg/python-build-standalone#19 is also problematic, but it can be worked around by using virtualenv instead of venv. Currently the code in the PR does use virtualenv because I was initially attempting to use the standalone python, but cffi put a halt to that plan, so I am going to rip that out so that all OS use venv, simplifying a few areas of the changes.

@@ -0,0 +1,15 @@
import cryptography.fernet
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is copied from jamesabel/spafit#2

It is a good smoketest for basic cryptography.

pyoxidizer/src/py_packaging/distribution.rs Outdated Show resolved Hide resolved
.unwrap()
.display()
.to_string();
if site_packages_s.starts_with("\\\\?\\") {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This prefix is added by Path.canonicalize, and I wasnt sure if Python could handle it.
I'm not sure if this is necessary. Need to try removing it.

Also it seems I need to set PYTHONHOME. I've seen warnings that it wasnt set whilst pip is installing stuff.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I read venv bin/activate again, and I am not sure about PYTHONHOME

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The message I had seen is appearing on macOS only, and is

...
modifying distutils/unixccompiler.py for oxidation
creating venv /var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/pyoxidizer-temp-venv.TMkXswfSsJy9/venv
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Collecting gevent
  Downloading ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like we are seeing some effects of https://bugs.python.org/issue22213 - when I used virtualenv instead of venv, the problem goes away.

fs::create_dir_all(&python_paths.pyoxidizer_state_dir).unwrap();

extra_envs.insert(
"PYOXIDIZER_DISTUTILS_STATE_DIR".to_string(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is moved out of distutils.rs because most of the venv environ stuff is here, and it feels a bit odd to getting only a single path returned from prepare_hacked_distutils and that value does not need to be any specific value for the distutils hack to work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also being able to run commands in the venv outside of PyOxidizer provides a lot of flexibility not currently possible with the config file. For that to happen either:

  1. the distutils hacking pushes the state directory name into the .py files, or
  2. the distutils .py and rust code both use the same state directory path

I have opt for the latter, as that seems to be more appropriate in a venv which has a 'prefix'

@@ -694,6 +955,8 @@ pub fn analyze_python_distribution_data(
};
}

let venv_base = dist_dir.parent().unwrap().join("hacked_base");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

"hacked_base" probably should be given a better name

);

let orig_distutils_path = dist.stdlib_path.join("distutils");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a separate bug, but it doesnt seem useful to split it off to a separate commit: distutils can not be anywhere - it must be the real one, as setuptools hunts for the real one, even navigating through a venv to find it.

pyoxidizer/src/py_packaging/distutils.rs Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants