-
-
Notifications
You must be signed in to change notification settings - Fork 151
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
add venv as an option for venv_backend #231
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments based on desk-checking the code, I'm not currently at a machine where I can test it.
nox/virtualenv.py
Outdated
if self.interpreter: | ||
cmd.extend(["-p", self._resolved_interpreter]) | ||
cmd = [self._resolved_interpreter] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change means that if virtualenv is used, it will now need to be installed in the resolved interpreter, whereas the current code only requires virtualenv to be installed in the current interpreter. It's not clear to me whether this would be a problem in practice, but it is a change in behaviour and if it's to be made, it should be done deliberately and not "by accident".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, that was a remnant of my hack to get pipx tests working earlier. I'll add the -p
flag back in if virtualenv is being used. I'll fix it.
"Re-using existing virtualenv at {}.".format(self.location_name) | ||
"Re-using existing virtual environment at {}.".format( | ||
self.location_name | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a risk here that the existing environment used virtualenv, but the request was to use venv? If so, would this result in the caller getting the wrong type of environment? This is a real edge case, and probably isn't a major consideration, but it's worth noting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there is. Agreed this is an edge case. I suppose there could be a call made to identify whether it's a virtualenv or venv and to assert as necessary before continuing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also have an outstanding bug to make sure the -r
checks the interpreter version as well. We might be able to just add a note to that issue that checking the backend should be part of the check as well. #123.
nox/virtualenv.py
Outdated
if self.interpreter is None: | ||
self._resolved = sys.executable | ||
if currently_in_virtual_environment: | ||
self._resolved = resolve_real_python_outside_venv(self.interpreter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As it stands, this has no hope of working on Windows. At this point, we're calling resolve_real_python_outside_venv(None)
(side note, it might be better to explicitly use None
, rather than have the reader need to track back to the if statement to determine that self.interpreter
is always None
at this point). There's no check for _WINDOWS
here (unlike the call below) so the fact that resolve_real_python_outside_venv
doesn't (yet) support Windows will cause immediate breakage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
nox/virtualenv.py
Outdated
@@ -238,7 +268,10 @@ def _resolved_interpreter(self): | |||
cleaned_interpreter = "python{}".format(xy_version) | |||
|
|||
# If the cleaned interpreter is on the PATH, go ahead and return it. | |||
if py.path.local.sysfind(cleaned_interpreter): | |||
if currently_in_virtual_environment and _SYSTEM != "Windows": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're ignoring cleaned_interpreter
here, which seems weird. Why go to the trouble of calculating it and then not use it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I didn't intentionally ignore it
nox/virtualenv.py
Outdated
See also: | ||
https://docs.python.org/3/library/sys.html#sys.prefix | ||
https://docs.python.org/3/library/sys.html#sys.base_prefix | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This definitely won't work on Windows. There are various implementations of this type of "locate Python" algorithm on the web, including a reusable library version at https://github.com/sarugaku/pythonfinder.
Unfortunately, reusable code for this seems hard to locate (hence the reason so many people write their own) but IMO we should use a library if at all possible (pythonfinder is the one I've heard of, but I have no problem if someone recommends a better one).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pythonfinder looks like it can replace the entire existing nox function unless I'm missing something. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced all the code with pythonfinder but it isn't able to find any installations. I'll keep trying with it, but won't be able to work on it any more until tonight. If it works it will simplify the code tremendously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've not used pythonfinder myself, I just knew about it from other projects. So I've no experience with it I'm afraid. I'll try to have a play with it myself, in case I get any ideas.
I would definitely want to make the pythonfinder stuff a separate PR, if
that's okay with y'all.
Relatedly, I'm a bit wary about taking on new dependencies in Nox. It
definitely warrants a bit of discussion.
…On Mon, Aug 5, 2019 at 10:14 AM Chad Smith ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In nox/virtualenv.py
<#231 (comment)>:
> @@ -174,6 +175,26 @@ def create(self):
return True
+def resolve_real_python_outside_venv(desired_intepreter: str) -> str:
+ """Return path to the real Python installation based
+
+ See also:
+ https://docs.python.org/3/library/sys.html#sys.prefix
+ https://docs.python.org/3/library/sys.html#sys.base_prefix
+ """
I replaced all the code with pythonfinder but it isn't able to find any
installations. I'll keep trying with it. If it works it will simplify the
code tremendously.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#231>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAB5I4ZLJ2EAUPFK4QNEYVDQDBNWLANCNFSM4IJHWZ4Q>
.
|
I'm completely fine with the pythonfinder thing being a separate discussion. However, getting But I do think that in the long term, duplicating this same bit of code in many projects is a bad idea... |
@pfmoore I'm pretty sure this is tox's: https://github.com/tox-dev/tox-venv/blob/master/src/tox_venv/hooks.py |
If we land the PR to switch to pythonfinder *first*, does this PR become
easier/less complex?
…On Mon, Aug 5, 2019 at 10:35 AM Chad Smith ***@***.***> wrote:
@pfmoore <https://github.com/pfmoore> I'm pretty sure this is tox's:
https://github.com/tox-dev/tox-venv/blob/master/src/tox_venv/hooks.py
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#231>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAB5I472HOLILTZYLKOK7NLQDBQETANCNFSM4IJHWZ4Q>
.
|
@theacodes Assuming pythonfinder does what I think it does, yes. This PR is really doing two things: adding the venv_backend option of venv, and updating Python resolution to make venv creation from within a virtual environment work. It makes sense to review the two changes separately; I can separate it out into two PRs. |
I'm not sure that's all of it. A key part is As a simpler workaround, you can let the launcher do the work for you, and call The reason I'm in favour of a library solution is that it's really tricky to get all the edge cases correct. Of course, users can always just supply the full executable path, so it's not like it's critical, but it's not a good UX if the software can't find a Python installation you know is there.
Yeah, mixing virtualenvs and venvs is really messy. At this point I think you can safely create a virtualenv from within an active venv (see the discussions around pypa/virtualenv#1345 for the ugly details) but I don't think creating a venv from within an active virtual environment (either venv or virtualenv) is even supported. So getting this fixed would be good (for general reliability, even if there's no specific issue it's causing right now). |
Something like the following should work for Windows, for what it's worth. Lightly tested, it works on my PC but I only have one Python version installed, so I couldn't test much... import os
import subprocess
def get_python(major, minor=None):
env = os.environ.copy()
env['PYTHONIOENCODING'] = "utf-8"
version = "-" + major
if minor:
version += "." + minor
try:
proc = subprocess.run(
["py", version, "-c", "import sys; print(sys.executable)"],
env=env,
capture_output=True
)
except Exception:
# Just say we couldn't find anything if we get any sort of error
return None
if proc.returncode != 0:
return None
return proc.stdout.decode("utf-8").strip()
if __name__ == '__main__':
import sys
print(get_python(*sys.argv[1:])) |
Whoa! I just looked at the list of dependencies for pythonfinder:
That's way too much for the job it's doing. Installing it pulled in 15 other packages, for a total of about 14M of data. At this point, I'd say let's not use pythonfinder. That's just silly :-( |
nox/virtualenv.py
Outdated
|
||
if self.interpreter: | ||
if self.interpreter and self.venv_or_virtualenv == "virtualenv": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if they request a different interpreter version than the one Nox is installed on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I think I see a bug.
In the case of venv we should call
[self._resolved_interpreter, 'venv', '-m', 'self.location']
rather than use sys.executable
since you can't specify the python interpreter to use in venv (it just uses the Python you create the venv with).
In the case of virtualenv it will remain unchanged
[sys.executable, 'virtualenv', '-m', 'self.location', '-p', self._resolved_interpreter]
Just FYI I filed an issue in pythonfinder on this: sarugaku/pythonfinder#78 |
Got the tests passing 🎉 . So to summarize, this PR adds support for |
I don't really have a feeling for how many other people want to use this. AFAIK the only reason you'd want it is to test a program that creates virtual environments. So that would include pipx, pipenv, poetry, virtualenv, venv, and maybe some others. Because of this, I don't know if there is much value added to using the venv backend without the improved Python resolution, so I was planning on waiting until the improved Python resolution was added before documenting it. |
Sounds good. Thank you.
…On Mon, Aug 12, 2019, 9:57 AM Chad Smith ***@***.***> wrote:
Thank you, @cs01 <https://github.com/cs01> and @pfmoore
<https://github.com/pfmoore>!
Does this need a follow-up PR for documentation as well, or do we think
it's sufficiently advanced enough that most users won't need it?
I don't really have a feeling for how many other people want to use this.
AFAIK the only reason you'd want it is to test a program that creates
virtual environments. So that would include pipx, pipenv, poetry,
virtualenv, venv, and maybe some others. Because of this, I don't know if
there is much value added to using the venv backend without the improved
Python resolution, so I was planning on waiting until the improved Python
resolution was added before documenting it.
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
<#231>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAB5I467HHIGZ4VNMSZONSTQEGJADANCNFSM4IJHWZ4Q>
.
|
Hmmm, I've been working on making virtualenv more like venv, and add python discovery part of it - see https://github.com/gaborbernat/virtualenv/blob/rewrite/src/virtualenv/interpreters/discovery/__init__.py 🤔 probably will be released in a month or so 🤔 so this entire ticket should self solve itself then 🤔 |
venv is now a valid backend for nox, so nox can create venvs, but interpreter resolution in nox still needs to be improved since it still defaults to the python in the venv. Are you saying that in the future, nox can use virtualenv but still find the base interpreter from there (I think currently it can only do this from venv), or that the default interpreter in virtualenv will be the base interpreter and therefore able to create a new venv/virtualenv from there? (This is the PR, open issue is at #233) |
virtualenv's future discovery mechanism will always let you know the base interpreter too (for venv/old virtualenv/host python) 👍 furthermore new virtualenv environments will be equivalent with current venvs. |
Right now, nox has a |
Not sure how this will integrate into nox; but virtualenv will contain the logic of interpreter discovery (with option to also access the host interpreter, not just the immediate discovered one). tox will definitely use this and no longer implement its own version of this functionality, nox might or might not choose to do so, 🤷♂ it's up to @theacodes |
Summary
This PR adds support for a different backend,
venv
. It adds a keyword argument to theVirtualEnv
class, which defaults toFalse
and is only true when the nox session hasvenv_backend=True
.It also updates the resolution of the Python path, since using
venv
alone does not fix issues when creating a venv from within a virtual environment.The path resolution is modified to determine if a virtual environment is being used. If so, it tries to find the desired Python interpreter version in the
base_prefix
rather than anywhere on the system's PATH. Note that Windows was not tested, and probably will require some more changes.Test Plan
Additional context
https://docs.python.org/3/library/sys.html#sys.prefix
https://docs.python.org/3/library/sys.html#sys.base_prefix
Tox's implementation for venv support is included as a plugin in an additional package: https://github.com/tox-dev/tox-venv/blob/master/src/tox_venv/hooks.py
fixes #199
cc @pfmoore