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

[feature] Download/use standalone python build when chose --python version doesn't exist #1243

Merged
merged 21 commits into from
Feb 7, 2024

Conversation

alextremblay
Copy link
Contributor

@alextremblay alextremblay commented Feb 4, 2024

  • I have added a news fragment under changelog.d/ (if the patch affects the end users)

Summary of changes

As per #1242, this PR updates pipx.interpreter.find_python_interpreter to download the desired python version if pipx is not able to find it in the system, rather than simply failing with an exception.

Test plan

Tested by running

# The following commands were successfully tested on a system which only has python 3.8 and 3.10 installed
$ pipx run --python=python3.9 cowsay -t hello
$ pipx run --python=python3.10 cowsay -t hello
$ pipx run --python=python3.11 cowsay -t hello
$ pipx run --python=python3.12 cowsay -t hello
$ pipx run --python=3.9 cowsay -t hello
$ pipx run --python=3.10 cowsay -t hello
$ pipx run --python=3.11 cowsay -t hello
$ pipx run --python=3.12 cowsay -t hello

The following was also tested:

myscript.py:

#!/usr/bin/env -S pipx run --python=3.11 --path

# /// script
# dependencies = [
#   "requests",  # example of external dependency
# ]
# ///
import requests

print(requests.get("https://example.com").text)
$ chmod  x myscript.py
$ ./myscript.py | head
<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {

@alextremblay
Copy link
Contributor Author

@dukecat0 @uranusjr I've got a preliminary POC of this feature which I'm quite happy with, but before I sink any more time into this, I'm hoping to get some feedback and make sure I'm on the right track.

Is this something you would like me to keep working on? do you have any notes on my implementation?

@dukecat0
Copy link
Member

dukecat0 commented Feb 4, 2024

Thanks for working on this! I personally find this feature very useful. 👍 Probably it will be better if there's an environment variable that allows users to disable this behavior.

@chrysle
Copy link
Contributor

chrysle commented Feb 4, 2024

Looks like a helpful feature, thanks!

Probably it will be better if there's an environment variable that allows users to disable this behavior.

I agree with that – or even a flag to toggle the behaviour.

@Gitznik
Copy link
Contributor

Gitznik commented Feb 4, 2024

Good stuff!

I would argue that this feature should be opt-in, rather than opt-out. I would be very confused if I accidentally mistype a python version and pipx just starts downloading it unprompted.

@chrysle
Copy link
Contributor

chrysle commented Feb 4, 2024

opt-in, rather than opt-out

I agree – that's why I suggest a flag (with negative default value).

@alextremblay
Copy link
Contributor Author

Excellent idea! I’m more than happy to implement that. Not sure what to call the flag though… something succinct?

ideally also an environment variable to flip the default

maybe something like —fetch-as-needed? It’s a bit wordy, but I can’t think of anything more succinct that gets the idea across

@Gitznik
Copy link
Contributor

Gitznik commented Feb 4, 2024

ideally also an environment variable to flip the default

1

maybe something like —fetch-as-needed? It’s a bit wordy, but I can’t think of anything more succinct that gets the idea across

fetch-missing-python? fetch-as-needed could also refer to the package to install/run itself.

src/pipx/constants.py Outdated Show resolved Hide resolved
src/pipx/standalone_python.py Outdated Show resolved Hide resolved
src/pipx/standalone_python.py Outdated Show resolved Hide resolved
src/pipx/standalone_python.py Outdated Show resolved Hide resolved
src/pipx/standalone_python.py Show resolved Hide resolved
src/pipx/interpreter.py Outdated Show resolved Hide resolved
@chrysle
Copy link
Contributor

chrysle commented Feb 4, 2024

Please add a news fragment, too. And we'll need tests.

src/pipx/standalone_python.py Outdated Show resolved Hide resolved
src/pipx/standalone_python.py Outdated Show resolved Hide resolved
src/pipx/standalone_python.py Show resolved Hide resolved
changelog.d/1242.feature.md Outdated Show resolved Hide resolved
src/pipx/main.py Outdated Show resolved Hide resolved
src/pipx/standalone_python.py Outdated Show resolved Hide resolved
tests/test_interpreter.py Outdated Show resolved Hide resolved
tests/test_interpreter.py Show resolved Hide resolved
@alextremblay
Copy link
Contributor Author

Hi All, this feature is now, to the best of my ability, complete.

I've added tests, a news entry, and adopted / implemented just about every change that's been requested.

The tests are all now passing on all platforms and python versions.

I've spent a not insignificant amount of time and energy making this feature implementation as good as it can be in the hopes that it will be accepted and merged. I am running out of time and energy to devote to this now.

I think it's ready to review and/or merge. I'm going to step away from it now. If there are any additional changes you would like to make, feel free to make them before or after merging the feature.

Thank you

@alextremblay alextremblay marked this pull request as ready for review February 5, 2024 15:13
tests/test_interpreter.py Outdated Show resolved Hide resolved
Copy link
Contributor

@Gitznik Gitznik left a comment

Choose a reason for hiding this comment

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

I can work on my change requests myself.

src/pipx/standalone_python.py Outdated Show resolved Hide resolved
tests/test_interpreter.py Outdated Show resolved Hide resolved
@Gitznik
Copy link
Contributor

Gitznik commented Feb 5, 2024

Would be nice if there was a command to clean up the python versions, e.g. when a downloaded python version does not have a installed app that uses it anymore. We can treat that as a separate feature request though IMO.

@alextremblay
Copy link
Contributor Author

Would be nice if there was a command to clean up the python versions, e.g. when a downloaded python version does not have a installed app that uses it anymore. We can treat that as a separate feature request though IMO.

Also a command to update one or all standalone versions (ie someone uses --python=3.9 --fetch-missing-python and wind up with v3.9.10 installed to PIPX_HOME/py/3.9. several months later, they come back and install another package with --python=3.9 --fetch-missing-python, and that package gets installed with python 3.9.10, even though v3.9.18 is now available)

That's a hard problem to solve automatically, so i think a manual process / command would be the way to go

@alextremblay
Copy link
Contributor Author

This latest error in the windows unit test is... interesting, to say the least.

is PIPX_HOME cached in CI between test runs?

I'm not quite sure how else to explain why PIPX_HOME/py/3.11 already exists on the windows CI server...

@chrysle
Copy link
Contributor

chrysle commented Feb 5, 2024

Probably we should use pytest's tmp_path fixture?

@alextremblay
Copy link
Contributor Author

Probably we should use pytest's tmp_path fixture?

to override the PIPX_STANDALONE_PYTHON_CACHEDIR constant?

I suppose so, but that somehow feels wrong. the unit test should as closely as possible reflect what will actually happen on a user's machine

ordinarily, this error we're seeing should be impossible. if standalone python 3.11's already been downloaded, the function should return early without trying to redownload it. this error seems to indicate that a previous run failed and produced an empy PIPX_HOME/py/3.11 folder...

@alextremblay
Copy link
Contributor Author

Well, apart from that rate limit error on the windows test, I think we're now good to go.

Are there any additional changes you need, or can this be merged?

src/pipx/interpreter.py Show resolved Hide resolved
tests/test_interpreter.py Outdated Show resolved Hide resolved
@chrysle
Copy link
Contributor

chrysle commented Feb 6, 2024

I'd like to raise awareness for #1243 (comment) that should still be implemented IMHO, as it tests basic functionality.

As for the rate limit, I see that as a possible issue, as these tests will be run many times. I propose skipping this test if standalone_python.py isn't modified (don't know how to achieve that, yet), or scheduling it.

@alextremblay
Copy link
Contributor Author

I'd like to raise awareness for #1243 (comment) that should still be implemented IMHO, as it tests basic functionality.

As for the rate limit, I see that as a possible issue, as these tests will be run many times. I propose skipping this test if standalone_python.py isn't modified (don't know how to achieve that, yet), or scheduling it.

The first suggestion from that comment (ensuring the target python isn't found on dev's machines) has already been implemented (by mocking out which in both the windows test and the unix test.

The second comment, adding a python_version variable to these two unit tests, doesn't make sense to me. none of the other tests in that test suite define such a variable, and i don't understand why we would want to add such an inconsistency or why the lack of this variable is a blocker towards getting this change merged?

@alextremblay alextremblay reopened this Feb 6, 2024
@alextremblay
Copy link
Contributor Author

I'd like to raise awareness for #1243 (comment) that should still be implemented IMHO, as it tests basic functionality.

As for the rate limit, I see that as a possible issue, as these tests will be run many times. I propose skipping this test if standalone_python.py isn't modified (don't know how to achieve that, yet), or scheduling it.

regarding the rate limit, that is definitely a concern. I'm going to try and write a fixture to mock out the API call specifically, that should take care of that problem

stand by

@chrysle
Copy link
Contributor

chrysle commented Feb 6, 2024

The first suggestion from that comment (ensuring the target python isn't found on dev's machines) has already been implemented (by mocking out which in both the windows test and the unix test.

However, implementing it would ensure the exception is raised correctly, which isn't entirely useless.

@alextremblay
Copy link
Contributor Author

However, implementing it would ensure the exception is raised correctly, which isn't entirely useless.

oh, i see, you're suggesting i write a test for the failure mode. gotcha, will do

@alextremblay
Copy link
Contributor Author

I'd like to raise awareness for #1243 (comment) that should still be implemented IMHO, as it tests basic functionality.

hi @chrysle, I've implemented test cases for versions of python which aren't available in the python-build-standalone project

in the future, we might want to expand the logic of the standalone_python module to collect data from multiple releases of the python-build-standalone project and merge it all together so that we can support fetching more python versions than are available in the current release (ie. 20231002 was the last release to include a version of python 3.8), but that's a massive increase in complexity for very little gain, and far outside the scope of this PR

Gitznik
Gitznik previously approved these changes Feb 6, 2024
Copy link
Contributor

@chrysle chrysle left a comment

Choose a reason for hiding this comment

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

Two suggestions, looks good to me other than that!

tests/test_interpreter.py Show resolved Hide resolved
tests/test_interpreter.py Outdated Show resolved Hide resolved
@chrysle chrysle enabled auto-merge (squash) February 7, 2024 14:11
@chrysle chrysle merged commit 407b797 into pypa:main Feb 7, 2024
12 checks passed
@chrysle
Copy link
Contributor

chrysle commented Feb 7, 2024

Thank you for all the work you have invested into this contribution!

Would be nice if there was a command to clean up the python versions, e.g. when a downloaded python version does not have a installed app that uses it anymore. We can treat that as a separate feature request though IMO.

Also a command to update one or all standalone versions

Additional concerns, as a pipx clean (?) command, shall be addressed in follow-ups.

@Gitznik
Copy link
Contributor

Gitznik commented Feb 7, 2024

Thank you for bearing with us through the review process @alextremblay. Great contribution!

We also moved logging the exceptions from the interpreter resolution outside of the scope of this issue, so that also needs a follow-up.

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.

[feature] Download/use standalone python build when chose --python version doesn't exist
4 participants