【问题标题】:Include python module (dependencies) installation in your python script在您的 python 脚本中包含 python 模块(依赖项)安装
【发布时间】:2014-11-22 18:52:23
【问题描述】:

有没有办法在运行实际/主脚本之前先包含/调用 python 模块(依赖项)安装?

例如在我的 main.py 中:

import os, sys
import MultipartPostHandler

def main():
    # do stuff here

但是 MultipartPostHandler 还没有安装,所以我想要的是先安装它 实际运行 main.py ......但以自动化方式。当我说自动时,我的意思是我只会调用一次脚本来启动依赖项安装,然后是主脚本的实际功能。 (不知怎么的,和maven有点类似。但我只需要安装部分)

我已经了解 setuptools 的基础知识。问题是我可能不得不分别调用安装(setup.py)和主脚本(main.py)。

非常感谢任何想法。提前致谢!

【问题讨论】:

  • 什么是python版本? python 2 还是 3?
  • 感谢您的回复。这是 python 2.7 先生

标签: python python-module


【解决方案1】:

有没有办法在运行实际/主脚本之前先包含/调用 python 模块(依赖项)安装?

  • 一个好方法是使用setuptools 并在install_requires 中明确列出它们。
  • 由于您提供了main 函数,您可能还想提供entry_points

我已经了解 setuptools 的基础知识。问题是我可能不得不分别调用安装(setup.py)和主脚本(main.py)。

这通常不是问题。首先使用requirements.txt 文件和pip install -r requirements.txt 安装所有东西是很常见的。另外,如果您列出依赖项,那么您可以有合理的期望,即当您的函数被调用时它会在那里,而不是依赖于try/except ImporError。期望存在必需的依赖项并仅将try/except 用于可选依赖项是一种合理的方法。

设置工具 101:

创建一个像这样的树结构:

$ tree
.
├── mymodule
│   ├── __init__.py
│   └── script.py
└── setup.py

您的代码将归入mymodule;让我们想象一些执行简单任务的代码:

# module/script.py    

def main():
    try:
        import requests
        print 'requests is present. kudos!'
    except ImportError:
        raise RuntimeError('how the heck did you install this?')

这是一个相关的设置:

# setup.py

from setuptools import setup
setup(
    name='mymodule',
    packages=['mymodule'],
    entry_points={
        'console_scripts' : [
            'mycommand = mymodule.script:main',
        ]
    },
    install_requires=[
        'requests',
    ]
)

这将使您的main 可作为命令使用,这还将负责安装您需要的依赖项(例如requests

~tmp damien$ virtualenv test && source test/bin/activate && pip install mymodule/
New python executable in test/bin/python
Installing setuptools, pip...done.
Unpacking ./mymodule
  Running setup.py (path:/var/folders/cs/nw44s66532x_rdln_cjbkmpm000lk_/T/pip-9uKQFC-build/setup.py) egg_info for package from file:///tmp/mymodule

Downloading/unpacking requests (from mymodule==0.0.0)
  Using download cache from /Users/damien/.pip_download_cache/https%3A%2F%2Fpypi.python.org%2Fpackages%2F2.7%2Fr%2Frequests%2Frequests-2.4.1-py2.py3-none-any.whl
Installing collected packages: requests, mymodule
  Running setup.py install for mymodule

    Installing mycommand script to /tmp/test/bin
Successfully installed requests mymodule
Cleaning up...
(test)~tmp damien$ mycommand 
requests is present. kudos!

更多有用的带有 argparse 的命令:

如果你想使用argparse 那么...

# module/script.py

import argparse

def foobar(args):
    # ...

def main():
    parser = argparse.ArgumentParser()
    # parser.add_argument(...)
    args = parser.parse_args()
    foobar(args)

【讨论】:

  • 非常感谢您的全面回答。非常感谢它dnozay
  • 问题,如果我的主要期望来自 argparse 的参数怎么办?我必须在 entry_points 下指定一些东西吗?提前致谢!
  • 您可以将 argparse 列为依赖项或检查 python >= 2.7,然后在您的 main 函数中构建解析器并调用它。而不是将代码放在模块主体中的某个位置,例如if __name__ == '__main__': 你可以把它放在console_scripts 公开的函数中。
  • 再次感谢您。但希望,你能显示 sn-p 代码吗?如果不是太多要求。谢谢
  • 对于那些正在寻找参考链接的人,可以在这里找到:setuptools.readthedocs.io/en/latest/…
【解决方案2】:

有几种方法可以做到这一点。一种方法是用try...except ImportError 块包围import 语句,然后如果引发ImportError 异常,则使用一些Python 代码安装包,例如:

try:
    import MultipartPostHandler
except ImportError:
    # code that installs MultipartPostHandler and then imports it

我认为这种方法不是很干净。另外,如果还有其他不相关的导入问题,则不会在此处检测到。更好的方法可能是使用bash 脚本来检查模块是否已安装:

pip freeze | grep MultipartPostHandler

如果没有,安装模块:

pip install MultipartPostHandler

然后我们就可以安全地运行原始 Python 代码了。

编辑:实际上,我更喜欢 FLORET 的回答。 imp 模块正是您想要的。

【讨论】:

    【解决方案3】:

    您应该使用imp 模块。这是一个例子:

    import imp
    import httplib2
    import sys
    
    try:
      import MultipartPostHandler
    except ImportError:
      # Here you download 
      http = httplib2.Http()
      response, content = http.request('http://where_your_file_is.com/here')
      if response.status == 200:
        # Don't forget the right managment
        with open('MultipartPostHandler.py', 'w') as f:
         f.write(content)
        file, pathname, description = imp.find_module('MultipartPostHandler')
        MultipartPostHandler = imp.load_module('MultipartPostHandler', file, pathname, description)
      else:
        sys.exit('Unable to download the file')
    

    对于完整的方法,请使用队列:

    download_list = []
    try:
        import FirstModule
    except ImportError:
        download_list.append('FirstModule')
    
    try:
        import SecondModule
    except ImportError:
        download_list.append('SecondModule')
    
    if download_list:
        # Here do the routine to dowload, install and load_modules
    
    # THe main routine
    def main():
        the_response_is(42)
    

    您可以使用open(file_content, 'wb')下载二进制文件

    希望对你有帮助

    BR

    【讨论】:

    • 这个答案没有解释为什么它是一个好方法。我当然不希望我的脚本在运行时开始下载额外的数据并从 Internet 导入。
    • @dnozay 我同意,我永远不会写这样的东西,主要是出于安全原因;)但有时,有一个小东西叫做现实,你知道日常工作、老板、客户......好的响应是代码工作时(我的响应)。最好的回应是你的。
    猜你喜欢
    • 1970-01-01
    • 2016-06-10
    • 2010-10-20
    • 2019-05-24
    • 1970-01-01
    • 2021-03-04
    • 1970-01-01
    • 1970-01-01
    • 2018-05-22
    相关资源
    最近更新 更多