文章目录

  • 环境信息
  • 命令行文件
  • 入口函数
  • command.CLICommand 解析
    • command_map 对象
    • parser 对象
    • 实际的Action函数,以`doDescribeTopics`为例
  • 调用示例
  • `format_output.py`文件
    • Response类是其他格式的基类
    • io.TextIOWrapper效果演示
      • 问题
    • 支持的输出格式
    • 自定义解析格式

环境信息

  • python: 3.8.5
  • tccli: 3.0.666.1

只列出关键代码

命令行文件

from tccli.main import main
if __name__ == '__main__':sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])sys.exit(main())

入口函数

main.py文件

def main():cli_version = __version__.rsplit(".", 1)[0]if sdkVersion < cli_version:sys.stderr.write("Version is inconsistent, python sdk version:%s tccli version:%s" % (sdkVersion, __version__))returntry:log.info("tccli %s" % ' '.join(sys.argv[1:]))CLICommand()()

main函数主要是调用了CLICommand()()

command.CLICommand 解析

class CLICommand(BaseCommand):def __init__(self):self._command_map = Noneself._argument_map = Nonesuper(CLICommand, self).__init__()def __call__(self, args=None):if args is None:# 将所有参数存入至 args args = sys.argv[1:]if len(args) > 0 and args[0] == "as":args[0] = "autoscaling"command_map = self._get_command_map()parser = self._create_parser(command_map)# 解决接口版本(--version) 和 tccli版本(--version)字段冲突self._handle_service_version_argumnet(args, parser)self._handle_warning(args)parsed_args, remaining = parser.parse_known_args(args)return command_map[parsed_args.command](remaining, parsed_args)

command_map 对象

command_map是一个OrderedDict,当servicednspod时,结果如下。说白了,就是{"func_name": func}这样的字典,通过字符串方便找到真正的同名的函数。

下面的示例,就是 dnspod这个service下的 Action

使用tccli dnspod help就能看到。

OrderedDict([('CreateDomain', <tccli.command.ActionCommand object at 0x7f6d7f0c16a0>), ('CreateDomainAlias', <tccli.command.ActionCommand object at 0x7f6d7f0a5370>), ('CreateDomainBatch', <tccli.command.ActionCommand object at 0x7f6d7f275970>), ('CreateDomainGroup', <tccli.command.ActionCommand object at 0x7f6d7eae5310>), ('CreateRecord', <tccli.command.ActionCommand object at 0x7f6d7f283160>), ('CreateRecordBatch', <tccli.command.ActionCommand object at 0x7f6d7e7de430>), ('DeleteDomain', <tccli.command.ActionCommand object at 0x7f6d7f2831c0>), ...])

parser 对象

这个实际上是CLIArgParser类的实例。

CLIArgParser来自argparser.py文件


class CLIArgParser(BaseArgParser):

其父类BaseArgParser继承自argparse.ArgumentParser

class BaseArgParser(argparse.ArgumentParser):

parse_known_args()方法在BaseArgParser重写了。
详细的不看了,这里直接看下相关的结果。

CLICommand__call__方法下添加打印代码。

print("parsed_args", parsed_args)
print("remaining", remaining)
sys.stdout.flush()

输出示例1

# tccli cls ModifyTopic help --detail
parsed_args Namespace(cli_input_json=None, cli_unfold_argument=False, command='cls', detail=True, endpoint=None, filter=None, generate_cli_skeleton=None, https_proxy=None, output=None, profile=None, region=None, role_arn=None, role_session_name=None, secretId=None, secretKey=None, service_version=None, timeout=None, token=None, use_cvm_role=False, waiter=None, warning=False)
remaining ['ModifyTopic', 'help']

示例2

# tccli cls DescribeTopics --Filters '[ {"Key": "topicName", "Values": [ "test-log" ] }]'
parsed_args Namespace(cli_input_json=None, cli_unfold_argument=False, command='cls', detail=False, endpoint=None, filter=None, generate_cli_skeleton=None, https_proxy=None, output=None, profile=None, region=None, role_arn=None, role_session_name=None, secretId=None, secretKey=None, service_version=None, timeout=None, token=None, use_cvm_role=False, waiter=None, warning=False)
remaining ['DescribeTopics', '--Filters', '[ {"Key": "topicName", "Values": [ "test-log" ] }]']

实际的Action函数,以doDescribeTopics为例

此函数定义在cls/cls_client.py文件当中。

按照如下调用来看,其把

  • remaining 当作 args 传入
  • parsed_args 当作 parsed_globals 传入
def doDescribeTopics(args, parsed_globals):...model = models.DescribeTopicsRequest()model.from_json_string(json.dumps(args))start_time = time.time()while True:rsp = client.DescribeTopics(model)result = rsp.to_json_string()...

这个也容易理解,一部分是“全局参数”,一部分是“Action函数”的参数。

其将“全局参数”转化为g_param, 打印一下。结果如下:

g_param {'filter': None, 'output': 'json', 'secretId': 'xxxxxxxxx', 'secretKey': 'xxxxxxxxxxx', 'token': None, 'role_arn': None, 'role_session_name': None, 'use_cvm_role': False, 'detail': False, 'profile': 'default', 'region': 'ap-beijing', 'endpoint': 'cls.tencentcloudapi.com', 'timeout': None, 'generate_cli_skeleton': None, 'cli_input_json': None, 'cli_unfold_argument': False, 'https_proxy': None, 'warning': False, 'waiter': None, 'command': 'cls', 'service_version': None, 'version': 'v20201016'}

model对象是v20201016/models.pyDescribeTopicsRequest的实例。其主要是实现了_deserialize方法。

class DescribeTopicsRequest(AbstractModel):

from_json_string方法来自abstract_model.py中的AbstractModel类。是DescribeTopicsRequest的父类。

而在from_json_string方法中又调用了上面的_deserialize方法。

到此,告一段落吧。

调用示例


import sys
from tccli.main import mainargs = ['tccli', 'cls', 'DescribeTopics','--Filters','[ {"Key": "topicName", "Values": [ "test-log" ] }]']sys.argv = args
main()

如上代码,可以在自己的脚本中,调用tccli中的函数了。

当然,由于其main总是将结果输出至stdout中,所以想将其结果保存至变量中的话,还需要自己写函数处理一下。这部分可以参考 python 将函数标准输出存至变量问题。

format_output.py文件

此文件中定义了输出格式相关的操作。

Response类是其他格式的基类

__call__方法内调用的self._format_response()方法由各子类实现,如JSONResult, TableResultTextResult

方法中,还有设置stream的代码。

def __call__(self, command, response, stream=None):if stream is None:if not six.PY2:sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')stream = sys.stdouttry:self._format_response(command, response, stream)except IOError as e:passfinally:self._flush_stream(stream)
  • 首先判断有没有stream传进来, 在当前的不修改源码的情况下,是没办法传stream参数的。所以一定会进入判断内的逻辑
  • python版本不是2.x的情况下,将sys.stdout指向io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8') 的结果。
    • 这一步,主要是增加了buffer效果(同时修改了encoding),写入数据不会立马看到,示例如下
  • 然后将stream指向sys.stdout,

io.TextIOWrapper效果演示

In [51]: sys.stdout =old_outIn [52]: print("hahha")
hahhaIn [53]: print("hhehe")
hheheIn [54]: sys.stdout = io.TextIOWrapper(sys.stdout.buffer,...:                                               encoding='utf-8')
In [55]: print("hahha")
In [56]: print("haha")
In [57]: sys.stdout.flush()hahhahaha

使用io.TextIOWrapper之后,print的结果不会马上显示,而是需要调用sys.stdout.flush()函数才能看到。

问题

在诸如doDescribeRecordList等函数中,如果使用了print()语句,那么需要马上执行sys.stdout.flush()方法,才能看到输出,否则最后只有相应的函数结果执行输出,而看不自己添加的print()效果,这是为什么呢?

这个原因是因为后来FormatOutput.output函数,改变了io流,新的io流与之前是不一样的了。验证代码如下:

import sys
import io
import timeold_stdout = sys.stdout
sys.stdout = io.TextIOWrapper(old_stdout.buffer, encoding='utf-8')
print("I'm sys.stdout.")# 没有这一行,脚本就会报错,暂时不明白
old_stdout = sys.stdout
sys.stdout = io.TextIOWrapper(old_stdout.buffer, encoding='utf-8')
print(time.ctime(), "heheh")
print(time.ctime(),"hahah")
print("over")

运行,上面的这个脚本,是不会看到I'm sys.stdout.的,因为前后两次的io流已经不一样了。

但是实际的tccli中,虽然也是设置了两次sys.stdout,但是并没有像上面那样使用old_stdout = sys.stdout这种语句,其脚本中使用了reload(sys)

  • main.py脚本中设置一次sys.stdout
  • format_output.py中设置一次sys.stdout
    • 被其他函数所调用时

尝试将两次设置sys.stdout放于不同的文件当中,也不行。

支持的输出格式

如代码中的情况,目前只支持3种方式。

这里思考,自定义一种格式的可能性?
自己编写一种格式,放在源代码中,然后,自己指定这种格式,是否可行?

[root@nano-kvm-11 ~]# tccli --output table1 dnspod DescribeDomain  --Domain hongyuan.com
usage: tccli [options] <command> <subcommand> [<subcommand> ...] [parameters]
To tccli help text, you can run:tccli helptccli configure helptccli service[cvm] helptccli service[cvm] action[RunInstances] help
tccli: error: argument --output: Invalid choice, valid choices are:json                                     | text
table                                   Invalid choice: 'table1', maybe you meant:* table

自定义解析格式

在开始之前是有参数检查的,需要先跨过这一关。

[root@nano-kvm-11 ~]# tccli --output json1 dnspod DescribeDomain  --Domain hongyuan.com
usage: tccli [options] <command> <subcommand> [<subcommand> ...] [parameters]
To tccli help text, you can run:tccli helptccli configure helptccli service[cvm] helptccli service[cvm] action[RunInstances] help
tccli: error: argument --output: Invalid choice, valid choices are:json                                     | text
table                                   Invalid choice: 'json1', maybe you meant:* json

腾讯云客户端命令行工具tccli主流程解析相关推荐

  1. linux使用mysql命令行工具_我使用过的Linux命令之mysql - MySQL客户端命令行工具

    我使用过的Linux命令之mysql - MySQL客户端命令行工具 用途说明 mysql命令是用来连接MySQL服务器并执行用户命令行的工具,如果使用MySQL作为数据库,那这个命令就是经常需要用到 ...

  2. 知晓云 – 云函数命令行工具发布

    九九重阳刚刚过去,一大波母螃蟹正在向你靠近,「知晓云」择此吉日出炉了一整锅热乎的新功能,欢迎各位同学敞开肚皮,尽情享用. No.0 云函数命令行工具发布 在云函数控制面板上可以很方便地创建.编辑.配置 ...

  3. (十二)洞悉linux下的Netfilteramp;iptables:iptables命令行工具源码解析【下】

    iptables用户空间和内核空间的交互 iptables目前已经支持IPv4和IPv6两个版本了,因此它在实现上也需要同时兼容这两个版本.iptables-1.4.0在这方面做了很好的设计,主要是由 ...

  4. 客户端命令行工具 - 接口调试神器 HTTPie

    http www.baidu.com (默认get请求) 一.http http://127.0.0.1:8080/admin/login mobile=13226317777password=abc ...

  5. 微软tfs服务器申请,TFS 的命令行工具

    TFS 的命令行工具 06/09/2015 本文内容 Visual Studio Team Foundation Server (TFS) 命令行工具执行几类任务. 某些任务可以通过用户界面完成,其他 ...

  6. Redis 笔记(16)— info 指令和命令行工具(查看内存、状态、客户端连接数、监控服务器、扫描大key、采样服务器、执行批量命令等)

    Info 命令返回关于 Redis 服务器的各种信息和统计数值.通过给定可选的参数 section ,可以让命令只返回某一部分的信息. 1. 显示模块 server : 一般 Redis 服务器信息, ...

  7. 通过命令行工具使用阿里云资源编排服务

    资源编排ROS 是一种简单易用的云计算资源管理和自动化运维服务.用户通过模板描述多个云计算资源的依赖关系.配置等,并自动完成所有资源的创建和配置,以达到自动化部署.运维等目的. 了解更多 通过命令行工 ...

  8. 【云原生 • Kubernetes】命令行工具 kubectl 介绍及命令汇总

    本文导读 1. kubectl 概述 2. kubectl 命令语法 3. kubectl help 获取更多信息 4. kubectl 命令大全 • 基础命令 • 部署命令 • 集群管理命令 • 故 ...

  9. 【重识云原生】第六章容器6.3.7节——命令行工具kubectl

    <重识云原生系列>专题索引: 第一章--不谋全局不足以谋一域 第二章计算第1节--计算虚拟化技术总述 第二章计算第2节--主流虚拟化技术之VMare ESXi 第二章计算第3节--主流虚拟 ...

最新文章

  1. python递归题目_Python递归的问题?
  2. python推荐书籍-7本经典的Python书籍,你都读过了么?
  3. C语言程序设计第三次作业——选择结构(1)
  4. TRUNK配置详细讲解
  5. 内部类的分类及其定义
  6. ios逆向小试牛刀之操作手记
  7. MyBatis拦截器原理探究
  8. 非线性光纤光学_1.56 m波段高能量百飞秒光纤激光器
  9. 移位操作提高代码的可读性_本地记录或类,以提高流操作的可读性
  10. php中for循环流程图,PHP for循环
  11. java.sql.SQLException: Parameter index out of range (5 > number of parameters, which is 4).
  12. 用 Anaconda 完美解决 Python2 和 python3 共存问题
  13. MySQL Shell副本集和MGR快速搭建详解
  14. 1049. 最后一块石头的重量 II(JavaScript)
  15. 目录行距怎么设置_硕士论文格式设置方法
  16. [转载] 杜拉拉升职记——34 设定工作目标要符合“SMART”原则
  17. [PHP]算法- 二叉树的深度的PHP实现
  18. 机器学习中的数学:微积分与最优化
  19. 游戏感:虚拟感觉的游戏设计师指南——第十九章 游戏感的未来
  20. 离心泵水力设计——0设计参数

热门文章

  1. Python工具脚本,PDF文件批量转图片(pdf图片提取器)工具(exe)
  2. 《炬丰科技-半导体工艺》一步清洁取代RCA两步清洁法用于Pre-Gate清洁
  3. 学习笔记 - 月冲年冲
  4. 【一起来烧脑】一步学会CSS3体系
  5. 关于为什么出现粘包问题及如何解决!
  6. BPM-业务流程管理
  7. 期刊信息管理list.php,科学网—【信管学人国际期刊投稿目录列表】-Journal List for Scholars in Info Mgt - 陈晓宇的博文...
  8. CAD标注样式修改后为什么图中标注不变?
  9. QCW切割 --铁片
  10. 使用富文本编辑器wangEditor完成图片文件的上传