-
Notifications
You must be signed in to change notification settings - Fork 3k
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: incorporate pip-run as pip run #3971
Comments
@jaraco broken link |
That's beautiful. I've long suspected that environments based on "what a particular console script requires" might be a great alternative to environments based on "paths relative to a copy of the Python executable", but you went and did it! |
So I don't have a real strong feeling about this. It doesn't feel like something I'd ever use personally, but I already have
Or something like that. With explicit temporary environment creation/deletion (via deactivate/exit) that is trivial to do. With rwt it seems like I'd have to go and edit my It's entirely possible (likely even) that there's some workflow or use case that I don't personally use that would make this useful though. However, I don't think it's something we'd want to recommend as a replacement for So I guess overall my suggestion about how to implement the feature would be to ditch the Python syntax and do something like: #!/usr/bin/python
# -*- coding: utf-8 -*-
# Requires: setuptools>=1.0
# Requires: cffi>=1.0
import setuptools
setuptools.setup(...) I think that makes it more clear that this is not Python syntax and you can't expect to do things like string interpolation or what have you inside of it. Given all of that though, I am -1 on recommending/using it for a |
This might be a great way to implement PEP 518. Surely all the interesting stuff is unrelated to how the dependencies are read. Recall that you would parse a .toml and look for the ['build-system']['requires'] key. It looks like it would probably run into the "pip --target does not work on global pip in Debian" problem caused by their "--user is the default" patch. I dread using programs that are written in Python even though I love developing programs in Python, and it's because of virtualenv. Virtualenv is for development. When you just want to run youtube-dl there is no |
I chose to use
Ugh. I don't want to invent yet another DSL for package management, especially one that mixes Mime headers and shell comments and requirement syntax. I want the declarations to be data and in a widely-accepted format (i.e. Python or JSON).
I do recall having read PEP 518, but PEP 518 falls short of the goals of rwt and has a narrower focus.
Not that you would necessarily want to do it that way, but you could.
As seasoned developers, we're comfortable with tooling and don't mind having and maintaining environments with It's also important that this mechanism supports a single file, so that a script can be represented in a Gist or as downloadable script. Consider this example where I've replaced That said, I'm okay with it not being something you would want to use. If you prefer for the state to accumulate in virtualenvs on your machine and virtualenvwrapper helps facilitate that, I'm all in favor of continuing to use those. I don't see
That's understandable. And I'm happy to defer that decision to the preferences of the pip maintainers. I present the idea here for consideration. |
Yes, it does. I've found that I've had to manually install pip on Xenial systems to bypass the issue. |
Having thought about it, I like the idea as a standalone utility (which I might use occasionally, but see below) but I'm not sure it fits that well as a pip subcommand. It sort of feels more like it's related to virtualenv than to pip. Personally, I have a Using |
To be clear, other than being -1 on using/recommending this for a
So my biggest problem with
Sure! I don't think that every thing that exists in pip needs to be something I'd personally use either :). My "I don't think I'd use this" is mostly about me not having a good frame of reference to judge this particular feature by and whether it's useful to include or not. My only real concern about adding a
Though as you mentioned, this does have the same bootstrapping problem that pip/setuptools/virtualenv has and there is also a certainly a discoverability problem too. Perhaps rebranding as |
I feel strongly about features like this. I think integrating this and/or something more like pipsi into pip would be transformative - that we would see more Python application development in general. Consider the humble Why not distribute a We do love our interactive shells in Python. In a system like rwt you would start with the script and say "give me a shell with that script's dependencies". Backwards compared to virtualenv where you start with the dependencies and eventually get the script. Which direction is best depends on what you are doing. Also, if we build rwt into pip, maybe --target will start working on Debian again. I'm not worried about I assume @jaraco is familiar with my own attempt at short bootstrap code https://bitbucket.org/dholth/enscons/src/tip/setup.py?fileviewer=file-view-default |
By the way does rwt handle cases like setuptools 27 is installed, but requires = [ 'setuptools==26'] |
Yup
|
I don't think this feature is related to pipsi (though I also think that something like pipsi inside of pip itself would be great). This seems to be more tailored towards one-off implicit, temporary environments whereas pipsi is tailored more towards per-command, permanent environments. I do think there is something here we need to figure out though for any potentional pipsi, rwt, and PEP 518 implementation is how is pip going to handle isolation. Currently pip and virtualenv do not have a dependency on each other (and that was done on purpose to allow people to use one without the other). However all of these things need some mechanism of an isolated install so it starts to become attractive to bolt the two things together more -- that or we need something like what rwt is currently doing, which is sort of emphereal environments based on I don't think that Anyways, my opinion on |
Agreed - for me the interesting thing about rwt is the isolation aspect, and that feels more like virtualenv/venv than pip. I would be very interested in a discussion on how rwt does isolation (I haven't even looked into it myself, yet[1]) and whether that's appropriate as a standard method for pip. IMO, it may even be worth considering an informational PEP "standard approach to providing script-specific dependencies". That would be useful for people writing zipapps, as well. [1] It may be that it's nothing more clever than "create a temp dir, do pip install -t, set sys.path appropriately, clean up afterwards". |
I've added a section in the readme on how it works. The isolation is extremely simple - relying on However, there are some additional details. For example, in jaraco/pip-run#1, I captured an issue where namespace packages wouldn't work properly on Python 3.2 and earlier because the There is other code in the codebase for relying on |
I'd like to revive this discussion. Since the original proposal, the implementation has been refined with a much clearer set of advertised use-cases, mainly enabling those one-off troubleshooting or installation demos. Here are some reasons why pip-run is different from virtualenv and why integration is valuable:
I'd like to re-introduce the integration via vendoring initially so that pip-run and Would the maintainers of pip entertain a revival of the #3979? What would it take to be accepted? |
I've had some situations recently where
Personally, yes.
I'd say, if you submit an updated PR, and none of the other maintainers raises objections, then (subject to review of the PR, obviously) I'd be happy to accept it. |
I think there's room for improvement here. I've opened up a couple of issues in the project.
That's interesting. I get a lot better performance.
It probably depends a lot on network speed, disk speed, and CPU, because it's live-resolving dependencies on PyPI and live expanding them. Still, 1.8s is a long time to wait for a script to start up, especially if you start it more than once. Concerns about caching and performance are being discussed in jaraco/pip-run#52. Of all of these concerns, I think this one is the most difficult to reconcile with other goals (namely accuracy vs stale caches).
To be sure, virtualenvs have at the same time gotten better, especially with the py launcher, which will auto-activate ./venv. For me, however, virtualenv breaks the ephemeral barrier - it adds implicit debt, requiring the user to find a home for it, then provision it, then clean it up. Pip-run is the only command you can give to a user to do that and not leave them with unmanaged state.
I branded as I don't want this solution to be "official" in the sense that it's exclusionary of other solutions. I want it to be broadly useful for my use cases and use-cases I don't care about. I don't see it as a competitor to venv or even pipx (which as you've observed fits a very different niche). I do want it to be prominent enough that people can use it when it suits them (or when directed) without having to mutate their system. If it would help, I'd be okay with I'm not sure I fully understand this concern, though. What's the issue with the "pip run" branding?
I continue to market it and tell people about it and demo it. It gets good enough reception, but one of the drawbacks is that for those who would find it useful, they also already have built up habits that are good enough. They probably are uneasy about installing something into their user or system python environments, and if they're not, then they're probably just as happy to install their requirements into that environment. In my mind, it's dramatically more useful when it already exists in the environment. I believe the issues in pip-run now capture the biggest concerns. I'm hoping we can address those and then explore exposing the functionality as pip run, even if just provisionally. |
The point was that It was a minor point, though. |
There are two point I (still partially) dislike with this option:
|
+1 on this. I implemented the 4th option as you describe for |
The latest release of pip-run (9.3) implements behaviors that I believe will satisfy the UX concerns that pfmoore raised. In particular:
I assume these changes address the biggest concerns with the UI. Is there anything else that needs consideration? |
This sounds fragile, to be honest. Is the exact mechanism by which the split point is inferred documented? I know I was the one who disliked the double dash, but I'm just as uncomfortable with "do what I mean" semantics. I think this is a genuinely hard UI design problem, and my instinct is that what works best depends on your use case. What works best for "run a temporary Python interpreter session with requests and packaging installed" is very different from "run this script which has its dependencies embedded in it", IMO.
I would expect this to be something that could be set by a command line flag as well as an environment variable. If we did move this to be a pip subcommand, I'd also expect it to be configurable in the pip config file1. As this is essentially a cache, it would also be good to have some cache management (so the user can explicitly remove the cache if something changes, for example). Again, if this gets included in pip I'd expect this to be managed via something like Footnotes
|
How do you disable quiet mode? |
On reflection, I'm coming to the conclusion that the biggest problem for tools like It would be very easy to claim that pip's UI is too complex, and that's the root problem here, but that's just sidestepping the issue. The key point is that we (pip) maintain that users should call pip from their own program via a subprocess call, and yet we don't actually provide a CLI that's particularly easy to use that way. I don't have any good answers here, to be honest. Maybe what's needed is a wrapper library, that handles calling pip in a subprocess, and exposes a strictly limited set of options - basically just the ones that might be needed when doing a "simple" install into the current environment. Something like the following: def pip_install(
requirements: list[Requirement],
req_file: os.PathLike,
*,
indexes: list[URL] = [PyPI_URL],
find_links: list[URL|os.PathLike] = [],
verbosity: int = 0, # zero is "-q", 1 is "normal", 2+ is various levels of "-v"
allow_sdists: bool = False, # By default, only install wheels (via --only-binary :all:)
) -> subprocess.CompletedProcess That's a simple enough API that tools can expose the options via their own CLI, and yet covers the core functionality. I'm returning a CompletedProcess object, so clients can't display output "as it's written", but as a first draft I'm going to say YAGNI to anything more complex[^1]. People wanting fine control should run pip directly, and deal with the full CLI. There's also questions around whether such an API should respect the user's pip config file and/or environment variables, which would need to be sorted out. We could even offer such an API in pip itself - the idea would not be so much to start offering "pip as a library" features, but simply to make a statement on what command line options we expect to be "normal" for clients just wanting to offer "install something" capabilities. What do people think of this? Is it something that tools might use (cc @pypa/pip-committers @jaraco @pypa/pipx-committers @pypa/build-maintainers)? It's pointless putting effort into something like this if no-one would use it. But maybe it would give people an option that's easier to maintain than a "let the user include any pip options they want" capability. |
From pipx’s perspective, I would always prefer an official API like this, provided it can do everything we need it to do. In this case, it can’t (yet) since people want pipx to respect pip config files and environment variables. However, pipx already exists and is stable, so this certainly isn’t urgent for pipx even if it did have all the feature pipx needs. I.e. it’s questionable if it would actually get used by pipx. But I think it certainly would find plenty of uses by the Python community. In fact I am sure I’ve seen someone already build pip as a library which wraps pip subprocess calls. (Edit: this may have been what I was thinking of https://github.com/frostming/unearth by @frostming. It’s to find and download packages, but not install them. If you’re looking for use cases, this is one.) From pip’s perspective, if this delivers a “pip run”-like functionality (or ”pipx-run”?) I think that is a step in the right direction too. Ultimately I’d like to see pipx bundled into pip (as npm ships with npx) or its functionality absorb into pip (making pipx redundant). |
Do you have details of precisely which pip config files/environment variables people want to be respected? The big problem here is that there's simply no point in wrapping all of pip's options, as that just leaves us with another equally complex interface. Whereas if we can identify a (much) smaller set of options that callers like pipx actally need, there's a potential benefit. As an example, I can't imagine pipx working properly if a user specified What I'm trying to do here is work out if there's a suitably limited subset of pip's options that would be sufficient for users (of pip) like pipx. What I'm hearing is that no, you want to expose all pip options. Which makes the idea of a "pip wrapper" unlikely to be worth the effort.
My problem is that at the moment, the big frustration for me is that tools like pipx and pip-run are coming up with messy UIs to allow the user to control pip, basically exposing pip's command line options and config mechanisms as a subset of their own CLI. That doesn't seem like a reasonable approach to me, but the only alternative people seem to be suggesting is "let's merge this functionality into pip". And frankly, that seems to me to be a very bad reason for adding functionality to pip (and one that as a maintainer, I don't really want to support). I don't know much (nothing, really) about npm/npx, so I don't know how they solved this issue. I do note that |
The changelog provides some guidance, and your instinct is right that
Currently, the only Is it possible that you're not seeing any output either because you've enabled |
I'd like to see that too FWIW!
When you install NodeJS, you get https://docs.npmjs.com/cli/v9/commands/npx has a good overview of the exact behaviours. |
Getting back to this question, we need to look at, not the UI of We'll need to define the precise option structure for I'd imagine that Personally, I think we're close enough that we need to explore in detail the ways in which this isn't going to just be "copy the |
I personally feel more strongly -- this would be among the worst ways of doing this. This has been suggested for pip-audit as well, and IMO the answer is the same as it was for that: the functionality we want to add to pip would have to be absorbed into pip (and adapted within the context of pip itself, as necessary without major breakage ideally) and all future development of that functionality would need to move into pip; with the external implementation effectively ceasing development. I especially do not want there to be a different public PyPI package which is where "new" functionality and other things are developed, before bringing them into The rationale is primarily based on reducing the effort around co-ordinating development, reducing duplicated effort, not delegating entire subsets of pip's functionality to a project maintained outside of it (I have UX concerns around that) and the vast potential for user confusion; especially if implementation diverge for any reason. |
Not as far as I know. Looking a bit further, I was running It looks like
Note that although I don't know what should happen as far as |
I'm not proposing to merge
In the previously-proposed pull request, The
I'd be open to this. My intention was that there would likely be a small period of overlap where I'd expected that I would have an outsized stake in maintaining the 'run' command within pip, but that it's design would be influenced more from users than from myself. |
This concern makes a lot more sense when pip-run is part of pip, as the user would expect it to run in whatever environment pip was invoked. Correct, you probably shouldn't use
(but for that to work, pip-run needs to be present alongside pip in each Python) |
And it seems to support my suspicion that npm/npx simply don't have all of the config options on the command line that pip has. Maybe that's something we could consider - drop a bunch of command line options in favour of only allowing them to be set via I can hear them all collecting the tar and feathers for me now... 🙂 |
... which would be almost completely negated for me by the need to have |
Which is the whole point of this issue. Since users have pip installed in every environment, they would have |
I like this. It makes the mental model of the code simpler. It makes maintenance simpler. It seems like a potentially decent trade off between being able to ship a feature to provide user value, as well as being able to maintain sanity as a maintainer. (I say this as someone with basically no skin in the game though, as I’m not a pip maintainer, and after having a child have been unable to do any open source work). |
/me nods. TBH, it'd be weird if this weren't the case. ;) From #3971 (comment):
I empathize and largely agree -- with the caveat that I've not used pip-run personally and don't know if the best direction to go here is its current CLI. I really do like the idea of All this to say: I feel similarly, but I am also wary of pigeon-holing ourselves into a tricky/difficult-to-maintain thing for all of us. :) |
FWIW, why was I'm imagining that some of the UX concerns raised here would've been easier to deal with it, if we didn't have to actively aim for an in-place substitution; and I just realised that this rename was the point where that constraint was effectively added into this effort. |
I don't consider this consequence to be "elegant", I'm afraid:
(It's even worse if the user has
Then I guess I'm -1 on this proposal. I think
As @pradyunsg has noted, that's a non-starter. Apart from anything else, I just saw the list of dependencies that |
Just because you happened to find an edge case that's inelegant isn't indicative that the interface is inherently broken. Indeed, pip has the same bug:
There's a case to be made that perhaps pip-run should explicitly disallow
The dependencies were added after it became apparent that pip was unlikely to adopt this functionality. For a long time, I maintained pip-run without any dependencies. I'd imagine any renewed effort to integrate the behavior would need to roll back these changes or re-implement the behavior. As an aside, Pydantic was added because the CPython core devs recommended it as a solution to a problem I presented at the Python Language Summit. Unlike pip-run, pipx works great as an installed application, and can even install itself, but not without some bootstrapping. Here's how I use pip-run to install boostrap pipx:
Imagine how nice it would be for pipx to be able to present that as an installation technique (with It really feels like there's no path to a solution here. I've made several concerted efforts to align this project with the visions of the PyPA, to solve the critiques and to come up with a solution that fits, but I continue to meet resistance from members who haven't even tried it or who seem to have only tried it in anger. I thought Paul would be excited that I address all four top critiques about the UI, even if not the way he would have done it. I appreciate that Paul has actually tried using pip-run, despite it having been presented for experimentation for years, but it doesn't feel like anybody has really tried to understand the general value that pip-run promises. I'm finding this discussion too hostile and emotionally taxing. I repeatedly get my hopes up only to be let down with more roadblocks. I'm going to unsubscribe from this conversation. If the team can decide that they're prepared to accept pip-run as pip run in some form (and in roughly what form), please feel free to loop me back in. |
FWIW, I think |
@jaraco, apologies if I came across as hostile. I think we simply have very different views of what a In the interests of being explicit, and but hopefully not as a way of dumping more requirements on this work1, my key requirements for a
I also think we need to be clear that once merged, "ownership" of the design and ongoing evolution of the
Again, in the interests of being explicit, I don't personally expect
Yeah, agreed. It was the easiest one to demonstrate, is all. My point is that certain On a somewhat related note, I will say that I've been getting increasingly frustrated with core Python's poor support for users who want to publish simple scripts with a few dependencies. Basically the target audience for a Footnotes
|
In an effort to obviateI've created rwt. If you're not familiar with rwt, take a look at that readme, which describes its purpose and gives some examples.easy_install
(including implicit invocations such assetup_requires
directives),I've been using
rwt
in my daily workflows and I'm finding it quite powerful as a bootstrapping tool. However, it suffers from the same bootstrapping problem assetuptools
andpip
andvirtualenv
-- you have to install it before it's available to use it, so breaks the 'one step' workflows and adds a step to the instructions you give to someone (install python, install pip, install rwt, run this command).I'd like to consider bundling rwt with pip as the
pip run
command. Sincerwt
is mostly a thin wrapper aroundpip
and its parameters are passed directly topip install
, it makes sense as a pip command, and adding it as a command to pip would solve the bootstrapping issue. The functionality would also then be available during pip install,potentially eliminating the.setup_requires
reliance oneasy_install
(or at least supporting aneasy_install
-free option)So I'm proposing two things:
rwt
aspip run
and make it the pypa-endorsed mechanism for on-demand dependency resolution.Inpip install
when building a source dist, invokesetup.py
using rwt.In the short term, the
pip run
command can be used for bootstrapping or test runs or whatever ad-hoc requirements one might have.discarded approach
Once this functionality has established more thoroughly and packagers can rely on all pip versions having this functionality, they could eliminate the reliance on distutils altogether and use whatever dependencies they require to build their package. Consider the
pbr
use case. Instead of invokingsetuptools.setup()
in their setup.py, they do this:Where
pbr
might have dependencies on setuptools or distutils and and invoke that behavior, or perhaps they use another build system. Additionally, pip might be able to eschew the responsibility of supplying setuptools. If a script wants to rely on setuptools, it can require that:That last bit (pip without setuptools bundled) makes my heart glow a little. Think it over, maybe try out rwt, and let me know what you think. I plan to put together a PR after addressing any concerns.
The text was updated successfully, but these errors were encountered: