带有 Click 库的 Python 3.6 中没有模块错误

新手上路,请多包涵

我正在尝试使用包 click 在 python 中构建 CLI。我使用的 Python 版本是 3.6

这是我的应用程序的主要部分:

 import os
import click

cmd_folder = os.path.join(os.path.dirname(__file__), 'commands')

class IAMCLI(click.MultiCommand):

    def list_commands(self, ctx):
        rv = []
        for filename in os.listdir(cmd_folder):
            if filename.endswith('.py') and \
                    filename.startswith('cmd_'):
                rv.append(filename[4:-3])
        rv.sort()
        return rv

    def get_command(self, ctx, cmd_name):
        ns = {}
        fn = os.path.join(cmd_folder, 'cmd_{}.py'.format(cmd_name))
        with open(fn) as f:
            code = compile(f.read(), fn, 'exec')
            eval(code, ns, ns)
        return ns['cli']

@click.command(cls=IAMCLI)
@click.option('--env', default='dev', type=click.Choice(['dev', 'staging', 'production']),
              help='AWS Environment')
@click.pass_context
def cli():
    """AWS IAM roles and policies management CLI."""
    pass

if __name__ == '__main__':
    cli()

这是树:

 ├── cli
│   ├── __init__.py
│   ├── aws
│   │   ├── __init__.py
│   │   ├── policy.py
│   │   └── role.py
│   ├── cli.py
│   └── commands
│       ├── __init__.py
│       └── cmd_dump.py

cmd_dump.py 看起来像这样:

 import click

from cli.aws.role import fetch_roles

@click.command('dump', short_help='Dump IAM resources')
@click.pass_context
def cli():
  pass

问题是,当我尝试运行 python cli/cli.py --help 这就是我得到的:

 File "cli/commands/cmd_dump.py", line 3, in <module>
    from cli.aws.role import fetch_roles
ModuleNotFoundError: No module named 'cli.aws'; 'cli' is not a package

对此有什么想法吗?

原文由 Mazzy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 384
2 个回答

在开始开发新的 python 项目时,我将尝试根据我的方法给出另一个答案。您打算分发您的项目,还是只是与某人分享?如果你这样做,你怎么看 - 这个人会因为需要记住命令而感到高兴吗

$ python path/to/project/codebase/cli/cli.py --help

使用你的工具?记住命令对他来说不是更容易吗?

 $ cli --help

反而?

我建议您立即开始打包您的项目 - 编写一个最小的安装脚本:

 from setuptools import setup, find_packages

setup(
    name='mypkg',
    version='0.1',
    packages=find_packages(),
    install_requires=['click'],
    entry_points={
        'console_scripts': ['cli=cli.cli:cli'],
    },
)

当出现新需求时,您始终可以增强设置脚本。将设置脚本放在代码库的根目录中:

 ├── setup.py
├── cli
│   ├── __init__.py
│   ├── aws
...

现在运行 python setup.py develop 或者更好, pip install --editable=. 1从代码库根目录( setup.py 脚本所在的位置)。您已经在开发模式下安装了您的项目,现在可以调用

$ cli --help

所有进口都得到正确解决(这将解决您的问题)。但除此之外,您获得了更多 - 您获得了一种打包项目以准备分发给目标用户的方法,以及一个干净的命令行界面,您的用户将以与您刚才相同的方式调用该界面。

现在继续项目开发。如果您更改 cli 命令的代码,它将即时应用,因此您无需在每次更改任何内容时都重新安装项目。

一旦您准备好项目开发并希望将其交付给您的用户,请发出:

 $ python setup.py bdist_wheel

这会将您的项目打包成一个可安装的 wheel 文件(您需要安装 wheel 包才能调用命令: pip install wheel --user )。通常它将位于代码库根目录的 dist 子目录中。将此文件提供给用户。要安装文件,他会发出

$ pip install Downloads/mypkg-0.1-py3-none.whl --user

并且可以立即开始使用您的工具:

 $ cli --help

这是一个非常简化的描述,有很多东西需要学习,但也有大量有用的材料可以指导您完成整个过程。

如果您想了解有关该主题的更多信息:作为快速入门参考,我会推荐出色的 PyPA 打包指南。对于打包 click 命令, 他们自己的文档 绰绰有余。


  1. 我鼓励您在适用的情况下使用 pip 进行分发和打包开发,因为它是一个标准工具。

原文由 hoefling 发布,翻译遵循 CC BY-SA 3.0 许可协议

不要在包内运行脚本!包是用来在代码中导入的,但不能在其中运行脚本。其余与导入错误无关。

例如:

 ├── cli # package
│   ├── __init__.py
│   ├── aws
│   │   ├── __init__.py
│   │   ├── policy.py
│   │   └── role.py
│   ├── cli.py
│   │   └── commands
│   │       ├── __init__.py
│   │       └── cmd_dump.py
├── run_this_module.py

要执行的模块 run_this_module.py

 import cli

"""Do your code here"""

原文由 Elis Byberi 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题