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

Support running with the Windows embeddable Python distribution #465

Merged
merged 3 commits into from
Sep 6, 2020

Conversation

pfmoore
Copy link
Member

@pfmoore pfmoore commented Aug 13, 2020

  • I have added an entry to docs/changelog.md

Summary of changes

Adds support for using pipx with the Windows embeddable distribution, which doesn't include a venv module itself. The change makes pipx use the embeddable distribution for running its own code, but uses the system default Python for creating virtual environments.

The code is not specific to the embeddable distribution, but is triggered if the venv module is not importable, which may be useful for other limited Python distributions.

Test plan

There is a version of pipx installable using the scoop package manager which uses this patch. I have been using this distribution for some time now.

# distribution


def _find_default_python():
Copy link
Member

Choose a reason for hiding this comment

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

If this is only used on windows, suggest changing the name to contain windows, something like _find_default_python_windows().

Copy link
Member Author

Choose a reason for hiding this comment

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

No problem, done.

)
if proc.returncode != 0:
# Cover the 9009 return code pre-emptively.
raise EnvironmentError("no available Python found")
Copy link
Member

Choose a reason for hiding this comment

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

Though EnvironmentError is technically accurate, pipx only catches PipxErrors (at the bottom of main.py) and prints a single line, user-facing error. This will result in a full stack trace, which we want to avoid. Could these be changed to PipxErrors?

Copy link
Member Author

Choose a reason for hiding this comment

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

Also done

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, this failed because of a circular import - constants imports util which in turn imports constants. I'll need to look in more detail at how to address this. I'll come back with a revised patch in a while...

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, after looking for a while for ways to avoid the circular import it occurred to me that there's no point. If we can't find a suitable value for DEFAULT_PYTHON, that will happen when constants.py is imported, which is outside the scope of the try..except that catches PipxError.

I see two possible fixes here:

  1. (Simple, but a bit of a hack) Replace the exception with a simple raise SystemExit("Python interpreter does not support venv"). This will avoid an unfriendly traceback, but will remain outside of the general PipxError handling.
  2. (More complex, maybe better?) Replace DEFAULT_PYTHON with a function, called when needed. I'd propose splitting this out into a separate file, pipx.interpreter, to break the circular import.

With option (2) it would also be possible to add some simple unit tests (monkeypatch import venv to fail, and check the default python is not sys.executable). But we'd be adding some non-trivial complexity for a fairly niche case.

What would you prefer?

Copy link
Member Author

Choose a reason for hiding this comment

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

@cs01 Gentle ping - which approach do you thing I should take with this?

Copy link
Member

@cs01 cs01 Aug 29, 2020

Choose a reason for hiding this comment

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

Hi sorry for the slow response.

I lean toward option 2. This will probably not be the last time we need to add additional logic to determine DEFAULT_PYTHON.

Copy link
Member Author

Choose a reason for hiding this comment

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

No worries, I'll see if I can implement that approach. I just didn't want to over-engineer for what is a relatively rare case, without knowing whether you supported it in principle.

@cs01
Copy link
Member

cs01 commented Aug 16, 2020

There is a version of pipx installable using the scoop package manager which uses this patch. I have been using this distribution for some time now.

Perhaps documentation for this should be added to pipx?

@pfmoore
Copy link
Member Author

pfmoore commented Aug 17, 2020

Perhaps documentation for this should be added to pipx?

Perhaps. It's not my project, though, so I'd be reluctant to give it more publicity without the owner (@uranusjr) confirming he was OK with that.

@uranusjr
Copy link
Member

I’ve mentioned the project in both #244 and #338. Neither message got any feedback, and I assumed the interest has been minimal.

It’s perfectly fine if it’s added to the documentation, but I’d caution that the maintenance has been low-effort (I regularly skip pipx updates I don’t care to follow), and anyone wanting to use it should be ready to contribute 🙂

@pfmoore
Copy link
Member Author

pfmoore commented Aug 18, 2020

(@uranusjr Offtopic here, but I've got some scripts that do auto-updates of a scoop bucket - I'm pretty sure I could set up an auto-update process that tracked new pipx releases. It's a bit fiddly, though, so I can't promise how soon I'd be able to get to it)

@pfmoore
Copy link
Member Author

pfmoore commented Sep 2, 2020

Sorry for the delay. New version uploaded. I had to rebase and force-push as I got in a mess merging with master (black changed its behaviour and I did a whole lot of fixups before I merged and found master handled it differently...)

Anyway, the resulting change seems cleaner as a single commit, so hopefully no harm done.


# This code was copied from https://github.com/uranusjr/pipx-standalone
# which uses this technique to build a completely standalone pipx
# distribution
Copy link
Member

Choose a reason for hiding this comment

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

Do these comment blocks belong inside the function below instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was intentional to put the comments before the function rather than inside it (I find it more readable that way). But I can reword it a bit, I guess. Maybe swap the paragraphs, and say "The following code was copied from ... which uses the same technique..."?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, the paragraphs seem more natural to me if swapped.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@cs01 cs01 merged commit 50dc0e9 into pypa:master Sep 6, 2020
@cs01
Copy link
Member

cs01 commented Sep 6, 2020

Thank you, @pfmoore

@pfmoore pfmoore deleted the embedded_dist_support branch September 7, 2020 07:00
@pfmoore
Copy link
Member Author

pfmoore commented Sep 7, 2020

Awesome, thanks!

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