【Python百宝箱】打造个性CLI应用:Python中最佳命令行开发实践

发布时间:2024年01月04日

深入浅出:Python命令行界面开发全攻略

前言

在现代软件开发中,命令行界面(CLI)作为一种直观且高效的交互方式,不断受到开发者的青睐。本文将带领读者探索Python中丰富的命令行界面开发工具与库,从简单到复杂,逐步介绍每个工具的特性、用法以及如何在项目中灵活应用。无论是初学者还是有一定经验的开发者,都能在这篇文章中找到适合自己的命令行界面开发工具。

【Python百宝箱】代码之外的艺术:精通命令行参数和日志记录在Python中的妙用

欢迎订阅专栏:Python库百宝箱:解锁编程的神奇世界

文章目录

1. Fire

1.1 Fire简介

Fire是一个由Google开发的命令行界面(CLI)开发工具,旨在使命令行应用程序的开发更加简单。它可以自动生成命令行接口,无需编写大量的解析代码。Fire基于Python装饰器和反射机制,使得开发者可以轻松地将Python代码转换为命令行工具。

1.2 特性与使用场景

Fire支持单个函数、类方法或整个对象的转换为命令。它提供了丰富的命令行参数处理和嵌套命令的支持。Fire适用于快速原型开发、交互式控制台和自动化任务等场景。

1.3 与现有项目集成
import fire

class Calculator:
    def add(self, x, y):
        return x + y

    def multiply(self, x, y):
        return x * y

if __name__ == "__main__":
    fire.Fire(Calculator)

在上述示例中,Calculator类中的add和multiply方法被转换为命令行接口。通过运行脚本,用户可以执行像python script.py add 3 5这样的命令。

1.4 Fire的高级特性:Command模块

Fire不仅可以将单个函数或类方法转换为命令,还提供了Command模块,用于更灵活地组织和管理命令行接口。通过继承fire.Command类,可以定义更复杂的命令行结构。以下是一个展示Fire的高级特性的示例:

import fire

class MathCommands:
    def add(self, x, y):
        return x + y

    def multiply(self, x, y):
        return x * y

class StringCommands:
    def greet(self, name):
        return f"Hello, {name}!"

class MyCLI(fire.Command):
    def __init__(self):
        super().__init__(name='mycli', context_settings={'help_option_names': ['-h', '--help']})
        self.add(MathCommands(), name='math', help='Math operations')
        self.add(StringCommands(), name='string', help='String operations')

if __name__ == "__main__":
    MyCLI()

在这个例子中,MathCommandsStringCommands分别表示数学和字符串操作,而MyCLI则组织了这两个命令模块。用户可以通过执行python script.py math add 3 5python script.py string greet John等命令调用相应的功能。

1.5 Fire与命令行参数的交互:自定义帮助信息

Fire允许开发者为每个命令和参数提供自定义的帮助信息,使得生成的命令行工具更具可读性和易用性。以下是一个示例,演示如何使用Fire的help参数定义帮助信息:

import fire

class CustomHelp:
    def command_with_help(self, x, y, _help="Perform a custom operation."):
        """This command demonstrates custom help."""
        return x + y

if __name__ == "__main__":
    fire.Fire(CustomHelp)

在这个例子中,command_with_help方法的_help参数用于定义该命令的自定义帮助信息。运行python script.py command_with_help --help将显示定义的帮助信息。

1.6 Fire与Python中其他库的集成:Fire + Click

Fire和Click是两个功能强大的命令行工具,它们可以很好地结合使用。下面的示例展示了如何使用Fire调用Click定义的命令:

import fire
import click

@click.command()
@click.argument('name')
def greet(name):
    """This command uses Click for argument parsing."""
    click.echo(f"Hello, {name}!")

if __name__ == "__main__":
    fire.Fire(greet)

这个例子中,greet命令由Click定义,但通过Fire可以轻松调用。这种结合使用的方式使开发者能够充分发挥两者的优势。

2. Click

2.1 Click概述

Click是一个功能强大而易于使用的Python库,用于创建命令行界面。它提供了简洁的API,允许开发者定义命令、参数和选项,以及处理用户输入。

2.2 命令行解析

Click使用装饰器来定义命令和参数。通过装饰器@click.command()定义一个命令,使用@click.argument()定义参数。

2.3 自定义命令与参数

Click支持复杂的命令结构,包括子命令和多级嵌套。自定义参数类型和默认值也是Click的强大功能。

2.4 高级功能
import click

@click.command()
@click.argument('name')
@click.option('--greeting', default='Hello', help='The greeting message.') 
def greet(name, greeting):
    """Print a greeting message."""
    click.echo(f"{greeting}, {name}!")

if __name__ == '__main__':
    greet()

上述示例定义了一个简单的Click命令,接受一个位置参数和一个可选参数。运行脚本时,可以通过python script.py John --greeting Hi来执行。

2.5 Click的参数类型与验证

Click不仅仅支持基本的参数类型,还提供了许多内置的高级参数类型,如文件、路径等。同时,Click还允许开发者自定义参数类型以满足特定需求。以下是一个演示Click参数类型和验证的示例:

import click

@click.command()
@click.argument('input_file', type=click.File('r'))
@click.argument('output_file', type=click.File('w'))
@click.option('--count', default=1, help='Number of greetings.')
def copy_file(input_file, output_file, count):
    """Copy the contents of one file to another."""
    contents = input_file.read()
    output_file.write(contents * count)
    click.echo(f'File copied {count} times.')

if __name__ == '__main__':
    copy_file()

在这个例子中,input_fileoutput_file分别表示输入和输出文件,其类型为Click提供的文件类型。--count为可选参数,用于指定复制的次数。

2.6 Click的多命令结构

Click支持创建多命令结构,使得开发者可以组织复杂的命令行应用。使用@click.group()装饰器定义一个命令组,然后通过@click.command()装饰器定义组内的各个命令。以下是一个示例:

import click

@click.group()
def cli():
    """This is the main entry point for the CLI."""
    pass

@cli.command()
def command1():
    """First command."""
    click.echo('Executing command1.')

@cli.command()
def command2():
    """Second command."""
    click.echo('Executing command2.')

if __name__ == '__main__':
    cli()

在这个例子中,cli被定义为命令组,包含了command1command2两个子命令。运行脚本时,可以通过python script.py command1python script.py command2执行相应的命令。

2.7 Click的高级特性:自定义命令类

Click允许开发者使用类来组织和管理命令。通过继承click.Command类,可以定义更复杂的命令行结构。以下是一个演示自定义命令类的示例:

import click

class MathCommands(click.Command):
    def __init__(self, name='math', **kwargs):
        super().__init__(name, **kwargs)

    def get_commands(self, ctx):
        return [AddCommand(), MultiplyCommand()]

class AddCommand(click.Command):
    def __init__(self, name='add', **kwargs):
        super().__init__(name, **kwargs)

    def invoke(self, ctx):
        click.echo('Executing addition command.')

class MultiplyCommand(click.Command):
    def __init__(self, name='multiply', **kwargs):
        super().__init__(name, **kwargs)

    def invoke(self, ctx):
        click.echo('Executing multiplication command.')

@click.command(cls=MathCommands)
def math():
    """Math operations."""
    pass

if __name__ == '__main__':
    math()

在这个例子中,通过自定义MathCommands类,将AddCommandMultiplyCommand两个子命令组织在一起。运行脚本时,可以通过python script.py math addpython script.py math multiply执行相应的命令。

3. argparse

3.1 argparse基础

argparse是Python标准库中的模块,用于解析命令行参数。它提供了一种简单而灵活的方式来定义命令行接口,支持位置参数、可选参数和子命令。

3.2 参数解析与验证

argparse通过ArgumentParser类实现参数解析。使用add_argument()方法添加不同类型的参数,并可指定验证规则。

3.3 子命令与分组

argparse支持通过add_subparsers()方法添加子命令,并为每个子命令定义独立的参数。

3.4 扩展argparse功能
import argparse

def calculate(args):
    result = args.x * args.y
    print(f"The result is: {result}"  )

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Simple calculator.')
    parser.add_argument('x', type=int, help='First number')
    parser.add_argument('y', type=int, help='Second number')

    subparsers = parser.add_subparsers(title='Commands', dest='command')
    subparser = subparsers.add_parser('multiply', help='Multiply two numbers')
    subparser.set_defaults(func=calculate)

    args = parser.parse_args()
    args.func(args)

在上述示例中,argparse被用于创建一个简单的计算器,支持命令行输入python script.py 5 3python script.py multiply 5 3

3.5 argparse的自定义参数类型与动作

argparse允许开发者定义自己的参数类型和动作,以满足特定需求。以下是一个展示自定义参数类型和动作的示例:

import argparse

def is_valid_file(arg):
    if not arg.endswith('.txt'):
        raise argparse.ArgumentTypeError('File must have a .txt extension')
    return arg

def custom_action(arg):
    print(f'Custom action performed with argument: {arg}')

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Custom argparse example.')
    parser.add_argument('input_file', type=is_valid_file, help='Input file with .txt extension')
    parser.add_argument('--custom', action='store', type=custom_action, help='Perform a custom action')

    args = parser.parse_args()

在这个例子中,is_valid_file函数用于自定义文件类型的参数验证,而custom_action函数则用于自定义动作。运行脚本时,可以通过python script.py input.txt --custom argument来执行。

3.6 argparse的互斥与组

argparse支持定义互斥参数组和参数组,以确保在命令行输入时一些参数的排他性或共存性。以下是一个互斥参数组和参数组的示例:

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Mutual exclusion and groups example.')
    
    group = parser.add_mutually_exclusive_group()
    group.add_argument('--verbose', action='store_true', help='Enable verbose mode')
    group.add_argument('--quiet', action='store_true', help='Enable quiet mode')

    args = parser.parse_args()
    if args.verbose:
        print('Verbose mode enabled.')
    elif args.quiet:
        print('Quiet mode enabled.')

在这个例子中,--verbose--quiet是互斥的参数,用户只能选择其中一个。通过运行脚本时添加相应的参数,可以测试互斥组的效果。

3.7 argparse与配置文件结合

argparse可以与配置文件结合使用,以提供更灵活的参数设置。以下是一个展示argparse与配置文件结合的示例:

import argparse
import configparser

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Argparse with configuration file example.')
    parser.add_argument('--config', type=argparse.FileType('r'), help='Configuration file')

    args = parser.parse_args()

    config = configparser.ConfigParser()
    if args.config:
        config.read_file(args.config)

    print('Configuration settings:')
    for section in config.sections():
        for key, value in config.items(section):
            print(f'{section}.{key}: {value}')

在这个例子中,用户可以通过命令行参数--config config.ini指定配置文件。配置文件内容如下:

[Settings]
verbose = true
output_dir = /path/to/output

运行脚本时,将读取配置文件并输出配置项。

4. Prompt Toolkit

4.1 Prompt Toolkit简介

Prompt Toolkit是一个用于构建交互式命令行应用程序的Python库。它提供了强大的输入处理和用户界面定制功能。

4.2 构建交互式命令行应用

Prompt Toolkit允许开发者创建具有动态更新、自动补全和多种输入模式的命令行界面。

4.3 高级输入处理

该库支持处理鼠标事件、键盘快捷键等高级输入处理,为用户提供更丰富的交互体验。

4.4 定制用户界面
from prompt_toolkit import prompt

def get_user_input():
    user_input = prompt('Enter something: ')
    print(f'You entered: {user_input}')

if __name__ == '__main__':
    get_user_input()

上述示例展示了如何使用Prompt Toolkit获取用户输入,并在屏幕上显示输入内容。

4.5 动态更新界面

Prompt Toolkit支持动态更新命令行界面,使得用户可以实时看到应用程序的状态变化。以下是一个简单的动态更新示例:

from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import Style
from prompt_toolkit.token import Token
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit import Application

def dynamic_interface():
    def get_text():
        return [('class:output', 'Dynamic content goes here.')]

    style = Style.from_dict({'output': 'bg:#ansiblue #ansiwhite'})

    formatted_text = FormattedTextControl(get_text)
    window = Window(content=formatted_text)

    application = Application(layout=window, style=style)
    application.run()

if __name__ == '__main__':
    dynamic_interface()

在这个例子中,通过FormattedTextControl实现了一个具有动态更新内容的界面。

4.6 自动补全功能

Prompt Toolkit提供了丰富的自动补全功能,使用户在输入时能够快速选择合适的选项。以下是一个自动补全功能的简单示例:

from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter

def auto_complete_example():
    completer = WordCompleter(['apple', 'banana', 'orange', 'grape'])
    user_input = prompt('Enter a fruit: ', completer=completer)
    print(f'You selected: {user_input}')

if __name__ == '__main__':
    auto_complete_example()

在这个例子中,用户输入时会自动补全水果的选项。

4.7 使用Prompt Toolkit构建复杂界面

Prompt Toolkit不仅可以构建简单的命令行界面,还可以创建复杂的用户界面。以下是一个使用Prompt Toolkit构建的待办事项应用的简单示例:

from prompt_toolkit import Application
from prompt_toolkit.layout import Layout
from prompt_toolkit.widgets import Box, Frame, TextArea, Label, Checkbox

def todo_app():
    # Define the layout
    layout = Layout(
        Box(
            Frame(TextArea(height=1, prompt='Enter a task: '), title='New Task'),
            Frame(Label('Todo List'), title='Todo List'),
            style='bg:#ffffff',
        )
    )

    # Create the application
    application = Application(layout=layout, full_screen=True)

    # Run the application
    application.run()

if __name__ == '__main__':
    todo_app()

这个例子展示了如何使用Prompt Toolkit创建一个简单的待办事项应用的用户界面。

5. curses

5.1 curses概述

curses是Python的标准库之一,用于创建基于文本终端的用户界面。它提供了对终端屏幕的底层控制。

5.2 基于终端的用户界面

curses允许开发者创建基于文本的用户界面,支持窗口、颜色、文本框等基本控件。

5.3 处理键盘和鼠标事件

curses可以捕获和处理键盘和鼠标事件,实现用户输入的交互响应。

5.4 创建交互式控制台应用
import curses

def main(stdscr):
    curses.curs_set(0)  # 隐藏光标
    stdscr.clear()
    stdscr.addstr(0, 0, "Press 'q' to exit.")
    
    while True:
        key = stdscr.getch()
        if key == ord('q'):
            break

if __name__ == '__main__':
    curses.wrapper(main)

在上述示例中,使用curses创建了一个简单的交互式控制台应用,用户可以按 ‘q’ 键退出应用。

5.5 curses中的窗口管理

curses中的窗口是一个重要概念,允许开发者在屏幕上创建多个独立的区域。以下是一个使用窗口管理的简单示例:

import curses

def main(stdscr):
    curses.curs_set(0)  # 隐藏光标

    height, width = stdscr.getmaxyx()
    window = curses.newwin(height, width, 0, 0)

    window.addstr(0, 0, "This is a window.")
    window.refresh()

    stdscr.getch()

if __name__ == '__main__':
    curses.wrapper(main)

这个例子中,使用curses.newwin()创建了一个窗口,并在窗口中添加文本。用户按任意键后退出。

5.6 颜色和样式设置

curses支持在终端中设置文本颜色和样式。以下是一个简单的颜色设置示例:

import curses

def main(stdscr):
    curses.start_color()
    curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)

    stdscr.addstr(0, 0, "This is red text.", curses.color_pair(1))
    stdscr.refresh()
    stdscr.getch()

if __name__ == '__main__':
    curses.wrapper(main)

在这个例子中,使用curses.init_pair()初始化了一个颜色对,并通过curses.color_pair()应用到文本上。

5.7 curses中的滚动和移动

curses允许在窗口中进行滚动和移动,以显示大于窗口大小的内容。以下是一个滚动和移动的简单示例:

import curses

def main(stdscr):
    curses.curs_set(0)  # 隐藏光标

    height, width = stdscr.getmaxyx()
    window = curses.newwin(height, width, 0, 0)

    text = "This is a long text. " * 10
    window.addstr(0, 0, text)

    window.refresh()

    window.getch()  # 等待用户按键

    window.scrollok(True)  # 允许滚动
    for i in range(5):
        window.scroll(1)  # 向上滚动一行
        window.refresh()
        curses.napms(100)  # 暂停一段时间

    window.getch()  # 等待用户按键

if __name__ == '__main__':
    curses.wrapper(main)

在这个例子中,创建了一个长文本窗口,用户按任意键后窗口开始滚动。

6. Docopt

6.1 了解Docopt语法

Docopt是一种基于文档字符串的命令行参数解析工具,它允许开发者使用自然语言描述命令行接口。

6.2 生成帮助信息

Docopt通过解析文档字符串自动生成帮助信息,避免了手动编写和维护命令行参数的文档。

6.3 命令行参数规范

Docopt支持根据文档字符串中的规范自动解析命令行参数,使得代码更加简洁。

6.4 与Python项目集成
"""Usage:
    script.py add <x> <y>
    script.py multiply <x> <y>

Options:
    -h --help     Show this help message and exit. 
"""

from docopt import docopt

def main():
    arguments = docopt(__doc__)
    
    if arguments['add']:
        result = int(arguments['<x>']) + int(arguments['<y>'])
    elif arguments['multiply']:
        result = int(arguments['<x>']) * int(arguments['<y>'])
    
    print(f'The result is: {result}')

if __name__ == '__main__':
    main()

在上述示例中,docopt解析了文档字符串中定义的命令行参数规范,根据用户输入执行相应的操作。

6.5 命令行参数的默认值与类型

Docopt允许为命令行参数设置默认值,并支持多种数据类型。以下是一个包含默认值和类型的示例:

"""Usage:
    script.py --input=<file> [--output=<file>] [--threshold=<float>]

Options:
    -h --help           Show this help message and exit.
    --input=<file>      Input file.
    --output=<file>     Output file. [default: output.txt]
    --threshold=<float> Threshold value. [default: 0.5]
"""

from docopt import docopt

def main():
    arguments = docopt(__doc__)
    
    input_file = arguments['--input']
    output_file = arguments['--output']
    threshold = float(arguments['--threshold'])
    
    print(f'Input file: {input_file}')
    print(f'Output file: {output_file}')
    print(f'Threshold: {threshold}')

if __name__ == '__main__':
    main()

在这个例子中,--output--threshold分别具有默认值,用户可以选择提供或不提供这些参数。

6.6 子命令的定义与解析

Docopt支持子命令的定义和解析,使得可以构建复杂的命令行应用。以下是一个子命令的示例:

"""Usage:
    script.py command-a <name>
    script.py command-b <id>

Options:
    -h --help           Show this help message and exit.
"""

from docopt import docopt

def main():
    arguments = docopt(__doc__)
    
    if arguments['command-a']:
        print(f'Running command-a with name: {arguments["<name>"]}')
    elif arguments['command-b']:
        print(f'Running command-b with id: {arguments["<id>"]}')

if __name__ == '__main__':
    main()

在这个例子中,根据用户输入的子命令执行相应的操作。

7. Cement

7.1 Cement框架介绍

Cement是一个基于MVC架构设计的命令行界面框架,提供了一套强大而灵活的工具,用于构建可扩展的命令行应用程序。

7.2 Cement中的MVC架构

Cement框架将应用程序分为模型、视图和控制器,使得开发者能够更好地组织和管理代码。

7.3 扩展Cement功能

Cement支持插件机制,允许开发者扩展框架功能,添加自定义的命令和扩展。

7.4 使用案例与最佳实践
from cement import App, Controller, ex

class MyController(Controller):
    class Meta:
        label = 'base'
        description = 'My Application'
        arguments = [
            (['-f', '--foo'], dict(help='Foo option')),
        ]

    @ex(help='My command')
    def my_command(self):
        # Implementation of the command
        self.app.log.info("Executing my_command")

if __name__ == '__main__':
    with App() as app:
        app.run()

在上述示例中,Cement框架被用于创建一个简单的命令行应用程序,包含一个自定义命令my_command

7.5 Cement中的配置管理

Cement框架提供了灵活的配置管理机制,允许开发者轻松定义和使用应用程序的配置项。以下是一个简单的配置管理示例:

from cement import App, Controller, ex

class MyController(Controller):
    class Meta:
        label = 'base'
        config_defaults = dict(
            foo='default_value',
            bar='another_default'
        )

    @ex(help='My command')
    def my_command(self):
        # Accessing configuration values
        foo_value = self.app.config.get('base', 'foo')
        bar_value = self.app.config.get('base', 'bar')
        self.app.log.info(f"Foo value: {foo_value}, Bar value: {bar_value}")

if __name__ == '__main__':
    with App() as app:
        app.run()

在这个例子中,config_defaults用于设置默认的配置值,并在my_command中通过self.app.config.get()获取配置值。

7.6 Cement中的日志记录

Cement框架内置了日志记录功能,允许开发者在应用程序中方便地记录信息、警告和错误。以下是一个简单的日志记录示例:

from cement import App, Controller, ex

class MyController(Controller):
    class Meta:
        label = 'base'

    @ex(help='My command')
    def my_command(self):
        # Logging information
        self.app.log.info("This is an information message.")
        # Logging a warning
        self.app.log.warning("This is a warning message.")
        # Logging an error
        self.app.log.error("This is an error message.")

if __name__ == '__main__':
    with App() as app:
        app.run()

在这个例子中,通过self.app.log可以轻松记录信息、警告和错误。

7.7 Cement中的插件扩展

Cement框架支持插件机制,允许开发者通过插件扩展框架的功能。以下是一个简单的插件扩展示例:

from  cement import App, Controller, ex
from cement.ext.ext_plugin import CementPluginHandler

class MyPlugin(Controller):
    class Meta:
        label = 'my_plugin'
        interface = CementPluginHandler
        description = 'My custom plugin'

    def load(self):
        # Loading the plugin
        self.app.log.info("My plugin has been loaded.")

if __name__ == '__main__':
    with App() as app:
        app.setup()
        app.run()

在这个例子中,MyPlugin被定义为一个插件,并在应用程序中通过app.setup()加载。

8. cliff

8.1 cliff简介

cliff是一个命令行界面框架,建立在setuptools和argparse之上,为开发者提供了一种简便的方式来创建模块化的、可扩展的CLI应用程序。

8.2 命令行界面框架

cliff通过定义Command类和Command的子类来创建命令行界面。每个Command类代表一个可执行的命令。

8.3 创建基于命令的应用

cliff支持创建包含多个命令的应用程序,并能够方便地扩展功能。

8.4 在cliff中使用插件与扩展
from cliff.app import App
from cliff.command import Command

class MyCommand(Command):
    def take_action(self, parsed_args):
        self.app.stdout.write('Hello, CLI!\n')

class MyCLI(App):
    def __init__(self):
        super(MyCLI, self).__init__(
            description='My Command Line Interface',
            version='1.0',
            command_manager='cliffdemo.command',
            deferred_help=True,
        )

if __name__ == '__main__':
    mycli = MyCLI()
    mycli.run()

在上述示例中,cliff框架被用于创建一个简单的命令行应用程序,包含一个自定义命令MyCommand

8.5 在cliff中使用参数和选项

cliff框架允许开发者为命令定义参数和选项,以实现更灵活的命令行应用。以下是一个包含参数和选项的示例:

from cliff.app import App
from cliff.command import Command
from cliff.command import CommandManager

class Greet(Command):
    """Greet the user."""

    def get_parser(self, prog_name):
        parser = super(Greet, self).get_parser(prog_name)
        parser.add_argument('name', help='The name to greet')
        parser.add_argument('--greeting', default='Hello', help='The greeting message')
        return parser

    def take_action(self, parsed_args):
        self.app.stdout.write(f"{parsed_args.greeting}, {parsed_args.name}!\n")

class MyCLI(App):
    def __init__(self):
        super(MyCLI, self).__init__(
            description='My Command Line Interface',
            version='1.0',
            command_manager=CommandManager('cliffdemo.command'),
            deferred_help=True,
        )

if __name__ == '__main__':
    mycli = MyCLI()
    mycli.run()

在这个例子中,Greet命令接受一个必需的参数和一个可选的选项,分别表示要问候的名字和问候语。

8.6 在cliff中定义子命令

cliff框架支持创建带有子命令的应用程序,通过继承Command类创建子命令。以下是一个包含子命令的示例:

from  cliff.app import App
from cliff.command import Command
from cliff.command import CommandManager

class ParentCommand(Command):
    """Parent command."""

    def take_action(self, parsed_args):
        self.app.stdout.write("This is the parent command.\n")

class ChildCommand(Command):
    """Child command."""

    def take_action(self, parsed_args):
        self.app.stdout.write("This is the child command.\n")

class MyCLI(App):
    def __init__(self):
        super(MyCLI, self).__init__(
            description='My Command Line Interface',
            version='1.0',
            command_manager=CommandManager('cliffdemo.command'),
            deferred_help=True,
        )

if __name__ == '__main__':
    mycli = MyCLI()
    mycli.run()

在这个例子中,ParentCommand是一个父命令,ChildCommand是一个子命令。在应用程序中使用CommandManager管理这些命令。

9. prompt_toolkit

9.1 prompt_toolkit特性

prompt_toolkit是一个用于构建丰富命令行界面的库,提供了丰富的特性,包括自动补全、语法高亮等。

9.2 构建丰富的命令行界面

prompt_toolkit允许开发者创建具有多种颜色、样式和布局的交互式命令行应用。

9.3 样式与主题

该库支持定制样式和主题,使得开发者能够创建符合应用程序设计的独特界面。

9.4 与其他库和框架集成
from  prompt_toolkit import prompt

def get_user_input():
    user_input = prompt('Enter something: ', vi_mode=True, enable_history_search=True)
    print(f'You entered: {user_input}')

if __name__ == '__main__':
    get_user_input()

上述示例中,使用了prompt_toolkit创建一个支持Vi模式和历史搜索的交互式命令行输入。

9.5 自动补全与建议

prompt_toolkit提供了自动补全和建议功能,使用户在输入时能够方便地选择合适的命令或参数。以下是一个自动补全的示例:

from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter

def get_user_input():
    completer = WordCompleter(['apple', 'banana', 'orange'])
    user_input = prompt('Enter a fruit: ', completer=completer)
    print(f'You entered: {user_input}')

if __name__ == '__main__':
    get_user_input()

在这个例子中,通过WordCompleter设置自动补全的备选单词,用户可以通过键盘选择并补全输入。

9.6 高级输入处理与事件

prompt_toolkit支持高级输入处理,包括鼠标事件、键盘快捷键等。以下是一个捕获键盘事件的示例:

from prompt_toolkit import prompt
from prompt_toolkit.key_binding import KeyBindings

def get_user_input():
    kb = KeyBindings()

    @kb.add('c-c')
    def _(event):
        event.app.exit(result='You pressed Ctrl-C!')

    user_input = prompt('Press Ctrl-C: ', key_bindings=kb)
    print(f'Result: {user_input}')

if __name__ == '__main__':
    get_user_input()

在这个例子中,通过KeyBindings捕获了按下Ctrl-C的事件,并在应用程序中进行了处理。

9.7 多窗口与布局

prompt_toolkit允许创建多窗口布局,实现更复杂的交互式命令行应用。以下是一个简单的多窗口示例:

from  prompt_toolkit import prompt
from prompt_toolkit.layout import HSplit, Window

def get_user_input():
    layout = HSplit([
        Window(height=1, content='Top window'),
        Window(height=1, content='Bottom window'),
    ])

    user_input = prompt('Multi-window layout: ', layout=layout)
    print(f'You entered: {user_input}')

if __name__ == '__main__':
    get_user_input()

在这个例子中,通过HSplit创建了水平分割的两个窗口,用户可以在不同窗口中进行交互。

总结

通过学习本文,读者将对Python中命令行界面开发的多种工具有全面的了解。从基础的参数解析到构建交互式控制台应用,再到使用框架创建模块化的CLI应用程序,每个章节都深入浅出,为读者提供了全方位的知识体验。无论是想快速创建简单的命令行工具,还是构建复杂的交互式应用,本文都为读者提供了足够的指导与灵感。

文章来源:https://blog.csdn.net/qq_42531954/article/details/135371536
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。