使用python模拟命令行终端

28 篇文章 0 订阅
4 篇文章 0 订阅

可以对?显示帮助信息,需要立即获取输入的字符,因此需要用到termios模块

另外需要对tab键做处理,当按下tab键时可以进行自动补全

#! /usr/bin/env python
# coding=utf-8

import os
import sys
import tty
import termios

'''
Enter:  13
Back:   127
?:      63
C-h:    8
C-w:    23
Tab:    9
C-u:    21
C-c:    3
C-d:    4
C-\:    28
SPACE:  32
'''

CLI_KEY_CNCR  = 13
CLI_KEY_BACK  = 127
CLI_KEY_QMARK = 63
CLI_KEY_CTRLH = 8
CLI_KEY_CTRLW = 23
CLI_KEY_TAB   = 9
CLI_KEY_CTRLU = 21
CLI_KEY_CTRLC = 3
CLI_KEY_CTRLD = 4
CLI_KEY_QUIT  = 28
CLI_KEY_SPACE = 32
CLI_KEY_TABLEN = 4

class CLI(object):
    def __init__(self):
        self.line = ''
        self.line_complete = ''
        self.completer_on = False
        self.completer_dict = {}
        self.completer_dict_keys = self.completer_dict.keys()
        self.completer_id = 0
        self.completer_cnt = len(self.completer_dict)
    def getch(self):
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch
    def completer_kw_update(self):
        self.completer_dict_keys = self.completer_dict.keys()
        self.completer_dict_keys.sort()
        self.completer_cnt = len(self.completer_dict)
    def completer_kw_add(self, key, word):
        self.completer_dict[key] = word
        self.completer_kw_update()
    def completer_kw_clear(self):
        self.completer_dict.clear()
        self.completer_id_update()
    def completer_id_update(self):
        self.completer_kw_update()
        if self.completer_id < self.completer_cnt - 1:
            self.completer_id += 1
        else:
            self.completer_id = 0
    def completer_wd_select(self, word):
        if not word:
            return ''
        cnt = self.completer_cnt
        while cnt>0:
            completer = self.completer_dict_keys[self.completer_id]
            self.completer_id_update()
            cnt -= 1
            if word == completer[:len(word)]:
                return completer[len(word):]
        return ''
    def printf(self, info=''):
        sys.stdout.write(info)
    def show_spec_len_str(self, info, maxlen, spacech=' '):
        'display a string of the specified length'
        maxlen = maxlen
        infolen = len(info)
        if maxlen < infolen:
            maxlen = infolen
        while infolen>0:
            ch = info[-infolen]
            for i in range(self.char_memory_len(ch)):
                self.printf(info[i-infolen])
            infolen -= self.char_memory_len(ch)
            maxlen -= self.char_display_len(ch)
        while maxlen>0:
            self.printf(spacech)
            maxlen -= self.char_display_len(spacech)
    def show_help_info(self):
        if self.completer_on:
            line = self.line_complete
        else:
            line = self.line
        lastwd = ''
        show_all = False
        if not line or line[-1] == ' ':
            show_all = True
        else:
            lastwd = line.split()[-1]
        if self.completer_dict:
            maxlen = max([len(info) for info in self.completer_dict])
        else:
            maxlen = 12
        for info in self.completer_dict:
            if show_all or lastwd == info[:len(lastwd)]:
                self.printf(' ')
                self.show_spec_len_str(info, maxlen)
                self.printf(' ')
                self.printf(self.completer_dict[info])
                self.printf('\r\n')
    def is_chinese_char(self, ch):
        return ord(ch) > 127
    def char_display_len(self, ch):
        if self.is_chinese_char(ch):
            return 2
        elif ord(ch) == CLI_KEY_TAB:
            return CLI_KEY_TABLEN
        else:
            return 1
    def char_memory_len(self, ch):
        if self.is_chinese_char(ch):
            return 3
        else:
            return 1
    def rm_last_char(self, line):
        lastch = ''
        rmlen = 0
        if len(line)>0:
            lastch = line[-1]
            self.printf('\b \b' * self.char_display_len(lastch))
            rmlen = self.char_memory_len(lastch)
            if len(line) >= rmlen:
                line = line[:-(rmlen)]
            else:
                rmlen = len(line)
                line = ''
        return rmlen, line
    def rm_last_word(self, line):
        lastwd = ''
        linelen = len(line)
        rspacelen = linelen - len(line.rstrip())
        if not linelen:
            return line
        lastwd = line.split()[-1]
        backlen = len(lastwd) + rspacelen
        rmlen = 0
        while backlen>0 and line:
            rmlen, line = self.rm_last_char(line)
            backlen -= rmlen
        return line
    def rm_one_line(self, line):
        rmlen = 0
        while line:
            rmlen, line = self.rm_last_char(line)
        return line
    def do_line_complete_proc(self):
        line = self.line
        line_complete = self.line_complete
        lastwd = ''
        self.printf('\r\n')
        if self.line_complete:
            self.printf(self.line_complete)
        else:
            self.printf(self.line)
        if not line:
            return line
        lastwd = line.split()[-1]
        completer = self.completer_wd_select(lastwd)
        if not completer.strip():
            self.line_complete = line
            return line
        backlen = len(line_complete) - len(line)
        while backlen>0 and line_complete:
            rmlen, line_complete = self.rm_last_char(line_complete)
            backlen -= rmlen
        self.printf(completer)
        line_complete = line + completer
        self.line_complete = line_complete
    def do_line_complete_end(self):
        if self.completer_on:
            self.line = self.line_complete
            self.line_complete = ''
            self.completer_on = False
    def get_line(self):
        self.line = ''
        self.line_complete = ''
        self.completer_on = False
        while True:
            ch = self.getch()
            if ch == '\r' or ch == '\n':
                self.do_line_complete_end()
                self.printf('\r\n')
                break
            elif ord(ch) == CLI_KEY_BACK or ord(ch) == CLI_KEY_CTRLH:
                if self.completer_on:
                    rmlen, self.line_complete = self.rm_last_char(self.line_complete)
                else:
                    rmlen, self.line = self.rm_last_char(self.line)
                self.do_line_complete_end()
            elif ord(ch) == CLI_KEY_QMARK:
                self.printf('?')
                self.printf('\r\n')
                self.show_help_info()
                if self.completer_on:
                    self.printf(self.line_complete)
                else:
                    self.printf(self.line)
            elif ord(ch) == CLI_KEY_CTRLW:
                if self.completer_on:
                    self.line_complete = self.rm_last_word(self.line_complete)
                else:
                    self.line = self.rm_last_word(self.line)
                self.do_line_complete_end()
            elif ord(ch) == CLI_KEY_TAB:
                self.completer_on = True
                self.do_line_complete_proc()
            elif ord(ch) == CLI_KEY_CTRLD:
                if self.line:
                    return self.line
                else:
                    return ch
            elif ord(ch) == CLI_KEY_QUIT:
                self.printf('\r\n Interrupted by <Ctrl-\>.\r\n')
                sys.exit()
            elif ord(ch) == CLI_KEY_CTRLU:
                if self.completer_on:
                    self.line_complete = self.rm_one_line(self.line_complete)
                else:
                    self.line = self.rm_one_line(self.line)
                self.do_line_complete_end()
            elif ord(ch) == CLI_KEY_SPACE:
                self.printf(ch)
                if self.completer_on:
                    self.line_complete += ch
                else:
                    self.line += ch
            else:
                self.printf(ch)
                self.do_line_complete_end()
                self.line += ch
                # chinese qmask proc
                if ord(ch) == 159 and len(self.line)>= 3 and self.line[-3:] == '\xef\xbc\x9f':
                    self.printf('\r\n')
                    self.line = self.line[:-3]
                    self.show_help_info()
                    self.printf(self.line)
        return self.line
    def get_raw_line(self):
        self.raw_line = ''
        while True:
            ch = self.getch()
            if ch == '\r' or ch == '\n':
                self.printf('\r\n')
                break
            elif ord(ch) == CLI_KEY_BACK or ord(ch) == CLI_KEY_CTRLH:
                rmlen, self.raw_line = self.rm_last_char(self.raw_line)
            elif ord(ch) == CLI_KEY_CTRLW:
                self.raw_line = self.rm_last_word(self.raw_line)
            elif ord(ch) == CLI_KEY_TAB:
                self.printf(' ' * self.char_display_len(ch))
                self.raw_line += ch
            elif ord(ch) == CLI_KEY_CTRLD:
                if self.raw_line:
                    return self.raw_line
                else:
                    return ch
            elif ord(ch) == CLI_KEY_QUIT:
                self.printf('\r\n Interrupted by <Ctrl-\>.\r\n')
                sys.exit()
            elif ord(ch) == CLI_KEY_CTRLU:
                self.raw_line = self.rm_one_line(self.raw_line)
            else:
                self.raw_line += ch
                self.printf(ch)
        return self.raw_line

def test():
    cli = CLI()
    help_info = {
    	'hello0':     'say hello 0',
    	'hello1':     'say hello 1',
    	'hellohello': 'say hello hello',
    	'hellohehe':  'say hello hehe',
    	'hellohi':    'say hello hi',
    	'你好啊':      'say 你好啊',
    	'你好吗':      'say 你好吗',
    	'你好哈':      'say 你好哈',
    	}
    for key in help_info:
        cli.completer_kw_add(key, help_info[key])
    while True:
        line = cli.get_line()
        if len(line) == 1 and ord(line[0]) == CLI_KEY_CTRLD:
            break
        if line == 'quit':
            break
        print(line)

if __name__ == "__main__": 
    test()

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 在Python中,您可以使用内置的模块来测试终端开发的底层接口。以下是一些您可以使用的模块: 1. unittest模块:这是Python的标准单元测试框架。您可以使用该模块来编写和运测试用例,测试您的底层接口是否按照预期工作。 2. doctest模块:该模块允许您在docstring中编写测试用例。这对于测试简单的函数和方法非常有用。 3. mock模块:该模块允许您模拟和替换代码中的对象和函数。这对于测试依赖其他模块或API的代码非常有用。 4. subprocess模块:该模块允许您在Python中启动子进程并与其交互。这对于测试终端应用程序和命令界面非常有用。 使用这些模块,您可以轻松地编写和运测试用例,以确保您的底层接口按照预期工作,并且可以快速识别和修复任何问题。 ### 回答2: Python是一种强大的编程语言,广泛用于开发终端应用程序和测试底层接口。下面是使用Python终端开发底层接口测试的一般步骤: 1. 导入所需库:使用Python终端开发底层接口测试需要导入一些相关的库,如serial(用于与串口通信)、telnetlib(用于与网络设备通信)等。 2. 设置测试环境:建立与终端或设备的连接,可以选择串口连接或网络连接,并确保连接正常。 3. 发送测试命令使用Python编写测试脚本,并通过已建立的连接发送测试命令终端或设备。可以使用相应的库函数发送串口数据或网络数据。 4. 接收和处理响应:等待终端或设备返回响应,并使用相关的函数接收响应数据。根据测试需求,对响应数据进处理和分析。 5. 验证测试结果:根据测试需求和预期结果,对接收到的响应数据进验证。可以使用断言语句来进结果的验证,并根据验证结果输出相应的测试报告。 6. 清理测试环境:测试完成后,需要关闭与终端或设备的连接,并进必要的清理工作。 这些是使用Python终端开发底层接口测试的基本步骤。使用Python接口测试可以帮助开发人员更方便、快捷地验证底层接口的准确性和功能性。同时,Python丰富的库和模块也为开发人员提供了各种强大的功能,如发送模拟数据、自动生成测试报告等,使测试工作更加高效和自动化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值