包的结构也可以作为命令行脚本运行

时间:2018-12-20 09:35:08

标签: python python-3.x command-line argparse python-packaging

我已经用the 'standard' minimal structure编写了一个程序包。看起来像这样:

my_package/
    my_package/
        __init__.py
    setup.py

__init__.py包含一个类,因此可以像预期的那样简单地导入和使用。

但是,代码确实适合在命令行中使用,例如

python my_package --arg1 "I like bananas."

首先,我刚刚在if __name__ == '__main__'中进行了__init__的签入,然后将使用argparse。这个有用,但是它不是很漂亮,因为这意味着您可以像这样从命令行调用它:

python my_package/__init__.py --arg1 "I like bananas."

据我了解,这是一个__main__.py文件所在的位置,它将作为文件夹内的默认脚本执行(类似于网站上的index.html文件)。我的想法是然后简单地导入__init__.py,运行argparse并将参数提供给类构造函数。像这样:

import argparse
from __init__ import MyClass

parser = argparse.ArgumentParser()
parser.add_argument("--arg1", help="Some dummy value")

args = parser.parse_args()
my_class = MyClass(**vars(args))
my_class.do_stuff()

这是应该如何构造相似的程序包,还是有更好的方法?


上面的作品但是 PyCharm告诉我,__main__.py __init__是一个未解决的引用。在该导入行上与MyClass相同。当我改用.__init__(带点)时,警告消失了,但是代码不再起作用,给了我ImportError: attempted relative import with no known parent package

1 个答案:

答案 0 :(得分:4)

我想为您建议一个不同的结构:

my_package/
    my_package/
        __init__.py
        cli_scripts.py
    setup.py

让我们假设您的__init__.py如下所示(作为补充,我建议将其中定义的类移动到单独的文件中,然后将其导入__init__中):

class Test(object):

    def __init__(self, a)
        self.a = a

    def __call__(self):
        print(self.a)

现在,程序包中还有一个附加文件,它利用了您在程序包中实现的内容,我们将其称为cli_scripts.py

import argparse

from my_package import Test


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("a", type=int, help="Just an example argument")
    return parser.parse_args()

def demonstration():
    args = parse_args()
    t = Test(a=args.a)
    t()

我现在的建议是利用setup.py中的console_scripts entry point,现在看起来像这样:

from setuptools import setup

setup(
    name='testpy',
    version='0.1',
    description='Just an example',
    author='RunOrVeith',
    author_email='xyz@mailinator.com',
    packages=["my_package"],
    entry_points={
        "console_scripts": ["mypkg=my_package.cli_scripts:demonstration"]},
    install_requires=[],
)

现在,当您在顶级pip install .文件夹中运行my_package时,将安装软件包。 entry_points将自动为您生成一个可执行文件,您现在可以使用在setup.py(在本示例中为mypkg)中为其指定的名称进行调用。这意味着您现在可以运行

mypkg 5 这将称为demonstration()

这种方式:

  • 您不需要处理任何__main__个文件
  • 您可以给脚本起一个有意义的名称
  • 您无需担心脚本是否可执行,也不必指定使用python运行脚本
  • 列表entry_points内可以有任意数量的
  • 它迫使您编写也可以从其他模块调用的函数, 而不是__main__

我认为这很干净。 您可以在this blog中阅读有关entry_points的更多信息,它具有更多功能! 如果您想使用__main__中指定的代码而不是这种cli_scripts方法,可以看看this question