如何从需要的脚本内部安装丢失的python包?

hec6srdp  于 2023-01-19  发布在  Python
关注(0)|答案(5)|浏览(150)

假设您已经在python发行版上安装了pip或easy_install,我想知道如何从脚本本身在用户目录中安装所需的包。
据我所知,pip也是一个python模块,因此解决方案应该如下所示:

try:
    import zumba
except ImportError:
    import pip
    # ... do "pip install --user zumba" or throw exception   <-- how?
    import zumba

我所缺少的是在python内部执行“pip install --user zumba”,我不想使用os.system()执行此操作,因为这可能会产生其他问题。
我想有可能...

jckbn6z7

jckbn6z71#

更新为较新的pip版本(〉= 10.0):

try:
    import zumba
except ImportError:
    from pip._internal import main as pip
    pip(['install', '--user', 'zumba'])
    import zumba

多亏了@Joop,我才能想出正确的答案。

try:
    import zumba
except ImportError:
    import pip
    pip.main(['install', '--user', 'zumba'])
    import zumba

一个重要的注意事项是,这将工作,而不需要根访问,因为它将安装在用户目录中的模块。
不确定它是否适用于二进制模块或需要编译的模块,但它显然适用于pure-python模块。
现在您可以编写自包含的脚本,而不必担心依赖关系。

14ifxucb

14ifxucb2#

自pip version〉= 10.0.0起,由于内部包重组,上述解决方案将无法工作。现在在脚本中使用pip的新方法如下:

try: import abc
except ImportError:
    from pip._internal import main as pip
    pip(['install', '--user', 'abc'])
    import abc
e37o9pze

e37o9pze3#

我想指出的是,当前接受的答案可能会导致应用程序名称冲突。从应用程序名称空间导入并不能给予您了解系统上安装了什么。
更好的方法是:

import pip

packages = [package.project_name for package in pip.get_installed_distributions()]

if 'package' not in packages:
    pip.main(['install', 'package'])
huwehgph

huwehgph4#

请勿使用pip.mainpip._internal.main

直接引自正式文件(黑体强调和编辑意见为本人,斜体为本人):
如前所述,pip是一个命令行程序。虽然它可以通过import pip从Python代码中获得,但您不能以这种方式使用pip的内部API。原因有很多:

  1. pip代码假定[它]单独控制程序的全局状态。pip管理诸如...之类的事情,而不考虑用户代码可能受到影响的可能性
  2. pip的代码 * 不是 * 线程安全的。如果你在一个线程中运行pip,不能保证你的代码或pip的代码能像你期望的那样工作。
  3. pip假定一旦完成其工作,进程将终止...在同一进程中两次调用pip可能会出现问题。
    这并不意味着pip开发人员原则上反对pip可以用作库的想法--只是它不是这样编写的,而且要重新设计内部组件以用作库(带有)稳定的API需要大量工作。而且我们目前根本没有资源......
    ...[E] pip内部的所有内容都被视为实现细节。甚至导入名称pip也可能会更改,恕不另行通知。虽然我们会尽可能不破坏某些内容,但所有内部API都可以随时更改,无论原因为何**..
    ...[I]在运行的Python进程中将包安装到sys.path中是应该小心完成的事情。导入系统会缓存某些数据,并且在程序运行时安装新包可能并不总是按预期运行
    以上所述[:]最可靠的方法,也是完全受支持的方法,是在子流程中运行pip。使用标准的subprocess模块可以很容易地做到这一点:
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'my_package'])

报告接着介绍了其他更适合解决相关问题的工具和办法。

zhte4eai

zhte4eai5#

一个基于上述内容的简单函数,它将模块名作为字符串并返回导入的模块。

def pipInstallOnError(module_name):
    '''Import a module.
    Attempt to pip install the module on ImportError.

    :Parameters:
        module_name (str) = The name of the module.

    :Return:
        (obj) The imported module.
    '''
    try:
        return __import__(module_name)
    except ImportError as error:
        from pip._internal import main as pip
        pip(['install', '--user', module_name])
        return __import__(module_name)

相关问题