autestoy 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
autestoy-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aoiiiix
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: autestoy
3
+ Version: 0.1.0
4
+ Summary: autestoy is a Python toy library for automating tests. autestoy -> auto test toy
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: asyncssh>=2.22.0
9
+ Requires-Dist: nicegui>=3.9.0
10
+ Requires-Dist: paramiko>=4.0.0
11
+ Requires-Dist: pyserial>=3.5
12
+ Requires-Dist: reportlib>=3.4.0
13
+ Requires-Dist: rich>=14.3.3
14
+ Requires-Dist: sdev>=0.7.10
15
+ Dynamic: license-file
16
+
17
+ # 简介
18
+
19
+ 一个尝试用于特定场景的不专业(指作者)的原型验证自动化测试工具
20
+
21
+ 名称一拍脑袋 auto+test+toy
22
+
23
+ 处于早早早早期阶段
24
+
25
+ ## 设计理念
26
+
27
+ - 协议支持保持可移植性,不应引入具体的细节支持,例如支持特定产品
28
+ - 考虑到使用环境,数据类切片应靠近verilog语法
29
+
30
+ # 项目结构
31
+
32
+ ## 目前的src树
33
+
34
+
35
+ ```bash
36
+ src
37
+ ├── autestoy
38
+ │   ├── __init__.py # 暴露API
39
+ │   ├── export # 导出相关功能源码目录
40
+ │   │   ├── collect.py # 收集器,用于记录的收集
41
+ │   │   ├── obsidian.py # obsidian格式(markdown+mermaid)生成器
42
+ │   │   ├── pdf.py # pdf报告生成器
43
+ │   │   ├── term.py # 终端显示、样式、时间戳配置
44
+ │   │   └── web.py # web报告生成器,暂定niegui
45
+ │   ├── protocols # 测试通路协议相关源码目录
46
+ │   │   ├── jtag.py # jtag通路,作者相关知识储备较少,优先级降低
47
+ │   │   ├── serial.py # 串口连接
48
+ │   │   ├── ssh.py # ssh、sftp
49
+ │   │   └── telnet.py # telnet协议连接
50
+ │   └── tools # 工具源码目录
51
+ │   ├── ansi.py # 终端显示ansi转义
52
+ │   ├── datatype.py # 数据类,创建易于操作的寄存器值以及数据转换
53
+ │   ├── result.py # 定义协议返回的结果,用于处理与报告生成
54
+ │   └── timestamp.py # 时间戳工具
55
+ ...
56
+ ```
57
+
58
+ ## 依赖关系
59
+
60
+ # 未来规划
61
+
62
+ - 尽快完善基础功能,至少完成一条完整的测试-显示-导出报告的流程
63
+ - 多环境测试
64
+ - 打包发布
65
+
66
+ ### 畅想(coding过程中的灵光一动)
67
+ - 实现字段类,将寄存器拆为多个字段直接控制
68
+ - 元编程,实时处理
69
+
70
+ # 快速开始
71
+
72
+
73
+ # 具体细节
74
+ (想到哪写到哪)
75
+
76
+ ## protocols
77
+
78
+ ### ssh
79
+
80
+ #### class SSH
81
+
82
+ - SSH
83
+
84
+ SSH实现了两套方法,一种是基于ssh连接的exec_run,每运行一次会创建一个通道,运行结束后销毁,所以无法保持上下文、路径等,运行效率稍低,但方便处理;
85
+ ```python
86
+ remote_config = RemoteConfig(...)
87
+ dut = SSH(remote_config)
88
+ dut.exec_run('cd path') # 每次exec_run都会创建一个新的通道,因此这条cd命令只在此次命令中有效
89
+ # home/path/
90
+ dut.exec_run('pwd') # 再次运行pwd目录恢复到创建channel时的默认路径
91
+ # home
92
+ dut.set_globel_path('./path') # global_path是类内部维护的一个全局路径,等同于在所有命令前加入cd命令
93
+ dut.exec_run('pwd') # 等同于 "cd ./path && pwd"
94
+ # home/path/
95
+ dut.with_path('home/another_path/').exec_run('pwd') # with_path会设置一个只能执行一次的临时路径,使用exec_run后消失
96
+ # /home/another_path
97
+ dut.exec_run('pwd')
98
+ # /home/path
99
+ dut.cd('new_path') # cd方法作用于global_path,切换全局路径
100
+ dut.exec_run('pwd')
101
+ # /home/path/new_path
102
+ ```
103
+ 还实现了long_running即长时间后台运行命令,通过threading库实现多线程运行,以达成不阻塞后续命令运行的效果。使用fifo在进程间传递命令的输出,可以做到实时处理输出特征。
104
+ ```python
105
+ process = dut.long_running('python create_log.py') # 设想这是一条可以持续产生log的脚本
106
+ tail_res = dut.long_running('tail -f log.txt') # 实时显示log输出
107
+ # 粗糙的处理流程,待改进
108
+ now = time.time()
109
+ while time.time() - now < 10: # 10s后退出
110
+ if not tail_res.fifo.enpty() and 'fail' in tail_res.fifo.get(): # fifo非空且'fail' 在fifo中,则退出
111
+ break
112
+ # 杀死进程:内部先使用stdin发送ctrl-c给远程退出信号,再运行td.Event.set()结束本地线程。
113
+ process.task_kill()
114
+ tail_res.task_kill()
115
+ # 查看进程状态,如果命令阻塞可能无法响应td.Event事件
116
+ print(process.long_running_task.is_alive())
117
+ print(tail_res.long_running_task.is_alive())
118
+ ```
119
+
120
+ 另一种是基于channel的交互式run方法,所有命令基于一个channel,可以保持上下文,效率高,但是处理复杂,需要自行识别命令行提示符号,不支持花里胡哨的命令行提示符。
121
+
122
+ channel的处理逻辑是根据正则表达式捕获命令行提示符,如果命令输出刚好匹配到了该正则,会导致输出处理提前结束,并影响后续命令。目前没有很好的解决方法。
123
+
124
+ ```python
125
+ remote_config = RemoteConfig(...)
126
+ dut = SSH(remote_config)
127
+ dut_ch1 = dut.create_channel()
128
+ # 如果远程环境使用了花里胡哨的终端,例如zsh {    ~/Project/autestoy ... ✔  autestoy  }这样子的提示符,并且在初始化channel时卡处
129
+ # 可以尝试设置insert_cmd参数,将在自动匹配终端提示符前发送一条命令
130
+ # 例如 ch1 = dut.create_channel(insert_cmd="bash"),这将切换为bash环境
131
+ dut_ch1.run('pwd')
132
+ # home
133
+ dut_ch1.run('cd path') # 在同一channel中运行,上下文继承
134
+ dut_ch1.run('pwd')
135
+ # home/path
136
+ ```
137
+
138
+ 基于channel的实现无long_running方法,实现long_running即会占用该通道,不如直接创建新通道运行。
139
+
140
+ - 关于term输出的时间戳
141
+
142
+ 时间戳大部分在获取返回内容并处理完成后输出时添加,所以并不代表命令输出的实际精确时间。但也可以一定程度上反映多线程语句输出的前后关系。
143
+
144
+ ## tools
145
+
146
+ ### datatype
147
+
148
+ #### class Bits
149
+
150
+ - 创建Bits:
151
+
152
+ Bits是为可以快速创建和修改特定位的数据类。以特定的切片格式快速访问和修改单个bit或bit字段。
153
+
154
+ 1. 从int创建:
155
+
156
+ int无法反映数据宽度,必须指定width参数
157
+ ```python
158
+ reg = Bits( 65535 , 16 ) # 0xFFFF 16bits
159
+ reg = Bits( 0x1234 , 8 ) # 0x34 8bits :发生高位截断
160
+ reg = Bits( 0b1111 , 32 ) # 0x0000_000F 32bits :高位补0
161
+ ```
162
+ 2. 从str创建:
163
+
164
+ 带有位数标识的字符串可以省略width,也可以使用width重新指定宽度;
165
+
166
+ 没有位数标识的字符串必须指定width;
167
+
168
+ ```python
169
+ reg = Bits( "0x1234_u8" ) # 0x34 8bits :字符串解析也会造成截断
170
+ reg = Bits( "0x1234_i8" , 16) # 0x0034 16bits :width指定宽度在字符串解析后作用,因此这种写法会并不会防止截断
171
+ reg = Bits( "0x1234" , 32) # 0x0000_1234 32bits :字符串无宽度标识时,需要指定宽度
172
+ reg = Bits( "8'hFF" , 8 ) # 0xFF 8bits :str支持verilog近似的语法,分隔副使用英文单引号,因此字符串使用双引号括起
173
+ reg = Bits( "32'hDEADBEAF" ) # 0xDEAD_BEAF 32bits :当然可以省略width
174
+ reg = Bits( "2.5E4" , 16) # 2500 16bits :科学计数法解析结果为float的字符串如果转换为int值不变,也可以被Bits接受
175
+ reg = Bits( "3.0E2_u8" ) # 0x2C 8bits :也支持科学计数法+标注位数,可以不指定width,当然也受到截断影响
176
+ ```
177
+ 目前"u8"、"i8"等有符号/无符号标识没有作区别处理。
178
+
179
+ 3. 从可迭代对象创建:
180
+
181
+ 可迭代对象的子类型可以是任意上述创建方法,需要指定宽度的传入元组携带参数,返回所有对象的拼接Bits
182
+
183
+ ```python
184
+ reg = Bits([ "8'hFF" , (0xAB,8) , ("255",8) , "0b0001_0010_i8"])
185
+ # reg -> 0xFFAB_FF12 32bits ,
186
+ ```
187
+ - Bits切片:
188
+
189
+ Bits切片遵循类似verilog的语法。
190
+
191
+ 1. Bits[n] 返回单比特,默认右侧低位
192
+ ```python
193
+ reg = Bits(0b0001_0000 , 8)
194
+ reg[3] -> Bits(0b0,1) # 默认右侧低位,第4位
195
+ reg[3:] -> Bits(0b0,1) # 指定右侧低位,第4位
196
+ reg[:3] -> Bits(0b1,1) # 指定左侧低位,第4位
197
+ ```
198
+ 2. Bits[a:b] a>b 右侧为低位 ; a<b 左侧为低位
199
+ ```python
200
+ reg = Bits( 0x1234_5678 , 32 )
201
+ reg[15:0] == res[16:31] == Bits( 0x5678 , 16 )
202
+ reg[0:15] == reg[31:16] == Bits( 0x1234 , 16 )
203
+ ```
204
+ 3. Bits[ a:b , c ...] 混合切片拼接
205
+ ```python
206
+ reg = Bits( 0x1234_5678 , 32 )
207
+ # 单bit拼接
208
+ reg[ 3 , 2 , 1 , 0 ] == reg[ 3: , 2: , 1: , 0: ] == reg[3:0] == Bits( 0x8 , 4 )
209
+ # 切片拼接
210
+ reg[ 7:0 , 0:7] == Bits( 0x7812 , 16 )
211
+ # 混合拼接
212
+ reg[ :0 , 1:2 , :3 ] == reg[0:3] == Bits( 0x1 , 4 )
213
+ ```
214
+
215
+
216
+ # ToDoList
217
+
218
+ - [ ] 为ssh-Channel.run/SSH.exec_run实现短交互命令,例如sudo登陆
219
+ - [x] ssh-SSH/Channel类初始化添加时间戳记录,考虑新的?Record类:MataRecord?
220
+ - [ ] 为?Record类添加方便的取值方法
221
+ - [ ] SSH、Channel、SFTP添加最近一次输出缓存
222
+ - [ ] ?Reocrd类添加保存错误退出码的属性
223
+
224
+ - [ ] 统一测试文件,运行时使用ftp传输运行脚本到远程被测试端,测试完成后删除
225
+ - [x] ftp服务
226
+ - [x] 添加CmdRecord,并作兼容处理->Result[T]
227
+ - [ ] 两端文件hash校验
228
+ - [ ] 获取远程服务器平台,可执行文件列表,hash命令
229
+ - [ ] 本地hashlib实现文件校验
230
+
231
+ - [x] 记录每一行命令输出的时间戳
232
+ - [x] Result-CmdRecord、CmdRecording为每一行输出添加时间戳
233
+ - [x] 更改print函数->可拓展是否显示时间戳,更改样式
234
+ - [x] 实现Timestamp类,替代time.time()
235
+
236
+ - [ ] 数据类-完善
237
+ - [x] np.array(uint8) 数据转换,bit切片转换 -> numpy引入处理复杂度,无极端速度需求,去除
238
+ - [ ] Bits
239
+ - [x] 基础切片
240
+ - [ ] 附加功能切片(还没想好)
241
+ - [ ] 段赋值
242
+ - [ ] Binary(Bits)
243
+ - [ ] Hexadecimal(Bits)
244
+ - [ ] Decimal(Bits)
245
+ - [ ] Field(Bits):寄存器子字段Bits
246
+ - [ ] Register(Bits+):带有字段的定长,
247
+ - [ ] Packet(Bits):带有字段的数据包类
248
+
249
+ - [ ] obsidian(markdiwn+mermaid) export
250
+ - [ ] web export
251
+ - [ ] pdf export
252
+ - [x] term display
253
+
254
+
255
+ - [x] BUG:ssh的channel模式run方法,概率性出现回显去除失败。
256
+ - [x] BUG:ssh-create_channel遇到zsh等进行了美化的终端时获取不到prompt死循环->嵌入bash
257
+
258
+
259
+
260
+ - [ ]
261
+
262
+ # 已知问题
263
+
264
+ -
@@ -0,0 +1,248 @@
1
+ # 简介
2
+
3
+ 一个尝试用于特定场景的不专业(指作者)的原型验证自动化测试工具
4
+
5
+ 名称一拍脑袋 auto+test+toy
6
+
7
+ 处于早早早早期阶段
8
+
9
+ ## 设计理念
10
+
11
+ - 协议支持保持可移植性,不应引入具体的细节支持,例如支持特定产品
12
+ - 考虑到使用环境,数据类切片应靠近verilog语法
13
+
14
+ # 项目结构
15
+
16
+ ## 目前的src树
17
+
18
+
19
+ ```bash
20
+ src
21
+ ├── autestoy
22
+ │   ├── __init__.py # 暴露API
23
+ │   ├── export # 导出相关功能源码目录
24
+ │   │   ├── collect.py # 收集器,用于记录的收集
25
+ │   │   ├── obsidian.py # obsidian格式(markdown+mermaid)生成器
26
+ │   │   ├── pdf.py # pdf报告生成器
27
+ │   │   ├── term.py # 终端显示、样式、时间戳配置
28
+ │   │   └── web.py # web报告生成器,暂定niegui
29
+ │   ├── protocols # 测试通路协议相关源码目录
30
+ │   │   ├── jtag.py # jtag通路,作者相关知识储备较少,优先级降低
31
+ │   │   ├── serial.py # 串口连接
32
+ │   │   ├── ssh.py # ssh、sftp
33
+ │   │   └── telnet.py # telnet协议连接
34
+ │   └── tools # 工具源码目录
35
+ │   ├── ansi.py # 终端显示ansi转义
36
+ │   ├── datatype.py # 数据类,创建易于操作的寄存器值以及数据转换
37
+ │   ├── result.py # 定义协议返回的结果,用于处理与报告生成
38
+ │   └── timestamp.py # 时间戳工具
39
+ ...
40
+ ```
41
+
42
+ ## 依赖关系
43
+
44
+ # 未来规划
45
+
46
+ - 尽快完善基础功能,至少完成一条完整的测试-显示-导出报告的流程
47
+ - 多环境测试
48
+ - 打包发布
49
+
50
+ ### 畅想(coding过程中的灵光一动)
51
+ - 实现字段类,将寄存器拆为多个字段直接控制
52
+ - 元编程,实时处理
53
+
54
+ # 快速开始
55
+
56
+
57
+ # 具体细节
58
+ (想到哪写到哪)
59
+
60
+ ## protocols
61
+
62
+ ### ssh
63
+
64
+ #### class SSH
65
+
66
+ - SSH
67
+
68
+ SSH实现了两套方法,一种是基于ssh连接的exec_run,每运行一次会创建一个通道,运行结束后销毁,所以无法保持上下文、路径等,运行效率稍低,但方便处理;
69
+ ```python
70
+ remote_config = RemoteConfig(...)
71
+ dut = SSH(remote_config)
72
+ dut.exec_run('cd path') # 每次exec_run都会创建一个新的通道,因此这条cd命令只在此次命令中有效
73
+ # home/path/
74
+ dut.exec_run('pwd') # 再次运行pwd目录恢复到创建channel时的默认路径
75
+ # home
76
+ dut.set_globel_path('./path') # global_path是类内部维护的一个全局路径,等同于在所有命令前加入cd命令
77
+ dut.exec_run('pwd') # 等同于 "cd ./path && pwd"
78
+ # home/path/
79
+ dut.with_path('home/another_path/').exec_run('pwd') # with_path会设置一个只能执行一次的临时路径,使用exec_run后消失
80
+ # /home/another_path
81
+ dut.exec_run('pwd')
82
+ # /home/path
83
+ dut.cd('new_path') # cd方法作用于global_path,切换全局路径
84
+ dut.exec_run('pwd')
85
+ # /home/path/new_path
86
+ ```
87
+ 还实现了long_running即长时间后台运行命令,通过threading库实现多线程运行,以达成不阻塞后续命令运行的效果。使用fifo在进程间传递命令的输出,可以做到实时处理输出特征。
88
+ ```python
89
+ process = dut.long_running('python create_log.py') # 设想这是一条可以持续产生log的脚本
90
+ tail_res = dut.long_running('tail -f log.txt') # 实时显示log输出
91
+ # 粗糙的处理流程,待改进
92
+ now = time.time()
93
+ while time.time() - now < 10: # 10s后退出
94
+ if not tail_res.fifo.enpty() and 'fail' in tail_res.fifo.get(): # fifo非空且'fail' 在fifo中,则退出
95
+ break
96
+ # 杀死进程:内部先使用stdin发送ctrl-c给远程退出信号,再运行td.Event.set()结束本地线程。
97
+ process.task_kill()
98
+ tail_res.task_kill()
99
+ # 查看进程状态,如果命令阻塞可能无法响应td.Event事件
100
+ print(process.long_running_task.is_alive())
101
+ print(tail_res.long_running_task.is_alive())
102
+ ```
103
+
104
+ 另一种是基于channel的交互式run方法,所有命令基于一个channel,可以保持上下文,效率高,但是处理复杂,需要自行识别命令行提示符号,不支持花里胡哨的命令行提示符。
105
+
106
+ channel的处理逻辑是根据正则表达式捕获命令行提示符,如果命令输出刚好匹配到了该正则,会导致输出处理提前结束,并影响后续命令。目前没有很好的解决方法。
107
+
108
+ ```python
109
+ remote_config = RemoteConfig(...)
110
+ dut = SSH(remote_config)
111
+ dut_ch1 = dut.create_channel()
112
+ # 如果远程环境使用了花里胡哨的终端,例如zsh {    ~/Project/autestoy ... ✔  autestoy  }这样子的提示符,并且在初始化channel时卡处
113
+ # 可以尝试设置insert_cmd参数,将在自动匹配终端提示符前发送一条命令
114
+ # 例如 ch1 = dut.create_channel(insert_cmd="bash"),这将切换为bash环境
115
+ dut_ch1.run('pwd')
116
+ # home
117
+ dut_ch1.run('cd path') # 在同一channel中运行,上下文继承
118
+ dut_ch1.run('pwd')
119
+ # home/path
120
+ ```
121
+
122
+ 基于channel的实现无long_running方法,实现long_running即会占用该通道,不如直接创建新通道运行。
123
+
124
+ - 关于term输出的时间戳
125
+
126
+ 时间戳大部分在获取返回内容并处理完成后输出时添加,所以并不代表命令输出的实际精确时间。但也可以一定程度上反映多线程语句输出的前后关系。
127
+
128
+ ## tools
129
+
130
+ ### datatype
131
+
132
+ #### class Bits
133
+
134
+ - 创建Bits:
135
+
136
+ Bits是为可以快速创建和修改特定位的数据类。以特定的切片格式快速访问和修改单个bit或bit字段。
137
+
138
+ 1. 从int创建:
139
+
140
+ int无法反映数据宽度,必须指定width参数
141
+ ```python
142
+ reg = Bits( 65535 , 16 ) # 0xFFFF 16bits
143
+ reg = Bits( 0x1234 , 8 ) # 0x34 8bits :发生高位截断
144
+ reg = Bits( 0b1111 , 32 ) # 0x0000_000F 32bits :高位补0
145
+ ```
146
+ 2. 从str创建:
147
+
148
+ 带有位数标识的字符串可以省略width,也可以使用width重新指定宽度;
149
+
150
+ 没有位数标识的字符串必须指定width;
151
+
152
+ ```python
153
+ reg = Bits( "0x1234_u8" ) # 0x34 8bits :字符串解析也会造成截断
154
+ reg = Bits( "0x1234_i8" , 16) # 0x0034 16bits :width指定宽度在字符串解析后作用,因此这种写法会并不会防止截断
155
+ reg = Bits( "0x1234" , 32) # 0x0000_1234 32bits :字符串无宽度标识时,需要指定宽度
156
+ reg = Bits( "8'hFF" , 8 ) # 0xFF 8bits :str支持verilog近似的语法,分隔副使用英文单引号,因此字符串使用双引号括起
157
+ reg = Bits( "32'hDEADBEAF" ) # 0xDEAD_BEAF 32bits :当然可以省略width
158
+ reg = Bits( "2.5E4" , 16) # 2500 16bits :科学计数法解析结果为float的字符串如果转换为int值不变,也可以被Bits接受
159
+ reg = Bits( "3.0E2_u8" ) # 0x2C 8bits :也支持科学计数法+标注位数,可以不指定width,当然也受到截断影响
160
+ ```
161
+ 目前"u8"、"i8"等有符号/无符号标识没有作区别处理。
162
+
163
+ 3. 从可迭代对象创建:
164
+
165
+ 可迭代对象的子类型可以是任意上述创建方法,需要指定宽度的传入元组携带参数,返回所有对象的拼接Bits
166
+
167
+ ```python
168
+ reg = Bits([ "8'hFF" , (0xAB,8) , ("255",8) , "0b0001_0010_i8"])
169
+ # reg -> 0xFFAB_FF12 32bits ,
170
+ ```
171
+ - Bits切片:
172
+
173
+ Bits切片遵循类似verilog的语法。
174
+
175
+ 1. Bits[n] 返回单比特,默认右侧低位
176
+ ```python
177
+ reg = Bits(0b0001_0000 , 8)
178
+ reg[3] -> Bits(0b0,1) # 默认右侧低位,第4位
179
+ reg[3:] -> Bits(0b0,1) # 指定右侧低位,第4位
180
+ reg[:3] -> Bits(0b1,1) # 指定左侧低位,第4位
181
+ ```
182
+ 2. Bits[a:b] a>b 右侧为低位 ; a<b 左侧为低位
183
+ ```python
184
+ reg = Bits( 0x1234_5678 , 32 )
185
+ reg[15:0] == res[16:31] == Bits( 0x5678 , 16 )
186
+ reg[0:15] == reg[31:16] == Bits( 0x1234 , 16 )
187
+ ```
188
+ 3. Bits[ a:b , c ...] 混合切片拼接
189
+ ```python
190
+ reg = Bits( 0x1234_5678 , 32 )
191
+ # 单bit拼接
192
+ reg[ 3 , 2 , 1 , 0 ] == reg[ 3: , 2: , 1: , 0: ] == reg[3:0] == Bits( 0x8 , 4 )
193
+ # 切片拼接
194
+ reg[ 7:0 , 0:7] == Bits( 0x7812 , 16 )
195
+ # 混合拼接
196
+ reg[ :0 , 1:2 , :3 ] == reg[0:3] == Bits( 0x1 , 4 )
197
+ ```
198
+
199
+
200
+ # ToDoList
201
+
202
+ - [ ] 为ssh-Channel.run/SSH.exec_run实现短交互命令,例如sudo登陆
203
+ - [x] ssh-SSH/Channel类初始化添加时间戳记录,考虑新的?Record类:MataRecord?
204
+ - [ ] 为?Record类添加方便的取值方法
205
+ - [ ] SSH、Channel、SFTP添加最近一次输出缓存
206
+ - [ ] ?Reocrd类添加保存错误退出码的属性
207
+
208
+ - [ ] 统一测试文件,运行时使用ftp传输运行脚本到远程被测试端,测试完成后删除
209
+ - [x] ftp服务
210
+ - [x] 添加CmdRecord,并作兼容处理->Result[T]
211
+ - [ ] 两端文件hash校验
212
+ - [ ] 获取远程服务器平台,可执行文件列表,hash命令
213
+ - [ ] 本地hashlib实现文件校验
214
+
215
+ - [x] 记录每一行命令输出的时间戳
216
+ - [x] Result-CmdRecord、CmdRecording为每一行输出添加时间戳
217
+ - [x] 更改print函数->可拓展是否显示时间戳,更改样式
218
+ - [x] 实现Timestamp类,替代time.time()
219
+
220
+ - [ ] 数据类-完善
221
+ - [x] np.array(uint8) 数据转换,bit切片转换 -> numpy引入处理复杂度,无极端速度需求,去除
222
+ - [ ] Bits
223
+ - [x] 基础切片
224
+ - [ ] 附加功能切片(还没想好)
225
+ - [ ] 段赋值
226
+ - [ ] Binary(Bits)
227
+ - [ ] Hexadecimal(Bits)
228
+ - [ ] Decimal(Bits)
229
+ - [ ] Field(Bits):寄存器子字段Bits
230
+ - [ ] Register(Bits+):带有字段的定长,
231
+ - [ ] Packet(Bits):带有字段的数据包类
232
+
233
+ - [ ] obsidian(markdiwn+mermaid) export
234
+ - [ ] web export
235
+ - [ ] pdf export
236
+ - [x] term display
237
+
238
+
239
+ - [x] BUG:ssh的channel模式run方法,概率性出现回显去除失败。
240
+ - [x] BUG:ssh-create_channel遇到zsh等进行了美化的终端时获取不到prompt死循环->嵌入bash
241
+
242
+
243
+
244
+ - [ ]
245
+
246
+ # 已知问题
247
+
248
+ -
@@ -0,0 +1,30 @@
1
+ [project]
2
+ name = "autestoy"
3
+ version = "0.1.0"
4
+ description = "autestoy is a Python toy library for automating tests. autestoy -> auto test toy"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "asyncssh>=2.22.0",
9
+ "nicegui>=3.9.0",
10
+ "paramiko>=4.0.0",
11
+ "pyserial>=3.5",
12
+ "reportlib>=3.4.0",
13
+ "rich>=14.3.3",
14
+ "sdev>=0.7.10",
15
+ ]
16
+
17
+
18
+ [tool.uv]
19
+ package = true
20
+
21
+ [tool.pytest.ini_options]
22
+ pythonpath = [
23
+ "./src",
24
+ # "./.venv/lib/python3.12/site-packages"
25
+ ]
26
+
27
+ [dependency-groups]
28
+ dev = [
29
+ "pytest>=9.0.2",
30
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,28 @@
1
+ from .export.term import Term, TermStyle
2
+ from .protocols.ssh import SSH, Channel_collect, RemoteConfig, SFTP_collect, SSH_collect
3
+ from .tools.ansi import AnsiBackground, AnsiColor, AnsiReset, AnsiStyle
4
+ from .tools.record import CmdRecord
5
+ from .tools.timestamp import Timestamp
6
+
7
+ # from .tools.ansi import remove_ansi,remove_ansi_bytes
8
+ __all__ = [
9
+ "SSH",
10
+ "RemoteConfig",
11
+ "CmdRecord",
12
+ "Timestamp",
13
+ "Channel_collect",
14
+ "SSH_collect",
15
+ "SFTP_collect",
16
+ "Term",
17
+ "TermStyle",
18
+ "GlobalTimeBase",
19
+ ]
20
+
21
+ # 脚本的基础时间
22
+ GlobalTimeBase = Timestamp()
23
+ # 终端显示相对时间的计算基时
24
+ Term.set_time_base(GlobalTimeBase)
25
+ # 导入库时显示本地时间
26
+ Term.putsln(
27
+ f"{AnsiStyle.bold}{AnsiColor.black}{AnsiBackground.yellow}[INFO] Srcipt start at [{Term.time_base}]{AnsiReset}"
28
+ )
@@ -0,0 +1,22 @@
1
+ """实现脚本输出收集,通过装饰器等"""
2
+
3
+ from functools import wraps
4
+
5
+
6
+ def collect(storage_dict: dict):
7
+ """
8
+ 类装饰器:将每个实例添加到 storage_dict 中。要求类的实例拥有name属性作为字典的键
9
+ """
10
+
11
+ def decorator(cls):
12
+ original_init = cls.__init__
13
+
14
+ @wraps(original_init)
15
+ def new_init(self, *args, **kwargs):
16
+ original_init(self, *args, **kwargs)
17
+ storage_dict[self.name] = self # 实例创建后立即保存
18
+
19
+ cls.__init__ = new_init
20
+ return cls
21
+
22
+ return decorator
@@ -0,0 +1,15 @@
1
+ """
2
+ 生成obsidian格式的导出文件相关工具(markdown + mermaid)
3
+ """
4
+
5
+ import inspect
6
+ import os
7
+
8
+
9
+ class ObsidianExporter:
10
+ def __init__(self, output_path: str | None = None) -> None:
11
+ self.output_path = (
12
+ output_path if output_path else os.path.abspath(inspect.stack()[1].filename)
13
+ )
14
+
15
+ print(f"Output path: {self.output_path}")
@@ -0,0 +1,3 @@
1
+ """
2
+ 用于导出pdf
3
+ """