9

我想编写一个脚本来自动设置一个全新的 ubuntu 安装并安装一个基于 django 的应用程序。由于脚本将在新服务器上运行,因此 Python 脚本需要自动安装一些必需的模块。

这是脚本。

#!/usr/bin/env python

import subprocess
import os
import sys

def pip_install(mod):
    print subprocess.check_output("pip install %s" % mod, shell=True)

if __name__ == "__main__":
    if os.getuid() != 0:
        print "Sorry, you need to run the script as root."
        sys.exit()

    try:
        import pexpect
    except:
        pip_install('pexpect') 
        import pexpect        

    # More code here...

安装pexpect成功,但是下一行import pexpect失败。我认为这是因为在运行时代码不知道新安装的pexpect.

如何在运行时安装和导入 Python 模块?我对另一种方法持开放态度。

4

5 回答 5

9

您可以导入 pip 而不是使用子进程:

import pip

def install(package):
    pip.main(['install', package])

# Example
if __name__ == '__main__':
    try:
        import pexpect
    except ImportError:
        install('pexpect')
        import pexpect

另一种做法:

import pip

def import_with_auto_install(package):
    try:
        return __import__(package)
    except ImportError:
        pip.main(['install', package])
    return __import__(package)

# Example
if __name__ == '__main__':
    pexpect = import_with_auto_install('pexpect')
    print(pexpect)

[编辑]

您应该考虑将requirements.txt与 pip 一起使用。好像您正在尝试自动化部署(这很好!),在我的工具带中,我还有 virtualenvwrapper、vagrantansible

这是我的输出:

(test)root@vagrant:~/test# pip uninstall pexpect
Uninstalling pexpect:
  /usr/lib/python-environments/test/lib/python2.6/site-packages/ANSI.py
  /usr/lib/python-environments/test/lib/python2.6/site-packages/ANSI.pyc
  /usr/lib/python-environments/test/lib/python2.6/site-packages/FSM.py
  /usr/lib/python-environments/test/lib/python2.6/site-packages/FSM.pyc
  /usr/lib/python-environments/test/lib/python2.6/site-packages/fdpexpect.py
  /usr/lib/python-environments/test/lib/python2.6/site-packages/fdpexpect.pyc
  /usr/lib/python-environments/test/lib/python2.6/site-packages/pexpect-2.4-py2.6.egg-info
  /usr/lib/python-environments/test/lib/python2.6/site-packages/pexpect.py
  /usr/lib/python-environments/test/lib/python2.6/site-packages/pexpect.pyc
  /usr/lib/python-environments/test/lib/python2.6/site-packages/pxssh.py
  /usr/lib/python-environments/test/lib/python2.6/site-packages/pxssh.pyc
  /usr/lib/python-environments/test/lib/python2.6/site-packages/screen.py
  /usr/lib/python-environments/test/lib/python2.6/site-packages/screen.pyc
Proceed (y/n)? y
  Successfully uninstalled pexpect
(test)root@vagrant:~/test# python test.py
Downloading/unpacking pexpect
  Downloading pexpect-2.4.tar.gz (113Kb): 113Kb downloaded
  Running setup.py egg_info for package pexpect
Installing collected packages: pexpect
  Running setup.py install for pexpect
Successfully installed pexpect
Cleaning up...
<module 'pexpect' from '/usr/lib/python-environments/test/lib/python2.6/site-packages/pexpect.pyc'>
(test)root@vagrant:~/test#
于 2013-06-21T12:12:48.580 回答
4

对于那些使用大于 10.x 的 pip 版本的人,没有main功能 forpip所以替代方法是使用import pip._internal as pip而不是import piplike :

保罗的更新答案

import pip._internal as pip

def install(package):
    pip.main(['install', package])

if __name__ == '__main__':
    try:
        import pexpect
    except ImportError:
        install('pexpect')
        import pexpect
于 2019-03-15T18:25:29.317 回答
3

我实际上为此目的制作了一个模块(impstall

它真的很容易使用:

import impstall
impstall.now('pexpect')
impstall.now('wx', pipName='wxPython')

问题/贡献的 Github 链接

于 2017-07-28T14:09:53.427 回答
2

imp我使用该模块解决了我的问题。

#!/usr/bin/env python

import pip
import imp

def install_and_load(package):
    pip.main(['install', package])

    path = '/usr/local/lib/python2.7/dist-packages'
    if path not in sys.path:
        sys.path.append(path)

    f, fname, desc = imp.find_module(package)
    return imp.load(package, f, fname, desc)

if __name__ == "__main__":
    try:
        import pexpect
    except:
        pexpect = install_and_load('pexpect')

    # More code...

实际上代码并不理想,因为我需要对 Python 模块目录进行硬编码。但由于该脚本适用于已知的目标系统,我认为没关系。

于 2013-06-21T14:05:35.137 回答
1

我有同样的问题,但谷歌的搜索都没有帮助。经过几个小时的调试,我发现可能是因为sys.path没有重新加载新的安装目录。

在我的 Ubuntu Docker 上,我想import dns.resolver在运行时使用 Python3.8(预安装)。我还创建了ubuntu用户并使用该用户运行所有东西(包括我的 Python 脚本)。

  • 在安装之前,sys.path没有,/home/ubuntu/.local/lib/python3.8/site-packages因为我没有安装任何东西。
  • 在使用subprocesspip.main类似方式安装时,它会创建/home/ubuntu/.local/lib/python3.8/site-packages(作为用户安装)。
  • 安装后,sys.path应刷新以包含此新位置。

由于sys.path是由site模块管理的,我们应该重新加载它(参考这里):

    import site
    from importlib import reload
    reload(site)

任何需要的人的完整块:

import subprocess
import sys

try:
    import dns.resolver
except ImportError:
    subprocess.check_call([sys.executable, "-m", "pip", "install", "dnspython"])
    import site
    from importlib import reload
    reload(site)
    import dns.resolver

我不是 Python 开发人员,所以这些代码可以进一步简化。对于像我这样的 DevOps 工程师来说,这可能会在新的 CI/CD 环境等情况下有所帮助。

于 2021-10-12T14:30:38.090 回答