9

I am writing a program that needs to install dependencies using pip. What is the proper way to do it and why?

Ideally it needs to be platform agnostic, but the program will be running on a Linux machine.

Method 1: pip.main()

import pip
args = ['param1', 'param2']
version = 0.1
package = ['some_package=={}'.format(version)]
pip.main(['install'] + args + package) 

Method 2: subprocess.call()

import subprocess
import sys
version = 0.1
package = 'some_package'

subprocess.call([sys.executable, '-m', 'pip', 'install', '{}=={}'.format(package, version)])
turnip
  • 2,246
  • 5
  • 30
  • 58

5 Answers5

9

In general

Do not call somebody else's main() unless you want to give them ownership of the process. They could, for example, call sys.exit() or one of the os.exec*() functions. They could also install signal handlers, change the umask, or make all sorts of other global changes to your process's state. If you don't want them to do such things, you should run their code in a subprocess instead.

(Of course, library code can do all of the above just as easily, but it's considered "rude" to do so without documenting it, whereas the author of a main() function typically assumes they have the whole process to themself.)

For Pip in particular

pip.main() is not a public interface, and is unsupported. Use a subprocess.

Kevin
  • 28,963
  • 9
  • 62
  • 81
2

It depends. pip is undocumented and may not be backwards compatible. I recommend using subprocess instead, as the basic semantics of pip are unlikely to be changed in the near future.

Daniel
  • 769
  • 8
  • 21
0

Looking at PEP 338, and the pip python source, it seems python -m pip [args] is equivalent to import sys, pip; sys.exit(pip.main(*args)). So either option should work without a problem.

I'd prefer calling main() directly, because it's one less level of complication.

That said, pip.main() is not a public interface, so it may change in future releases. So that would argue for using a subprocess call.

jakevdp
  • 77,104
  • 11
  • 125
  • 160
0

I hope Its not so late... :) This is how I would use subprocess and pip with multiple options during package installation. These options can be stored in pip.ini file aswell.

import subprocess

pkg =<package to install>
subprocess.call([sys.executable,'-m', 'pip', 'install','--trusted-host=pypi.org', '--trusted-host=files.pythonhosted.org', pkg])

-1

as of 10.0 pip.main() is not supported/exposed, so instead you can use a work around as

def install_module(mod):
    from pip import _internal as pip
    pip.main(['install', mod])
bhavin
  • 122
  • 7