【问题标题】:When designing a CLI, how does one indicate that FILE is required (either by stdin or by argument)在设计 CLI 时,如何指示需要 FILE(通过标准输入或参数)
【发布时间】:2020-04-15 11:06:56
【问题描述】:

最好是看一个例子。

我希望我的 CLI 能够双向运行,如何在帮助文档中正确传达这一点?

Usage:
  my-cli import FILE
  my-cli import [FILE] (in case where stdin is used only)

例如

my-cli import test.xlsx

my-cli import < test.xlsx

在第二种情况下,未传递 FILE 标志(因此在我当前的实现中需要 FILE 会导致错误)。

放松约束会导致系统按预期工作,只是现在可以不传入文件并且不通过标准输入。

关于更多上下文,我正在开发一个 Django 管理 CLI(语法紧跟 argparse)。下面是一些代码,显示 FILE 是可选的场景。

    def add_arguments(self, parser):
        subparsers = parser.add_subparsers(
            title='commands', dest='command', help='command help')
        subparsers.required = True

        parser_import = subparsers.add_parser('import', help='import help')

        parser_import.add_argument('FILE', nargs='?', type=argparse.FileType('r'), default=sys.stdin)

nargs='?' 参数使帮助看起来像:

usage: manage.py my-cli import [-h] [FILE]

positional arguments:
  FILE

optional arguments:
  -h, --help  show this help message and exit

我正在寻找的是以某种方式调整我的代码,以便生成的./manage.py my-cli import --help 显示更理智的东西。此外,不通过标准输入传递任何内容或传递文件都会引发错误。

【问题讨论】:

  • 我发现一个'-'可以用来表示必须读取标准输入。所以我可以将其设为必填字段,然后确保用户使用 - 传递到标准输入。
  • IMO,没有理由允许路径作为参数。始终从标准输入读取。越简单越好。
  • @WilliamPursell 虽然这不会使用户更复杂。对于用户来说,my-cli import FILE 的选项比 my-cli import - < FILEmy-cli import < FILE 更简单。
  • my-cli < FILE 确实比my-clii FILE 长一个字符。 IMO,附加逻辑不会保存一个附加复杂性的字符。但是cmd | my-clicmd | my-cli - 简单,无法知道哪个是更常见的用例。后者很可能更常见。如果您只是从标准输入读取,一切都会变得更简单。
  • 在我的反对意见中,仅当文件系统被抽象出来或使用不便时才需要从 STDIN 读取,并且是与自动化脚本等一起使用的特殊情况。大多数 UNIX 工具都接受 FILE 作为参数,并为方便起见还允许使用 STDIN。

标签: python command-line-interface argparse manage.py


【解决方案1】:
  • 简单胜于复杂
  • 显式优于隐式

牢记这两个概念:

  1. 帮助将如下所示:
usage: manage.py my_cli import [-h] FILE

positional arguments:
  FILE        path to file, otherwise if "-", read from STDIN

optional arguments:
  -h, --help  show this help message and exit

这样,FILE 始终是必需的,如果不存在,则会抛出错误。 '-' 是一个显式占位符,用于表示标准输入将被传送到的参数。


结果,Django 代码看起来像这样:

    def add_arguments(self, parser):
        subparsers = parser.add_subparsers(
            title='commands', dest='command', help='command help')
        subparsers.required = True
        parser_import = subparsers.add_parser('import', help='import help')
        parser_import.add_argument('FILE', help='path to file, otherwise if "-", read from STDIN')

还有一个上下文管理器,可以描述“文件路径”的功能,否则如果为“-”,则从 STDIN 读取:


@contextlib.contextmanager
def file_ctx(filename: str) -> IO[bytes]:
    if filename == '-':
        yield io.BytesIO(sys.stdin.buffer.read())
    else:
        with open(filename, 'rb') as f:
            yield f

【讨论】:

    猜你喜欢
    • 2018-03-03
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-03
    相关资源
    最近更新 更多