簡體   English   中英

使用Python和Click創建shell命令行應用程序

[英]Creating a shell command line application with Python and Click

我正在使用click( http://click.pocoo.org/3/ )來創建命令行應用程序,但我不知道如何為此應用程序創建shell。
假設我正在編寫一個名為test的程序,我有一個名為subtest1subtest2的命令

我能夠從終端工作,如:

$ test subtest1
$ test subtest2

但我在考慮的是一個shell,所以我可以這樣做:

$ test  
>> subtest1  
>> subtest2

點擊可以實現嗎?

這不是不可能的點擊,但也沒有內置的支持。 首先要做的是通過將invoke_without_command=True傳遞給組裝飾器(如此處所述), 沒有子命令的情況下調用組回調。 那么你的組回調就必須實現一個REPL。 Python具有用於在標准庫中執行此操作的cmd框架。 使click子命令可用涉及覆蓋cmd.Cmd.default ,如下面的代碼片段所示。 正確地獲取所有細節,例如help ,應該可以在幾行中完成。

import click
import cmd

class REPL(cmd.Cmd):
    def __init__(self, ctx):
        cmd.Cmd.__init__(self)
        self.ctx = ctx

    def default(self, line):
        subcommand = cli.commands.get(line)
        if subcommand:
            self.ctx.invoke(subcommand)
        else:
            return cmd.Cmd.default(self, line)

@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
    if ctx.invoked_subcommand is None:
        repl = REPL(ctx)
        repl.cmdloop()

@cli.command()
def a():
    """The `a` command prints an 'a'."""
    print "a"

@cli.command()
def b():
    """The `b` command prints a 'b'."""
    print "b"

if __name__ == "__main__":
    cli()

我試圖做一些類似於OP的東西,但是有額外的選項/嵌套的子子命令。 使用內置cmd模塊的第一個答案在我的情況下不起作用; 也許有一些更多的擺弄..但我確實只是運行click-shell 沒有機會對其進行廣泛測試,但到目前為止,它似乎完全符合預期。

我知道這是超級老,但我一直在研究fpbhb的解決方案以支持選項。 我確信這可以使用更多的工作,但這是一個如何完成它的基本示例:

import click
import cmd
import sys

from click import BaseCommand, UsageError


class REPL(cmd.Cmd):
    def __init__(self, ctx):
        cmd.Cmd.__init__(self)
        self.ctx = ctx

    def default(self, line):
        subcommand = line.split()[0]
        args = line.split()[1:]

        subcommand = cli.commands.get(subcommand)
        if subcommand:
            try:
                subcommand.parse_args(self.ctx, args)
                self.ctx.forward(subcommand)
            except UsageError as e:
                print(e.format_message())
        else:
            return cmd.Cmd.default(self, line)


@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
    if ctx.invoked_subcommand is None:
        repl = REPL(ctx)
        repl.cmdloop()


@cli.command()
@click.option('--foo', required=True)
def a(foo):
    print("a")
    print(foo)
    return 'banana'


@cli.command()
@click.option('--foo', required=True)
def b(foo):
    print("b")
    print(foo)

if __name__ == "__main__":
    cli()

現在有一個名為click_repl的庫可以完成大部分工作。 我以為我會分享我的努力。

一個難點是你必須使用repl命令創建一個特定的命令,但是如果沒有提供另一個命令,我們可以重新調整@fpbhb的方法以允許默認調用該命令。

這是一個完全有效的示例,它支持所有單擊選項,包含命令歷史記錄,並且無需輸入REPL即可直接調用命令:

import click
import click_repl
import os
from prompt_toolkit.history import FileHistory

@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
    """Pleasantries CLI"""
    if ctx.invoked_subcommand is None:
        ctx.invoke(repl)

@cli.command()
@click.option('--name', default='world')
def hello(name):
    """Say hello"""
    click.echo('Hello, {}!'.format(name))

@cli.command()
@click.option('--name', default='moon')
def goodnight(name):
    """Say goodnight"""
    click.echo('Goodnight, {}.'.format(name))

@cli.command()
def repl():
    """Start an interactive session"""
    prompt_kwargs = {
        'history': FileHistory(os.path.expanduser('~/.repl_history'))
    }
    click_repl.repl(click.get_current_context(), prompt_kwargs=prompt_kwargs)

if __name__ == '__main__':
    cli(obj={})

以下是使用REPL的樣子:

$ python pleasantries.py
> hello
Hello, world!
> goodnight --name fpbhb
Goodnight, fpbhb.

並直接使用命令行子命令:

$ python pleasntries.py goodnight
Goodnight, moon.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM