如何构建一个简单的基于命令行的python项目

时间:2014-10-24 21:48:37

标签: python

我在单个文件app_name.py中编写了一个命令行应用程序,但它确实有效。现在我将它分解为不同的.py文件,以便于管理和可读性。我将所有这些py文件放在src/文件夹中,因为我在github上看到了很多。

app_name/
    src/
        file1.py
        file2.py
        cli.py
        __init__.py

我已将所有导入放入__init__.py from .file1 import function1中的相对导入不在__init__中,并且放在需要的单个文件中。例如,

#!usr/bin/env python
#__init__.py

import os
import argparse
#etc...

run_cli()

在cli.py中,我有

from .file1 import function1

def run_cli(): pass

if __name__ == '__main__':
    run_cli()

这是因为当我使用时,在实际的命令行app_name <arguments>上,__name__不是主要的,所以我在run_cli()中呼叫__init__.py。虽然这看起来并不正确,但我必须致电src而不是app_name

1 个答案:

答案 0 :(得分:2)

我认为你可能会混淆两件事。在您的源代码发布中有一个src目录是一个相当普遍,惯用的事情;在已安装的软件包或应用程序中使用它,而不是那么多。

有两种基本方法可以解决这个问题。


首先,您可以构建一个Python程序包,将程序包安装到site-packages中,并将脚本安装到Python脚本在PATH上的任何位置。 Python Packaging User Guide在其构建和分发包的教程中介绍了这一点。请参阅LayoutScripts部分以及从那里链接的示例。

这通常会为您提供如下安装的布局:

<...somewhere system/user/venv .../lib/pythonX.Y/site-packages>
    app_name/
        file1.py
        file2.py
        cli.py
        __init__.py

<...somewhere.../bin/>
    app_name

但是,根据用户选择安装东西的方式,它可能是鸡蛋,拉链包装,轮子或其他任何东西。只要您的代码有效,您就不在乎了。特别是,您的代码可以假设app_name是可导入的包。

理想情况下,路径上的app_name脚本是一个“入口点”脚本(pip本身可能是您系统上的一个很好的示例),理想情况下是在安装时即时构建的脚本。使用setuptools,您可以指定它应该导入哪个包以及它应该在该包中调用哪个函数,它将执行其他所有操作 - 确保在安装时实际使用Python,找出如何{{ 1}}将软件包添加到pkg_resources(默认情况下不需要,但如果您不希望它是可导入的,则可以使其工作),依此类推。

如原始提问者的评论中所述,python-commandline-bootstrap可能会帮助您更快地将此解决方案整合在一起。


另一种方法是将所有内容保留在网站包之外,并使包特定于您的应用。在这种情况下,您基本上想要做的是:

  • 安装一个包含软件包(作为目录或压缩)和包装脚本的目录。
  • 在包装器脚本中,在sys.path之前将dirname(abspath(argv[0]))添加到sys.path
  • 将包装器脚本符号链接到用户import上的某个位置。

在这种情况下,你必须手动编写包装脚本,但是你不需要任何花哨的东西。

但是,通常,您并不希望应用程序依赖于具有某些特定版本和Python设置的用户。您可能希望使用PATHpyInstallerpy2exepy2appcx_Freeze等工具来执行上述所有操作。他们都做了不同的事情,一直到构建Mac zc.buildout捆绑目录的极端,使用自定义的,独立的,剥离的Python框架和stdlib以及嵌入框架的包装器可执行文件。


无论哪种方式,您真的不想调用包目录.app。这意味着包本身将被命名为src,这不是一个好名字。如果您的应用被称为src,您希望在追溯中看到spamifier,而不是spamifier,对吧?