首页 > 解决方案 > 如何使用 Click CLI 添加选项并将选项正确传递给函数?

问题描述

我正在上我的第一门编程课程,所以如果问题太天真,请原谅。我正在使用 Python Boto3 模块和“Click”库来构建管理 EC2 实例的命令行界面。代码:

@click.group()
@cli.group('instances')
def instances():
    pass
@instances.command('list')
@click.option('--project', default=None,help='List instances by project tag, e.g. -project = <project name>')
def list_instances(project):
    'List EC2 instances'
    instances = filter_project_instances(project)
    for i in instances:
            print(', '.join((
            i.id,
            i.instance_type,
        )))
        return

@cli.group('volumes')
#Details of this 'volumes' command are omitted for simplification 

基本上,“点击”允许我使用命令(例如实例、卷)、子命令(列表)和选项(--project)来包装我的函数。这样的命令行: shotty.py instances list --project Valkyrie 可以列出标记为“Valkyrie”的实例

现在,我需要在此命令行中添加一个选项来指定我想用来登录的 AWS 配置文件。该配置文件是使用“aws configure --profile [profile name]”命令创建的(配置文件名称可以是 Dan,凯尔等):

shotty.py --profile [配置文件名称] 实例列表

最初,我对配置文件名称进行硬编码,并将sessionec2用作任何其他函数都可以使用的全局变量。

import boto3
import botocore
import click

session = boto3.Session(profile_name='Dan')
ec2 = session.resource('ec2')

虽然实现了上述要求,但基于“点击”文档,我必须执行以下操作来添加这样的“--profile”选项:

@click.group()
@click.option('--profile', default=None,help='Select the AWS profile')
def cli(profile):
   session = boto3.Session(profile_name=profile)
   ec2 = session.resource('ec2')

但是现在,sessionec2不再可用于其他功能。这个 cli() 函数就像脚本的入口点,在 main() 函数中被撤销:

if __name__ == '__main__':
    cli()

我能想到的唯一方法是创建一个单独的函数

  def session(profile):
        session = boto3.Session(profile_name=profile)
        ec2 = session.resource('ec2')
        return ec2

但是现在这带来了另一个问题,我必须将配置文件作为参数添加到所有其他功能,例如

def filter_project_instances(project, profile):
        'Filter EC2 instances'
        ec2 = session(profile)
        instances = ec2.instances.all()
        return instances

这意味着我必须以某种方式在此filter_project_instances函数中再次定义配置文件。这对我来说没有多大意义。任何帮助,将不胜感激!更新:我在发布之前查看了 global 关键字,但大多数搜索告诉我,拥有全局变量主要是一个糟糕设计的标志,所以我认为我缺乏一些 python 的东西来使它在这里工作

标签: pythonamazon-ec2clickcommand-line-interfaceboto3

解决方案


经过试验,似乎最合适的解决方案是将我的配置文件变量设为全局

@click.group()
@click.option('--profile', default = None, help='Select the AWS profile')
def cli(profile):
    "Shotty manages snapshots"
    session = boto3.Session(profile_name=profile)
    ec2_cli = session.resource('ec2')
    global ec2
    ec2 = ec2_cli

尽管这种方法通常不受欢迎,但我一直在努力按照大多数人的建议将所有相关函数封装在一个类中(如何在 Python 中的函数之间共享值?)在这种情况下,这种全局变量解决方案似乎是最好的,因为它涉及的最少代码的变化


推荐阅读