I believe that at least some of these problems can be addressed given that pip *knows* that this import is an in-script import. So the list of corner cases will be shorter.


On Tue, Sep 20, 2016 at 1:35 PM Paul Moore <p.f.moore@gmail.com> wrote:
On 19 September 2016 at 23:46, אלעזר <elazarg@gmail.com> wrote:
>> import pip
>> pip.install('attrs')
>> import attr
> Please forgive me for my ignorance, but it doesn't work as written - what's
> the actual method?

As David Mertz said, pip.main(['install', 'attrs']) works right now,
but it is NOT a supported use of pip[1]. To be 100% explicit, the only
supported way of doing this is

import sys
from subprocess import run
run([sys.executable, '-m', 'pip', 'install', 'attrs'])

I suggested a hypothetical "pip.install" method as there is currently
some discussion on the pip tracker about providing a supported install
method. But it doesn't exist yet. Sorry for being confusing.

While on the whole subject of this, I should also point out that there
are a lot of potential issues with installing new packages while a
Python program is running. They are all low-probability, and easy to
avoid if you're not doing weird things, but for a generally-promoted
mechanism, we need to explain the corner cases[2], and an approach
with a list of caveats longer than the main documentation is

1. If the install fails, you need to catch that and report it to the
user, in a more friendly manner than pip's output. For example if the
user has no C compiler and you need a C extension to be built.
2. You quite possibly want to suppress pip's output if it's *not* a
failure, as it'll clutter up the program's real output.
3. If the code has already imported foo.bar, then you install a new
version of foo (there are discussions as to whether pip install foo
should automatically imply --upgrade, so even if it won't do that by
default now, it might in the future), and maybe that new version
doesn't have a bar submodule. So now you have a weird mix of old and
new code in your process.
4. The install mechanism sometimes (I can't recall the details) caches
the fact that it couldn't import a module. If it does that and then
later you pip install that module, imports will still fail because the
information is cached.

I'm still not at all clear why any of this is so much better than a
comment at the top of the script

# To run this script, you need to "pip install attrs" first


[1] We've had people report issues where pip breaks their logging
config, for example, because pip uses logging but doesn't expect to be
run from user code that also does so.
[2] That "run([sys.executable, ...])" invocation doesn't work in an
embedded program, for example, where sys.executable isn't "python".