dsh-origin-bridge 0.4.2 → 0.4.3
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.
- package/README.md +299 -295
- package/originlab.py +62 -4
- package/package.json +1 -5
- package/server.py +11 -3
- package/smoke_test.py +11 -3
- package/cases/catalogue.py +0 -636
- package/cases/data.py +0 -120
- package/render_realdata.py +0 -99
- package/run_cases.py +0 -304
package/cases/catalogue.py
DELETED
|
@@ -1,636 +0,0 @@
|
|
|
1
|
-
"""The case bank: human-style prompts + expected outcomes for all 27 tools.
|
|
2
|
-
|
|
3
|
-
Grouped by side-effect level, because that is what decides how a case may be
|
|
4
|
-
run and what it leaves behind:
|
|
5
|
-
|
|
6
|
-
L0 read-only, never touches Origin (pure parsing / preset metadata)
|
|
7
|
-
L1 read-only, goes through COM (status / inspect / view)
|
|
8
|
-
L2 mutates the Origin session, writes nothing to disk
|
|
9
|
-
L3 writes files to disk (incl. the composite figure / chart_render)
|
|
10
|
-
L4 process level or destructive (exit / reclaim / raw LabTalk)
|
|
11
|
-
|
|
12
|
-
Each case is a prompt a real person might type plus the assertion the runner
|
|
13
|
-
checks. `{name}` in args resolves from a context the runner fills in as it
|
|
14
|
-
goes: datasets from cases/data.py, plus handles that earlier cases `save`.
|
|
15
|
-
|
|
16
|
-
`.bin` workstation samples are out of scope for this bank on purpose.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
import math
|
|
20
|
-
|
|
21
|
-
CASES = []
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def case(level, tool, prompt, args=None, ok=True, code=None, has=(), eq=(), save=None, note="",
|
|
25
|
-
min=(), msg=()):
|
|
26
|
-
CASES.append({"level": level, "tool": tool, "prompt": prompt, "args": dict(args or {}),
|
|
27
|
-
"ok": ok, "code": code, "has": list(has), "eq": list(eq),
|
|
28
|
-
"save": dict(save or {}), "note": note, "min": list(min), "msg": list(msg)})
|
|
29
|
-
return CASES[-1]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# ------------------------------------------------------------------ L0 read-only
|
|
33
|
-
# origin_read_file: pure parsing, the widest surface of "dirty real-world files".
|
|
34
|
-
for key, prompt, has in (
|
|
35
|
-
("dat", "帮我看看这个 .dat 是什么分隔符、几行数据", ["columns", "rows", "delimiter"]),
|
|
36
|
-
("units", "这个文件表头有三行,长名和单位分开写着,能认出列名吗", ["columns", "header_rows"]),
|
|
37
|
-
("csv", "读一下这个 csv,别导入,只告诉我列情况", ["columns", "delimiter"]),
|
|
38
|
-
("semi", "这堆 .txt 是分号隔开的,你看看能不能自动认出来", ["delimiter", "rows"]),
|
|
39
|
-
("spaced", "这个文件是用空格对齐的,不是 tab,能解析吗", ["columns", "delimiter"]),
|
|
40
|
-
("multi", "表头占了好几行,第一行还有个 run 标记,你看它认不认得出列名", ["columns", "header_rows"]),
|
|
41
|
-
("na", "这列里有 NA 和减号表示缺值,解析出来多少个有效点", ["rows", "warnings"]),
|
|
42
|
-
("comment", "开头有 # 注释行,读的时候会不会当成数据", ["rows", "warnings"]),
|
|
43
|
-
("gbk", "这个文件是中文单位、GBK 编码的,你读读看会不会乱码", ["encoding", "columns"]),
|
|
44
|
-
("bom", "文件开头有 BOM,列名会不会带个怪字符", ["columns", "encoding"]),
|
|
45
|
-
("dup", "有两列重名,解析结果里怎么区分", ["columns"]),
|
|
46
|
-
("huge", "这个文件行数比较多,读一下大概多少行", ["rows"]),
|
|
47
|
-
):
|
|
48
|
-
case("L0", "origin_read_file", prompt, {"path": "{%s}" % key}, has=has)
|
|
49
|
-
|
|
50
|
-
case("L0", "origin_read_file", "只有一列数据的文件它能读吗", {"path": "{onecol}"}, ok=False,
|
|
51
|
-
msg=["一列"], note="要说清是只有一列,不能推给『识别不出分隔符』让人去查编码")
|
|
52
|
-
|
|
53
|
-
case("L0", "origin_read_file", "把 sample.dat 的列信息给我", {"path": "{dat}", "comment": "run"},
|
|
54
|
-
has=["columns"])
|
|
55
|
-
case("L0", "origin_read_file", "这个路径下的文件存在吗:C:/nope/not_here.dat", {"path": "C:/nope/not_here.dat"},
|
|
56
|
-
ok=False, note="文件不存在必须报错,不能静默返回空表")
|
|
57
|
-
case("L0", "origin_read_file", "我给了个文件夹路径,你看看它怎么处理", {"path": "{dir}"}, ok=False)
|
|
58
|
-
case("L0", "origin_read_file", "空文件会返回什么?别崩就行", {"path": "{empty}"}, ok=False)
|
|
59
|
-
case("L0", "origin_read_file", "这文件里一个数字都没有", {"path": "{text}"}, ok=False)
|
|
60
|
-
|
|
61
|
-
# 仪器导出:前面几十行参数说明,真正的表头紧贴数据上方,单位写在名字里 "Potential/V"。
|
|
62
|
-
case("L0", "origin_read_file", "这是工作站导出的 txt,开头一大段参数,能找到真正的表头吗",
|
|
63
|
-
{"path": "{chi}"}, eq=[("rows", 40), ("delimiter", ","),
|
|
64
|
-
("columns.0.name", "Potential"), ("columns.0.units", "V"),
|
|
65
|
-
("columns.1.name", "Current"), ("columns.1.units", "A")],
|
|
66
|
-
note="不能把第一行的日期当成列名")
|
|
67
|
-
case("L0", "origin_read_file", "那个工作站 txt 的扫描速率和仪器型号是多少",
|
|
68
|
-
{"path": "{chi}"}, has=["metadata"],
|
|
69
|
-
eq=[("metadata.Instrument Model", "CHI660E")])
|
|
70
|
-
|
|
71
|
-
# Preset metadata: 40 scientific chart presets, pure Python.
|
|
72
|
-
case("L0", "origin_chart_presets", "支持哪些科研图表预设?全列出来", has=["templates", "n_templates"])
|
|
73
|
-
for cat in ("spectroscopy", "electrochemistry", "thermal", "distribution",
|
|
74
|
-
"categorical", "relationship", "medical", "3d"):
|
|
75
|
-
case("L0", "origin_chart_presets", "%s 类有哪些预设" % cat, {"category": cat},
|
|
76
|
-
min=[("templates", 1)])
|
|
77
|
-
case("L0", "origin_chart_presets", "有机器学习类的预设吗", {"category": "does_not_exist"},
|
|
78
|
-
ok=False, code="bad_category", note="不存在的分类要报错并列出可用分类,不能返回空列表当成功")
|
|
79
|
-
case("L0", "origin_chart_presets", "分类名我可能写错,带空格的行不行", {"category": " spectroscopy "},
|
|
80
|
-
min=[("templates", 1)], note="分类应容忍首尾空格,不能静默返回 0 个")
|
|
81
|
-
|
|
82
|
-
for name, ask in (
|
|
83
|
-
("xps", "XPS 那个预设要哪些列"),
|
|
84
|
-
("xrd", "XRD 预设的默认轴标题是什么"),
|
|
85
|
-
("cv", "循环伏安预设建议用什么拟合"),
|
|
86
|
-
("eis", "EIS 预设画的是什么图"),
|
|
87
|
-
("uv_vis", "UV-Vis 预设默认图类型"),
|
|
88
|
-
("tga_dtg", "TGA-DTG 预设要几列"),
|
|
89
|
-
("kaplan_meier", "生存分析那个预设的说明给我看看"),
|
|
90
|
-
("bland_altman", "Bland-Altman 预设需要哪些列"),
|
|
91
|
-
("roc_curve", "ROC 预设是画啥的"),
|
|
92
|
-
("histogram", "直方图预设的默认参数"),
|
|
93
|
-
):
|
|
94
|
-
case("L0", "origin_chart_preset", ask, {"name": name},
|
|
95
|
-
has=["required_columns", "default_axis_titles", "default_plot_kind"])
|
|
96
|
-
case("L0", "origin_chart_preset", "有个叫 not_a_preset 的预设吗", {"name": "not_a_preset"}, ok=False)
|
|
97
|
-
|
|
98
|
-
for name, cols, complete in (
|
|
99
|
-
("xps", ["binding_energy", "intensity"], True),
|
|
100
|
-
("xps", ["binding_energy"], False),
|
|
101
|
-
("cv", ["potential", "current"], True),
|
|
102
|
-
("cv", ["voltage", "i"], False),
|
|
103
|
-
("uv_vis", ["wavelength", "absorbance"], True),
|
|
104
|
-
("tga", ["temperature", "mass_percent"], True),
|
|
105
|
-
("dsc", ["temperature", "heat_flow"], True),
|
|
106
|
-
("eis", ["z_real", "z_imag"], True),
|
|
107
|
-
("xrd", ["two_theta", "intensity"], True),
|
|
108
|
-
("ftir", ["wavenumber", "intensity"], True),
|
|
109
|
-
):
|
|
110
|
-
# chart_check is a dry-run diagnostic: it reports missing columns as a
|
|
111
|
-
# warning rather than failing, so the assertion is on `status`, not on `ok`.
|
|
112
|
-
case("L0", "origin_chart_check",
|
|
113
|
-
"我数据里有 %s 这些列,够不够用 %s 预设" % ("/".join(cols), name),
|
|
114
|
-
{"name": name, "columns": cols},
|
|
115
|
-
eq=[("status", "ok" if complete else "warning")],
|
|
116
|
-
note="" if complete else "缺列要写进 issues,不能报成没问题")
|
|
117
|
-
case("L0", "origin_chart_check", "列信息我给成字典形式的吧",
|
|
118
|
-
{"name": "xps", "data": {"binding_energy": [1, 2], "intensity": [3, 4]}},
|
|
119
|
-
eq=[("status", "ok")], note="data 传字典应当按列名吃下,不能抛 TypeError")
|
|
120
|
-
case("L0", "origin_chart_check", "data 传成列名列表",
|
|
121
|
-
{"name": "xps", "data": ["binding_energy", "intensity"]}, eq=[("status", "ok")])
|
|
122
|
-
case("L0", "origin_chart_check", "data 给个真实文件路径",
|
|
123
|
-
{"name": "xps", "data": "{units}"}, has=["columns_detected"])
|
|
124
|
-
case("L0", "origin_chart_check", "data 给个不存在的路径",
|
|
125
|
-
{"name": "xps", "data": "C:/nope.dat"}, ok=False)
|
|
126
|
-
case("L0", "origin_chart_check", "data 给个数字",
|
|
127
|
-
{"name": "xps", "data": 42}, ok=False, code="bad_arguments")
|
|
128
|
-
case("L0", "origin_chart_check", "啥列都没给,它怎么说",
|
|
129
|
-
{"name": "xps", "columns": []}, eq=[("status", "warning")],
|
|
130
|
-
note="空列表要报出所有缺列")
|
|
131
|
-
case("L0", "origin_chart_check", "预设名不存在时检查会咋样",
|
|
132
|
-
{"name": "nope_not_here", "columns": ["a"]}, ok=False)
|
|
133
|
-
|
|
134
|
-
# ------------------------------------------------------------------ L1 read-only
|
|
135
|
-
# These go through COM but change nothing, so they are the safe bulk.
|
|
136
|
-
for ask in ("现在连上 origin 了吗", "origin 是什么版本", "状态看一下",
|
|
137
|
-
"现在项目里开了哪些页面", "python 是哪个解释器,路径给我",
|
|
138
|
-
"确认一下 origin 活着", "连接正常吗?我刚才崩了一次",
|
|
139
|
-
"看看有没有卡在弹窗上", "origin 装在哪", "再说一次现在的状态"):
|
|
140
|
-
case("L1", "origin_status", ask, has=["connected", "open_pages"])
|
|
141
|
-
|
|
142
|
-
# Bootstrap handles the rest of the bank depends on.
|
|
143
|
-
case("L2", "origin_import", "把这条曲线导进来", {"path": "{dat}"},
|
|
144
|
-
has=["worksheet", "rows", "columns"], save={"ws": "worksheet"})
|
|
145
|
-
case("L2", "origin_import", "这份也导进来,多列的", {"path": "{wide}"},
|
|
146
|
-
has=["worksheet"], save={"wsw": "worksheet"})
|
|
147
|
-
case("L2", "origin_write", "我直接给你数据,你建成表:t 和 v 两列",
|
|
148
|
-
{"columns": "{columns}"}, has=["worksheet"], save={"wsi": "worksheet"})
|
|
149
|
-
|
|
150
|
-
for ask in ("现在有几张图?都列出来", "图里有几个层、几条曲线", "看看那个图页的情况",
|
|
151
|
-
"工作簿里都有啥", "我刚导入的表现在还在吗", "列一下所有页面",
|
|
152
|
-
"这张图的曲线数对吗", "帮我确认图层索引", "句柄都还有效吗",
|
|
153
|
-
"图页名字是什么", "再查一次页面列表", "inspect 一下这张图"):
|
|
154
|
-
case("L1", "origin_inspect", ask, has=["pages", "handles"])
|
|
155
|
-
case("L1", "origin_inspect", "看看这张图的细节", {"graph": "{gr}"}, has=["pages"])
|
|
156
|
-
case("L1", "origin_inspect", "句柄 gr-999 还在吗", {"graph": "gr-999"}, ok=False,
|
|
157
|
-
note="坏句柄要报错,不能回落到活动页")
|
|
158
|
-
|
|
159
|
-
for ask in ("这张图现在长啥样,截给我看", "图渲染出来我看看", "缩小一点再截图",
|
|
160
|
-
"原图给我看一眼", "看看成图效果", "把这张图画布缩到 400 宽",
|
|
161
|
-
"确认图例有没有挡住曲线", "再截一次", "这个图有符号吗", "颜色对不对,看图"):
|
|
162
|
-
case("L1", "origin_view", ask, {"graph": "{gr}", "width": 320}, has=["ok"])
|
|
163
|
-
case("L1", "origin_view", "看一张不存在的图", {"graph": "gr-9999"}, ok=False)
|
|
164
|
-
|
|
165
|
-
# ------------------------------------------------------------------ L2 in-memory
|
|
166
|
-
IMPORT_FILES = ["dat", "units", "csv", "semi", "spaced", "multi", "na", "comment",
|
|
167
|
-
"gbk", "bom", "dup", "wide", "fit", "onecol", "chi"]
|
|
168
|
-
for key in IMPORT_FILES:
|
|
169
|
-
case("L2", "origin_import", "导入 %s 这个文件" % key, {"path": "{%s}" % key},
|
|
170
|
-
has=["worksheet", "rows"])
|
|
171
|
-
case("L2", "origin_import", "导入并把工作簿改名叫 BOOK_A", {"path": "{dat}", "book_name": "BOOK_A"},
|
|
172
|
-
has=["name", "worksheet"])
|
|
173
|
-
case("L2", "origin_import", "路径打错了:C:\\temp\\curve22.dat", {"path": "C:\\temp\\curve22.dat"}, ok=False)
|
|
174
|
-
case("L2", "origin_import", "导入一个空文件", {"path": "{empty}"}, ok=False)
|
|
175
|
-
case("L2", "origin_import", "导入一个只有文字没有数字的文件", {"path": "{text}"},
|
|
176
|
-
has=["warnings"], min=[("warnings", 1)],
|
|
177
|
-
note="Origin 会把散文当成 1 行文本收进来,必须给出警告而不是报成功")
|
|
178
|
-
|
|
179
|
-
case("L2", "origin_write", "内联建表,两列各 5 个点",
|
|
180
|
-
{"columns": {"x": [1, 2, 3, 4, 5], "y": [2, 4, 6, 8, 10]}}, has=["worksheet", "rows"])
|
|
181
|
-
case("L2", "origin_write", "宽表:表头 x/y1/y2,三行数据",
|
|
182
|
-
{"headers": ["x", "y1", "y2"], "rows": [[1, 2, 3], [4, 5, 6], [7, 8, 9]]},
|
|
183
|
-
has=["worksheet", "cols"])
|
|
184
|
-
case("L2", "origin_write", "用我这份 csv 的内容建表", {"columns": "{wide_columns}"}, has=["worksheet"])
|
|
185
|
-
case("L2", "origin_write", "表名就叫 WIDE 吧", {"columns": "{wide_columns}", "book_name": "WIDE"},
|
|
186
|
-
has=["name"])
|
|
187
|
-
case("L2", "origin_write", "两列长度不一样,一个 3 一个 2",
|
|
188
|
-
{"columns": {"x": [1, 2, 3], "y": [1, 2]}}, ok=False, note="长度不齐必须拒收")
|
|
189
|
-
case("L2", "origin_write", "列里混了文字", {"columns": {"x": [1, "abc", 3], "y": [1, 2, 3]}}, ok=False)
|
|
190
|
-
case("L2", "origin_write", "啥都不给就建表", {"columns": {}}, ok=False)
|
|
191
|
-
case("L2", "origin_write", "只有表头没有数据行", {"headers": ["a", "b"], "rows": []}, ok=False)
|
|
192
|
-
case("L2", "origin_write", "行里列数比表头多", {"headers": ["a"], "rows": [[1, 2], [3, 4]]}, ok=False)
|
|
193
|
-
case("L2", "origin_write", "数字给成字符串能容忍吗", {"columns": {"x": ["1", "2"], "y": ["3", "4"]}},
|
|
194
|
-
note="数值字符串应当可以转,转不了要明确报错")
|
|
195
|
-
case("L2", "origin_write", "负数和科学计数法", {"columns": {"x": [-1.5, 2e-3], "y": [1e6, -3.25]}},
|
|
196
|
-
has=["rows"])
|
|
197
|
-
|
|
198
|
-
for pt in ("line", "scatter", "line_symbol", "column"):
|
|
199
|
-
case("L2", "origin_plot", "用 %s 方式画这张表" % pt, {"worksheet": "{ws}", "x": 1, "y": 2,
|
|
200
|
-
"plot_type": pt}, has=["graph"])
|
|
201
|
-
case("L2", "origin_plot", "把第一条曲线画出来", {"worksheet": "{ws}", "x": 1, "y": 2},
|
|
202
|
-
has=["graph", "graph_page", "proof_level"], save={"gr": "graph"})
|
|
203
|
-
case("L2", "origin_plot", "四条 y 一起画到一张图上",
|
|
204
|
-
{"worksheet": "{wsw}", "x": 1, "y": [2, 3, 4, 5]}, has=["plots_in_layer"])
|
|
205
|
-
case("L2", "origin_plot", "用 linesymb 模板画", {"worksheet": "{ws}", "x": 1, "y": 2,
|
|
206
|
-
"template": "linesymb"}, has=["graph", "template"])
|
|
207
|
-
case("L2", "origin_plot", "图页名字叫 MYGRAPH", {"worksheet": "{ws}", "x": 1, "y": 2,
|
|
208
|
-
"graph_name": "MYGRAPH"}, has=["graph_page"])
|
|
209
|
-
case("L2", "origin_plot", "标题写「充放电曲线」", {"worksheet": "{ws}", "x": 1, "y": 2,
|
|
210
|
-
"title": "充放电曲线"}, has=["graph"])
|
|
211
|
-
case("L2", "origin_plot", "画到已有那张图的第 1 层", {"worksheet": "{ws}", "x": 1, "y": 2,
|
|
212
|
-
"graph": "{gr}", "layer": 1}, ok=False,
|
|
213
|
-
note="第 1 层还不存在,应当明确拒绝而不是静默画到别处")
|
|
214
|
-
case("L2", "origin_plot", "句柄瞎写一个 ws-42", {"worksheet": "ws-42", "x": 1, "y": 2},
|
|
215
|
-
ok=False, code="worksheet_not_found")
|
|
216
|
-
case("L2", "origin_plot", "不给 y 列", {"worksheet": "{ws}", "x": 1}, has=["graph"],
|
|
217
|
-
note="y 有默认值 2,省略是合法的")
|
|
218
|
-
case("L2", "origin_plot", "y 给成空列表", {"worksheet": "{ws}", "x": 1, "y": []}, ok=False)
|
|
219
|
-
case("L2", "origin_plot", "模板名我乱写的", {"worksheet": "{ws}", "x": 1, "y": 2,
|
|
220
|
-
"template": "not_a_template"},
|
|
221
|
-
ok=False, code="bad_template")
|
|
222
|
-
case("L2", "origin_plot", "画完再画一次同样的,看看会不会重复", {"worksheet": "{ws}", "x": 1, "y": 2},
|
|
223
|
-
has=["graph"])
|
|
224
|
-
case("L2", "origin_plot", "x 列号写成 0", {"worksheet": "{ws}", "x": 0, "y": 2},
|
|
225
|
-
ok=False, code="bad_column", note="0 会被当成第 1 列,静默错位")
|
|
226
|
-
case("L2", "origin_plot", "y 列号写成 0", {"worksheet": "{ws}", "x": 1, "y": [0]},
|
|
227
|
-
ok=False, code="bad_column")
|
|
228
|
-
|
|
229
|
-
for lt in ("right", "top", "bottom"):
|
|
230
|
-
case("L2", "origin_layer", "加一个 %s 层" % lt, {"graph": "{gr}", "layer_type": lt},
|
|
231
|
-
has=["layer_index", "layers_after"])
|
|
232
|
-
case("L2", "origin_layer", "再加一个右 Y 轴", {"graph": "{gr}", "layer_type": "right"}, has=["ok"])
|
|
233
|
-
case("L2", "origin_layer", "层类型写错成 triple", {"graph": "{gr}", "layer_type": "triple"}, ok=False)
|
|
234
|
-
case("L2", "origin_layer", "在不存在的图上加层", {"graph": "gr-9999", "layer_type": "right"}, ok=False)
|
|
235
|
-
case("L2", "origin_layer", "双 Y 轴常用,加一个", {"graph": "{gr}", "layer_type": "right"},
|
|
236
|
-
has=["layer_type_name"])
|
|
237
|
-
case("L2", "origin_layer", "加层后确认层数变了", {"graph": "{gr}", "layer_type": "top"},
|
|
238
|
-
eq=[("layer_type_name", "TopX")])
|
|
239
|
-
case("L2", "origin_layer", "再来一个 bottom", {"graph": "{gr}", "layer_type": "bottom"}, has=["ok"])
|
|
240
|
-
case("L2", "origin_layer", "不指定层类型", {"graph": "{gr}"}, has=["layer_type_name"],
|
|
241
|
-
note="默认 right,Origin 那边叫 RightY")
|
|
242
|
-
case("L2", "origin_layer", "图句柄给空字符串", {"graph": "", "layer_type": "right"},
|
|
243
|
-
has=["layer_index"], note="空句柄回落到当前活动图页,不能崩")
|
|
244
|
-
|
|
245
|
-
STYLE_CASES = [
|
|
246
|
-
("横轴标题写 Time (s)", {"x_title": "Time (s)"}),
|
|
247
|
-
("纵轴标题 Signal (mV)", {"y_title": "Signal (mV)"}),
|
|
248
|
-
("两个轴标题一起写", {"x_title": "t / s", "y_title": "I / mA"}),
|
|
249
|
-
("横轴改对数", {"x_scale": "log"}),
|
|
250
|
-
("纵轴改对数", {"y_scale": "log"}),
|
|
251
|
-
("X 轴范围设成 0 到 25", {"xlim": [0, 25]}),
|
|
252
|
-
("Y 轴范围 0 到 100", {"ylim": [0, 100]}),
|
|
253
|
-
("横轴主刻度步长 5", {"xtick": 5}),
|
|
254
|
-
("纵轴刻度步长 20", {"ytick": 20}),
|
|
255
|
-
("第一条曲线改红色", {"series": 0, "color": "red"}),
|
|
256
|
-
("线宽加到 3", {"series": 0, "line_width": 3.0}),
|
|
257
|
-
("符号换成三角", {"series": 0, "symbol_kind": 3}),
|
|
258
|
-
("符号放大到 12", {"series": 0, "symbol_size": 12.0}),
|
|
259
|
-
("符号空心", {"series": 0, "symbol_interior": 1}),
|
|
260
|
-
("透明度 40", {"series": 0, "transparency": 40.0}),
|
|
261
|
-
("把曲线下方填充", {"series": 0, "fill_area": 1}),
|
|
262
|
-
("颜色用十六进制", {"series": 0, "color": "#2E86AB"}),
|
|
263
|
-
("轴标题给空字符串清空", {"x_title": ""}),
|
|
264
|
-
("范围反着写 25 到 0", {"xlim": [25, 0]}),
|
|
265
|
-
("范围只给一个数", {"xlim": [5]}),
|
|
266
|
-
("刻度给 0 表示自动", {"xtick": 0}),
|
|
267
|
-
("颜色名写错成 bluuu", {"series": 0, "color": "bluuu"}),
|
|
268
|
-
("同时改标题和线宽", {"x_title": "E / V", "series": 0, "line_width": 2.0}),
|
|
269
|
-
("整层改样式不指定 series", {"layer": 0, "x_title": "Layer title"}),
|
|
270
|
-
]
|
|
271
|
-
for ask, args in STYLE_CASES:
|
|
272
|
-
case("L2", "origin_style", ask, dict({"graph": "{gr}"}, **args), has=["applied", "failed"],
|
|
273
|
-
note="失败项要进 failed 列表,不能表面成功")
|
|
274
|
-
case("L2", "origin_style", "两条曲线的图,把第二条改蓝色",
|
|
275
|
-
{"graph": "{gr2}", "series": 1, "color": "blue"}, has=["applied", "failed"])
|
|
276
|
-
case("L2", "origin_style", "改第 9 条曲线(这张图只有两条)",
|
|
277
|
-
{"graph": "{gr2}", "series": 9, "color": "red"}, ok=False, code="bad_series")
|
|
278
|
-
case("L2", "origin_style", "透明度 40 用在第二条曲线",
|
|
279
|
-
{"graph": "{gr2}", "series": 1, "transparency": 40.0}, has=["applied", "failed"])
|
|
280
|
-
case("L2", "origin_style", "改一张不存在的图", {"graph": "gr-9999", "x_title": "x"}, ok=False)
|
|
281
|
-
case("L2", "origin_style", "图句柄不给", {"x_title": "x"}, ok=False)
|
|
282
|
-
|
|
283
|
-
# Positions come from the engine's own table so the bank cannot drift from it.
|
|
284
|
-
import originlab as _ol
|
|
285
|
-
|
|
286
|
-
for pos in sorted(_ol.LEGEND_POSITIONS):
|
|
287
|
-
case("L2", "origin_legend", "图例放 %s" % pos, {"graph": "{gr}", "position": pos},
|
|
288
|
-
min=[("applied", 1)])
|
|
289
|
-
for bogus in ("corner", "middle_right", "outside", "RIGHT-IN", "none"):
|
|
290
|
-
case("L2", "origin_legend", "图例位置写成 %s" % bogus, {"graph": "{gr}", "position": bogus},
|
|
291
|
-
ok=False, code="bad_position")
|
|
292
|
-
case("L2", "origin_legend", "把图例关掉", {"graph": "{gr}", "show": False},
|
|
293
|
-
eq=[("proof_level", "verified")], note="这条决定预览图有没有图例")
|
|
294
|
-
case("L2", "origin_legend", "重新显示图例", {"graph": "{gr}", "show": True}, has=["applied"])
|
|
295
|
-
case("L2", "origin_legend", "图例文字我指定:['样品', '拟合']",
|
|
296
|
-
{"graph": "{gr}", "entries": ["样品", "拟合"]}, has=["text"])
|
|
297
|
-
case("L2", "origin_legend", "位置写个不存在的 corner", {"graph": "{gr}", "position": "corner"}, ok=False,
|
|
298
|
-
code="bad_position")
|
|
299
|
-
case("L2", "origin_legend", "图例自动按列名生成", {"graph": "{gr}"}, has=["applied"])
|
|
300
|
-
|
|
301
|
-
case("L2", "origin_annotate", "在 (5, 20) 标一个「起始」",
|
|
302
|
-
{"graph": "{gr}", "labels": [{"text": "起始", "x": 5, "y": 20}]}, has=["items"])
|
|
303
|
-
case("L2", "origin_annotate", "加一条 x=12 的竖参考线",
|
|
304
|
-
{"graph": "{gr}", "lines": [{"x": 12}]}, has=["items"])
|
|
305
|
-
case("L2", "origin_annotate", "加一条 y=50 的横线", {"graph": "{gr}", "lines": [{"y": 50}]}, has=["items"])
|
|
306
|
-
case("L2", "origin_annotate", "同时加三个标注",
|
|
307
|
-
{"graph": "{gr}", "labels": [{"text": "a", "x": 2, "y": 5}, {"text": "b", "x": 8, "y": 20},
|
|
308
|
-
{"text": "c", "x": 18, "y": 60}]}, has=["items"])
|
|
309
|
-
case("L2", "origin_annotate", "标注文字用中文带单位",
|
|
310
|
-
{"graph": "{gr}", "labels": [{"text": "峰值 82 mV", "x": 22, "y": 82}]}, has=["items"])
|
|
311
|
-
case("L2", "origin_annotate", "标注和线一起给",
|
|
312
|
-
{"graph": "{gr}", "labels": [{"text": "阈值", "x": 10, "y": 30}], "lines": [{"x": 10}]},
|
|
313
|
-
has=["items"])
|
|
314
|
-
case("L2", "origin_annotate", "坐标超出轴范围会怎样",
|
|
315
|
-
{"graph": "{gr}", "labels": [{"text": "out", "x": 999, "y": 999}]},
|
|
316
|
-
note="允许放但应能读回;不能静默丢")
|
|
317
|
-
case("L2", "origin_annotate", "labels 给成字符串不是列表",
|
|
318
|
-
{"graph": "{gr}", "labels": "text"}, ok=False)
|
|
319
|
-
case("L2", "origin_annotate", "空列表", {"graph": "{gr}", "labels": []}, ok=False,
|
|
320
|
-
code="bad_arguments")
|
|
321
|
-
case("L2", "origin_annotate", "lines 给成字符串列表", {"graph": "{gr}", "lines": ["测试"]},
|
|
322
|
-
ok=False, code="bad_arguments")
|
|
323
|
-
case("L2", "origin_annotate", "lines 里啥坐标都不给", {"graph": "{gr}", "lines": [{"note": "x"}]},
|
|
324
|
-
ok=False, code="bad_arguments")
|
|
325
|
-
case("L2", "origin_annotate", "在不存在的图上标注", {"graph": "gr-9999", "labels": [{"text": "x", "x": 1, "y": 1}]},
|
|
326
|
-
ok=False)
|
|
327
|
-
case("L2", "origin_annotate", "标注在第 1 层", {"graph": "{gr}", "layer": 1,
|
|
328
|
-
"labels": [{"text": "L1", "x": 3, "y": 3}]})
|
|
329
|
-
case("L2", "origin_annotate", "什么都不给", {"graph": "{gr}"}, ok=False)
|
|
330
|
-
|
|
331
|
-
for tpl in ("heat_map", "cmap", "mesh", "contline", "contgray", "3d", "bar3d"):
|
|
332
|
-
case("L2", "origin_matrix", "把这个矩阵画成 %s" % tpl,
|
|
333
|
-
{"rows": "{matrix_rows}", "template": tpl}, has=["graph", "shape"])
|
|
334
|
-
case("L2", "origin_matrix", "只建矩阵不画图", {"rows": "{matrix_rows}"}, has=["matrix_book"])
|
|
335
|
-
case("L2", "origin_matrix", "矩阵书写成 MAT1", {"rows": "{matrix_rows}", "book_name": "MAT1"},
|
|
336
|
-
has=["matrix_book"])
|
|
337
|
-
case("L2", "origin_matrix", "行列不齐的矩阵(第一行 3 个第二行 2 个)",
|
|
338
|
-
{"rows": [[1, 2, 3], [4, 5]]}, ok=False, note="ragged 输入必须拒收")
|
|
339
|
-
case("L2", "origin_matrix", "空矩阵", {"rows": []}, ok=False)
|
|
340
|
-
case("L2", "origin_matrix", "单行矩阵", {"rows": [[1, 2, 3]]}, has=["shape"])
|
|
341
|
-
case("L2", "origin_matrix", "含负值和零", {"rows": [[-1, 0], [0, 1]], "template": "cmap"}, has=["ok"])
|
|
342
|
-
case("L2", "origin_matrix", "指定 xy 范围 [0, 10, 0, 5]",
|
|
343
|
-
{"rows": "{matrix_rows}", "xy_range": [0, 10, 0, 5]}, has=["xlim", "ylim"])
|
|
344
|
-
case("L2", "origin_matrix", "模板名乱写", {"rows": "{matrix_rows}", "template": "nope"}, ok=False)
|
|
345
|
-
case("L2", "origin_matrix", "矩阵标题写「阻抗分布」", {"rows": "{matrix_rows}", "title": "阻抗分布"},
|
|
346
|
-
has=["ok"])
|
|
347
|
-
|
|
348
|
-
for kind in ("linear", "poly3", "expdecay", "gauss", "lorentz", "logistic", "boltzmann",
|
|
349
|
-
"sine", "power", "cubic"):
|
|
350
|
-
case("L2", "origin_fit", "用 %s 拟合一下" % kind,
|
|
351
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "kind": kind}, has=["fit"])
|
|
352
|
-
case("L2", "origin_fit", "线性拟合,把参数报告也生成",
|
|
353
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "kind": "linear", "make_report": True}, has=["fit"])
|
|
354
|
-
case("L2", "origin_fit", "要完整的拟合结果不要裁剪",
|
|
355
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "kind": "linear", "full": True}, has=["result"],
|
|
356
|
-
note="full=True 时整份报告放在 result 里,不再是裁剪过的 fit")
|
|
357
|
-
case("L2", "origin_fit", "自定义函数 y=a*exp(-b*x)+c",
|
|
358
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "func": "a*exp(-b*x)+c",
|
|
359
|
-
"starts": {"a": 1, "b": 0.1, "c": 0}}, ok=False, code="fit_function_unavailable",
|
|
360
|
-
note="NLFit 只认 Origin 里已定义的函数名,表达式不支持,必须明确拒绝")
|
|
361
|
-
case("L2", "origin_fit", "内置函数 ExpDec1 不给 kind",
|
|
362
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "func": "ExpDec1"},
|
|
363
|
-
has=["fit", "note"], eq=[("kind", "nlfitsing")])
|
|
364
|
-
case("L2", "origin_fit", "固定 y0=0 只拟合 A1 和 t1",
|
|
365
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "func": "ExpDec1", "fixed": {"y0": 0}},
|
|
366
|
-
has=["fit", "constraints"])
|
|
367
|
-
case("L2", "origin_fit", "给参数加上下界",
|
|
368
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "func": "ExpDec1", "bounds": {"A1": [0, 100]}},
|
|
369
|
-
has=["constraints"])
|
|
370
|
-
case("L2", "origin_fit", "kind 写 linear 但给了 func",
|
|
371
|
-
{"worksheet": "{wsf}", "x": 1, "y": 2, "kind": "linear", "func": "Gauss"},
|
|
372
|
-
has=["fit", "note"], eq=[("kind", "nlfitsing")])
|
|
373
|
-
case("L2", "origin_fit", "拟合表里第 3 列", {"worksheet": "{wsw}", "x": 1, "y": 3}, has=["fit"])
|
|
374
|
-
case("L2", "origin_fit", "点太少能不能拟合", {"worksheet": "{wsf}", "x": 1, "y": 2}, has=["fit"])
|
|
375
|
-
case("L2", "origin_fit", "函数名不存在的拟合", {"worksheet": "{wsf}", "x": 1, "y": 2,
|
|
376
|
-
"func": "wat*wat"}, ok=False,
|
|
377
|
-
code="fit_function_unavailable")
|
|
378
|
-
case("L2", "origin_fit", "拟合不存在的表", {"worksheet": "ws-9999", "x": 1, "y": 2}, ok=False)
|
|
379
|
-
case("L2", "origin_fit", "列号给成 0", {"worksheet": "{wsf}", "x": 0, "y": 2},
|
|
380
|
-
ok=False, code="bad_column")
|
|
381
|
-
case("L2", "origin_fit", "kind 和 func 都不给", {"worksheet": "{wsf}", "x": 1, "y": 2},
|
|
382
|
-
note="应当走默认或明确报错,不能崩")
|
|
383
|
-
|
|
384
|
-
case("L2", "origin_formula", "加一列算 y 的两倍", {"worksheet": "{ws}", "col": 3,
|
|
385
|
-
"formula": "col(2)*2"}, has=["computed_rows"])
|
|
386
|
-
case("L2", "origin_formula", "派生列名叫 ratio", {"worksheet": "{ws}", "col": 3, "formula": "col(2)/10",
|
|
387
|
-
"label": "ratio"}, has=["columns"])
|
|
388
|
-
case("L2", "origin_formula", "给派生列加单位 mA", {"worksheet": "{ws}", "col": 3, "formula": "col(2)",
|
|
389
|
-
"units": "mA"}, has=["ok"])
|
|
390
|
-
case("L2", "origin_formula", "用 i 索引做线性序列", {"worksheet": "{ws}", "col": 3,
|
|
391
|
-
"formula": "i*0.5"}, has=["last"])
|
|
392
|
-
case("L2", "origin_formula", "写个 sin 公式", {"worksheet": "{ws}", "col": 3,
|
|
393
|
-
"formula": "sin(col(1))"}, has=["first", "last"])
|
|
394
|
-
case("L2", "origin_formula", "公式引用不存在的列", {"worksheet": "{ws}", "col": 7,
|
|
395
|
-
"formula": "col(99)"},
|
|
396
|
-
ok=False, code="formula_no_effect")
|
|
397
|
-
case("L2", "origin_formula", "公式是乱码中文", {"worksheet": "{ws}", "col": 8, "formula": "算一下"},
|
|
398
|
-
ok=False, code="formula_no_effect")
|
|
399
|
-
case("L2", "origin_formula", "不给公式", {"worksheet": "{ws}", "col": 3}, ok=False)
|
|
400
|
-
case("L2", "origin_formula", "在不存在的表上加列", {"worksheet": "ws-9999", "col": 3,
|
|
401
|
-
"formula": "col(2)"}, ok=False)
|
|
402
|
-
case("L2", "origin_formula", "覆盖已有的第 2 列", {"worksheet": "{ws}", "col": 2,
|
|
403
|
-
"formula": "col(2)+1"}, has=["computed_rows"])
|
|
404
|
-
case("L2", "origin_formula", "再算一次同样的公式(幂等)", {"worksheet": "{ws}", "col": 3,
|
|
405
|
-
"formula": "col(2)*2"}, has=["ok"])
|
|
406
|
-
case("L2", "origin_formula", "列号给 0", {"worksheet": "{ws}", "col": 0, "formula": "col(2)"},
|
|
407
|
-
ok=False, code="bad_column", note="0 不能落到第 1 列上,会覆盖原始数据")
|
|
408
|
-
case("L2", "origin_formula", "列号给 -1", {"worksheet": "{ws}", "col": -1, "formula": "col(2)"},
|
|
409
|
-
ok=False, code="bad_column")
|
|
410
|
-
|
|
411
|
-
for ask, args, want_ok in (
|
|
412
|
-
("关掉所有图页", {"kind": "graph"}, True),
|
|
413
|
-
("把图页都清了", {"kind": "graph", "dry_run": True}, True),
|
|
414
|
-
("干跑一下看看会关哪些", {"dry_run": True}, True),
|
|
415
|
-
("工作表也清一下", {"kind": "workbook", "dry_run": True}, True),
|
|
416
|
-
("矩阵页清掉", {"kind": "matrix", "dry_run": True}, True),
|
|
417
|
-
("只关指定名字的页", {"names": ["Graph1"], "dry_run": True}, True),
|
|
418
|
-
("关一个不存在的页名", {"names": ["NOPE"], "dry_run": True}, True),
|
|
419
|
-
("页面类型写错", {"kind": "nonsense"}, False),
|
|
420
|
-
("全清(不分类型)", {"dry_run": True}, True),
|
|
421
|
-
("实际关闭图页", {"kind": "graph"}, True),
|
|
422
|
-
("关完再确认还剩什么", {"dry_run": True}, True),
|
|
423
|
-
("再清一次(应该没东西可关了)", {"kind": "graph"}, True),
|
|
424
|
-
("names 给空列表", {"names": [], "dry_run": True}, True),
|
|
425
|
-
("重复关闭同一批页", {"names": ["Graph1"]}, True)):
|
|
426
|
-
case("L2", "origin_close_pages", ask, args, ok=want_ok, has=["ok"])
|
|
427
|
-
|
|
428
|
-
case("L2", "origin_labtalk", "读一下当前活动层的 showlegend",
|
|
429
|
-
{"script": "layer.showlegend = layer.showlegend;", "numeric": ["layer.showlegend"]},
|
|
430
|
-
has=["numeric"], note="整数型 LabTalk 变量必须能读回,不能是 nan/None")
|
|
431
|
-
case("L2", "origin_labtalk", "把图例显示打开", {"script": "layer.showlegend = 1;",
|
|
432
|
-
"numeric": ["layer.showlegend"]}, has=["numeric"])
|
|
433
|
-
case("L2", "origin_labtalk", "读一个字符串变量", {"script": "str1$ = \"abc\";", "readback": ["str1$"]},
|
|
434
|
-
has=["readback"])
|
|
435
|
-
case("L2", "origin_labtalk", "跑个无害的 ls 看看返回", {"script": "doc -a;"}, has=["ok"])
|
|
436
|
-
case("L2", "origin_labtalk", "空脚本", {"script": ""}, ok=False)
|
|
437
|
-
case("L2", "origin_labtalk", "只有空格", {"script": " "}, ok=False)
|
|
438
|
-
for bad, why in (("doc -s;", "关工程"), ("close;", "关页"), ("quit;", "退 Origin"),
|
|
439
|
-
("system dir;", "起外部进程"), ("run.section;", "跑脚本块")):
|
|
440
|
-
case("L2", "origin_labtalk", "执行 %s" % bad, {"script": bad}, ok=False,
|
|
441
|
-
code="labtalk_denied", note="破坏性命令必须被黑名单拦下:%s" % why)
|
|
442
|
-
case("L2", "origin_labtalk", "把危险命令写成大写带多余空格", {"script": "DOC -s ;"}, ok=False,
|
|
443
|
-
code="labtalk_denied", note="黑名单要折叠空白并忽略大小写")
|
|
444
|
-
case("L2", "origin_labtalk", "读一个不存在的变量", {"script": "xx = 1;", "numeric": ["nosuchvar"]},
|
|
445
|
-
has=["ok"])
|
|
446
|
-
case("L2", "origin_labtalk", "脚本里带中文注释", {"script": "// 中文注释\nyy = 2;",
|
|
447
|
-
"numeric": ["yy"]}, has=["numeric"])
|
|
448
|
-
|
|
449
|
-
# ------------------------------------------------------------------ L3 writes files
|
|
450
|
-
for fmt, ext in (("png", "png"), ("tif", "tif"), ("svg", "svg"), ("pdf", "pdf"),
|
|
451
|
-
("emf", "emf"), ("jpg", "jpg")):
|
|
452
|
-
case("L3", "origin_export", "导出成 %s" % fmt,
|
|
453
|
-
{"graph": "{gr}", "path": "{dir}/out." + ext, "fmt": fmt}, has=["path", "bytes", "head"])
|
|
454
|
-
for w in (400, 800, 1200, 1600, 2400):
|
|
455
|
-
case("L3", "origin_export", "导出 PNG,宽度 %d" % w,
|
|
456
|
-
{"graph": "{gr}", "path": "{dir}/w%d.png" % w, "fmt": "png", "width": w}, has=["dimensions"])
|
|
457
|
-
case("L3", "origin_export", "不给路径,让它自己起名", {"graph": "{gr}"}, has=["path"])
|
|
458
|
-
case("L3", "origin_export", "导出到不存在的深层目录",
|
|
459
|
-
{"graph": "{gr}", "path": "{dir}/nope/deep/x.png"},
|
|
460
|
-
note="应当自动建目录或明确报错,不能写出半个文件")
|
|
461
|
-
case("L3", "origin_export", "格式写成 tiff 两个 f", {"graph": "{gr}", "path": "{dir}/a.tiff",
|
|
462
|
-
"fmt": "tiff"}, has=["ok"])
|
|
463
|
-
case("L3", "origin_export", "格式写 docx", {"graph": "{gr}", "fmt": "docx"}, ok=False)
|
|
464
|
-
case("L3", "origin_export", "导出不存在的图", {"graph": "gr-9999", "path": "{dir}/x.png"}, ok=False)
|
|
465
|
-
case("L3", "origin_export", "同一个文件导出两次(覆盖)",
|
|
466
|
-
{"graph": "{gr}", "path": "{dir}/twice.png", "fmt": "png"}, has=["bytes"])
|
|
467
|
-
case("L3", "origin_export", "路径里有中文", {"graph": "{gr}", "path": "{dir}/图表.png", "fmt": "png"},
|
|
468
|
-
note="中文路径历史上不稳,至少要如实报告失败")
|
|
469
|
-
case("L3", "origin_export", "宽度给 0", {"graph": "{gr}", "path": "{dir}/z.png", "width": 0},
|
|
470
|
-
note="非法宽度不能静默当成默认值")
|
|
471
|
-
|
|
472
|
-
for ask in ("保存工程", "存成 opju 我回头继续改", "存到 out 目录", "保存一下当前项目",
|
|
473
|
-
"存盘,文件名 proj1.opju", "再存一次覆盖掉", "存成 .opj 老格式",
|
|
474
|
-
"保存到中文文件名", "保存并确认文件头是 Origin 的", "存盘后还能编辑吗"):
|
|
475
|
-
case("L3", "origin_save_project", ask, {"path": "{dir}/proj.opju"},
|
|
476
|
-
has=["path", "bytes", "head", "editable"])
|
|
477
|
-
case("L3", "origin_save_project", "不给路径,存到默认位置", {}, has=["saved"])
|
|
478
|
-
case("L3", "origin_save_project", "存到一个不能写的路径", {"path": "C:\\Windows\\nope.opju"}, ok=False)
|
|
479
|
-
|
|
480
|
-
FIG_ARGS = [
|
|
481
|
-
("一步出图:导入 sample 然后画图导出", {"source": "{dat}", "x": 1, "y": 2,
|
|
482
|
-
"export_path": "{dir}/fig1.png"}),
|
|
483
|
-
("用内联数据一步出图", {"columns": "{columns}", "x": 1, "y": 2,
|
|
484
|
-
"export_path": "{dir}/fig2.png"}),
|
|
485
|
-
("出图带轴标题", {"source": "{dat}", "x": 1, "y": 2, "x_title": "Time (s)",
|
|
486
|
-
"y_title": "Signal (mV)", "export_path": "{dir}/fig3.png"}),
|
|
487
|
-
("出图要图例", {"source": "{dat}", "x": 1, "y": 2, "legend": True,
|
|
488
|
-
"export_path": "{dir}/fig4.png"}),
|
|
489
|
-
("出图不要图例", {"source": "{dat}", "x": 1, "y": 2, "legend": False,
|
|
490
|
-
"export_path": "{dir}/fig5.png"}),
|
|
491
|
-
("用模板出图", {"source": "{dat}", "x": 1, "y": 2, "template": "linesymb",
|
|
492
|
-
"export_path": "{dir}/fig6.png"}),
|
|
493
|
-
("四条曲线一次出图", {"source": "{wide}", "x": 1, "y": [2, 3, 4, 5],
|
|
494
|
-
"export_path": "{dir}/fig7.png"}),
|
|
495
|
-
("出图同时存工程", {"source": "{dat}", "x": 1, "y": 2, "output_dir": "{dir}"}),
|
|
496
|
-
("只要工程不要图", {"source": "{dat}", "x": 1, "y": 2, "project_path": "{dir}/only.opju",
|
|
497
|
-
"do_project": True}),
|
|
498
|
-
("指定图标题", {"source": "{dat}", "x": 1, "y": 2, "title": "循环曲线",
|
|
499
|
-
"export_path": "{dir}/fig8.png"}),
|
|
500
|
-
("导出 svg 格式", {"source": "{dat}", "x": 1, "y": 2, "fmt": "svg",
|
|
501
|
-
"export_path": "{dir}/fig9.svg"}),
|
|
502
|
-
("宽度 2000 出图", {"source": "{dat}", "x": 1, "y": 2, "width": 2000,
|
|
503
|
-
"export_path": "{dir}/fig10.png"}),
|
|
504
|
-
("工作站 txt 一步出图(前面几十行参数要跳过)",
|
|
505
|
-
{"source": "{chi}", "x": 1, "y": 2, "export_path": "{dir}/chi.png", "title": "LSV"}),
|
|
506
|
-
("什么都不给", {}, False),
|
|
507
|
-
("只给 source 不给输出位置", {"source": "{dat}", "x": 1, "y": 2}, True),
|
|
508
|
-
("source 和 columns 都不给但给了 x/y", {"x": 1, "y": 2}, False),
|
|
509
|
-
("source 指向不存在的文件", {"source": "C:/nope.dat", "export_path": "{dir}/x.png"}, False),
|
|
510
|
-
("列号越界", {"source": "{dat}", "x": 1, "y": 9, "export_path": "{dir}/x.png"}, False),
|
|
511
|
-
("重复出同样的图(覆盖同名文件)", {"source": "{dat}", "x": 1, "y": 2,
|
|
512
|
-
"export_path": "{dir}/fig1.png"}, True),
|
|
513
|
-
]
|
|
514
|
-
for entry in FIG_ARGS:
|
|
515
|
-
# Entries may omit the expectation, which means "should succeed".
|
|
516
|
-
case("L3", "origin_figure", entry[0], entry[1],
|
|
517
|
-
ok=entry[2] if len(entry) > 2 else True)
|
|
518
|
-
|
|
519
|
-
PRESET_DATA = {
|
|
520
|
-
"xps": {"binding_energy": [round(284 + i * 0.4, 2) for i in range(12)],
|
|
521
|
-
"intensity": [round(800 + 60 * math.sin(i / 2.0)) for i in range(12)]},
|
|
522
|
-
"xrd": {"two_theta": [round(20 + i * 1.5, 2) for i in range(12)],
|
|
523
|
-
"intensity": [round(120 + 900 * math.exp(-((i - 5) ** 2) / 3.0)) for i in range(12)]},
|
|
524
|
-
"cv": {"potential": [round(-0.2 + i * 0.04, 3) for i in range(12)],
|
|
525
|
-
"current": [round(1e-4 * math.sin(i / 2.0), 8) for i in range(12)]},
|
|
526
|
-
"uv_vis": {"wavelength": [200 + 10 * i for i in range(12)],
|
|
527
|
-
"absorbance": [round(0.1 + 0.05 * math.sin(i / 3.0), 4) for i in range(12)]},
|
|
528
|
-
"tga": {"temperature": [30 + 25 * i for i in range(12)],
|
|
529
|
-
"mass_percent": [round(100 - 0.8 * i - 1.5 * (i > 6), 3) for i in range(12)]},
|
|
530
|
-
"dsc": {"temperature": [25 + 5 * i for i in range(12)],
|
|
531
|
-
"heat_flow": [round(0.2 * math.exp(-((i - 6) ** 2) / 4.0), 5) for i in range(12)]},
|
|
532
|
-
"histogram": {"value": [round(abs(3.0 * math.sin(i)), 3) for i in range(24)]},
|
|
533
|
-
"bland_altman": {"method1": [round(10 + i * 0.7, 2) for i in range(12)],
|
|
534
|
-
"method2": [round(10.4 + i * 0.66, 2) for i in range(12)]},
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
for name in ("xps", "xrd", "cv", "uv_vis", "tga", "dsc", "histogram", "bland_altman"):
|
|
538
|
-
case("L3", "origin_chart_render", "用 %s 预设一步出图" % name,
|
|
539
|
-
{"name": name, "columns": PRESET_DATA[name], "output_dir": "{dir}"},
|
|
540
|
-
note="每个预设配自己那套列名,不能拿一份数据喂所有预设")
|
|
541
|
-
case("L3", "origin_chart_render", "预设出图带图例",
|
|
542
|
-
{"name": "xps", "columns": "{xps}", "output_dir": "{dir}", "with_legend": True}, has=["ok"])
|
|
543
|
-
case("L3", "origin_chart_render", "预设出图不要图例",
|
|
544
|
-
{"name": "xps", "columns": "{xps}", "output_dir": "{dir}", "with_legend": False}, has=["ok"])
|
|
545
|
-
case("L3", "origin_chart_render", "自定义轴标题",
|
|
546
|
-
{"name": "xps", "columns": "{xps}", "output_dir": "{dir}",
|
|
547
|
-
"x_title": "BE / eV", "y_title": "Intensity"}, has=["ok"])
|
|
548
|
-
case("L3", "origin_chart_render", "从文件出图", {"name": "xps", "source": "{xps_file}",
|
|
549
|
-
"output_dir": "{dir}"})
|
|
550
|
-
case("L3", "origin_chart_render", "指定 x/y 列号", {"name": "xps", "source": "{xps_file}",
|
|
551
|
-
"x": 1, "y": 2, "output_dir": "{dir}"})
|
|
552
|
-
case("L3", "origin_chart_render", "三行表头的文件(列名解析不吃 Long Name 块)",
|
|
553
|
-
{"name": "xps", "source": "{units}", "output_dir": "{dir}"}, ok=False,
|
|
554
|
-
code="preset_columns_mismatch",
|
|
555
|
-
note="units.dat 的多行表头被当成数据列名,拒画比硬套预设诚实;这是已知限制")
|
|
556
|
-
case("L3", "origin_chart_render", "导出 pdf", {"name": "xps", "columns": "{xps}",
|
|
557
|
-
"output_dir": "{dir}", "fmt": "pdf"})
|
|
558
|
-
case("L3", "origin_chart_render", "宽度 3000", {"name": "xps", "columns": "{xps}",
|
|
559
|
-
"output_dir": "{dir}", "width": 3000})
|
|
560
|
-
case("L3", "origin_chart_render", "列不够,只有 binding_energy",
|
|
561
|
-
{"name": "xps", "columns": {"binding_energy": [1, 2, 3]}, "output_dir": "{dir}"}, ok=False,
|
|
562
|
-
note="缺列必须拒绝,不能画半张图")
|
|
563
|
-
case("L3", "origin_chart_render", "预设名不存在",
|
|
564
|
-
{"name": "not_a_preset", "columns": "{xps}", "output_dir": "{dir}"}, ok=False)
|
|
565
|
-
case("L3", "origin_chart_render", "数据完全对不上(cv 数据喂 xps 预设)",
|
|
566
|
-
{"name": "xps", "columns": "{cv}", "output_dir": "{dir}"}, ok=False)
|
|
567
|
-
case("L3", "origin_chart_render", "不给输出目录", {"name": "xps", "columns": "{xps}"},
|
|
568
|
-
note="应当说明没有落盘,或写到明确位置")
|
|
569
|
-
case("L3", "origin_chart_render", "图标题自定义", {"name": "xps", "columns": "{xps}",
|
|
570
|
-
"output_dir": "{dir}", "title": "Survey"}, has=["ok"])
|
|
571
|
-
case("L3", "origin_chart_render", "换个 plot_type", {"name": "xps", "columns": "{xps}",
|
|
572
|
-
"output_dir": "{dir}", "plot_type": "line_symbol"},
|
|
573
|
-
has=["ok"])
|
|
574
|
-
|
|
575
|
-
# ------------------------------------------------------------------ L4 process level
|
|
576
|
-
for ask in ("现在有几个 origin 实例", "有没有没窗口的残留实例", "实例清点一下",
|
|
577
|
-
"后台跑着的 origin 有几个", "看看是不是我起的实例占着端口",
|
|
578
|
-
"任务管理器里那种没窗口的 origin 列出来", "实例数会不会超上限",
|
|
579
|
-
"再清点一次", "有前台窗口的实例有几个", "现在 started_by_us 是谁",
|
|
580
|
-
"探测结果里 probe 字段是什么", "确认没有孤儿实例"):
|
|
581
|
-
case("L4", "origin_instances", ask, has=["count", "probe"],
|
|
582
|
-
eq=[("probe", "ok")])
|
|
583
|
-
for ask in ("先看看会回收哪些,别真动手", "预览一下回收", "close_background 传 false",
|
|
584
|
-
"确认预览不会杀进程", "dry run 之后再清点一次"):
|
|
585
|
-
case("L4", "origin_reclaim", ask, {"close_background": False}, has=["closed", "left_running"])
|
|
586
|
-
for ask in ("回收残留实例", "把没窗口的实例关掉", "再回收一次(应该没东西了)",
|
|
587
|
-
"回收后确认数量为 0", "重复回收是否幂等", "关掉后台实例再清点",
|
|
588
|
-
"再执行一次回收", "回收完看状态", "回收后确认前台窗口没被误杀"):
|
|
589
|
-
case("L4", "origin_reclaim", ask, has=["probe", "notify"])
|
|
590
|
-
|
|
591
|
-
case("L4", "origin_exit", "先存一份再关 origin", {"save_to": "{dir}/bye.opju"}, has=["ok"])
|
|
592
|
-
case("L4", "origin_status", "关完之后确认连接状态", has=["connected"])
|
|
593
|
-
case("L4", "origin_import", "退出之后再导入,看它会不会自动重连", {"path": "{dat}"}, has=["worksheet"])
|
|
594
|
-
case("L4", "origin_exit", "直接关,不保存", {}, has=["ok"])
|
|
595
|
-
case("L4", "origin_exit", "已经关了再关一次(幂等)", {}, note="重复退出不应崩")
|
|
596
|
-
case("L4", "origin_instances", "退出后清点实例", has=["count"])
|
|
597
|
-
case("L4", "origin_reclaim", "退出后回收一次残留", has=["probe"])
|
|
598
|
-
case("L4", "origin_reclaim", "把桥自己起的后台实例全关掉", has=["closed", "probe"])
|
|
599
|
-
case("L4", "origin_status", "实例被关掉后第一次调用要自己接上", has=["connected"],
|
|
600
|
-
note="COM 指针失效时桥必须丢弃缓存重连,不能一路 connection_error")
|
|
601
|
-
case("L4", "origin_import", "掉线之后重新导入数据", {"path": "{dat}"}, has=["worksheet", "rows"],
|
|
602
|
-
save={"ws": "worksheet"})
|
|
603
|
-
case("L4", "origin_plot", "掉线之后重新画图", {"worksheet": "{ws}", "x": 1, "y": 2},
|
|
604
|
-
has=["graph"], save={"gr": "graph"})
|
|
605
|
-
case("L4", "origin_status", "最后确认连接恢复可用", has=["connected"])
|
|
606
|
-
case("L4", "origin_exit", "退出并存盘到新名字", {"save_to": "{dir}/final.opju"}, has=["ok"])
|
|
607
|
-
case("L4", "origin_open", "把刚存的工程重新打开", {"path": "{dir}/final.opju"}, has=["ok"])
|
|
608
|
-
case("L4", "origin_open", "打开不存在的工程", {"path": "C:/nope.opju"}, ok=False)
|
|
609
|
-
case("L4", "origin_open", "打开一个 .txt 说它是工程", {"path": "{semi}"}, ok=False)
|
|
610
|
-
case("L4", "origin_open", "路径给空", {"path": ""}, ok=False)
|
|
611
|
-
case("L4", "origin_open", "再打开一次同一个工程", {"path": "{dir}/final.opju"}, has=["ok"])
|
|
612
|
-
|
|
613
|
-
for ask, args, want in (
|
|
614
|
-
("打开 out 里那个 proj.opju", {"path": "{dir}/proj.opju"}, True),
|
|
615
|
-
("用相对路径打开工程", {"path": "proj.opju"}, False),
|
|
616
|
-
("打开中文文件名的工程", {"path": "{dir}/中文工程.opju"}, False),
|
|
617
|
-
("把刚才那个工程再打开一次看看页面数", {"path": "{dir}/final.opju"}, True),
|
|
618
|
-
("打开一个只有表头的 .dat 当工程", {"path": "{units}"}, False),
|
|
619
|
-
("路径给成目录", {"path": "{dir}"}, False),
|
|
620
|
-
("打开后确认能继续导入数据", {"path": "{dir}/final.opju"}, True),
|
|
621
|
-
):
|
|
622
|
-
case("L4", "origin_open", ask, args, ok=want)
|
|
623
|
-
|
|
624
|
-
for ask, args, want in (
|
|
625
|
-
("退出并存盘到 bye2.opju", {"save_to": "{dir}/bye2.opju"}, True),
|
|
626
|
-
("退出后马上再退出一次", {}, True),
|
|
627
|
-
("退出,不保存", {}, True),
|
|
628
|
-
("退出后看状态", {}, True),
|
|
629
|
-
("退出并存到中文路径", {"save_to": "{dir}/退出工程.opju"}, True),
|
|
630
|
-
("第三次退出(幂等检查)", {}, True),
|
|
631
|
-
("退出后确认还能重新连上干活", {}, True),
|
|
632
|
-
):
|
|
633
|
-
case("L4", "origin_exit", ask, args, ok=want, has=["ok"])
|
|
634
|
-
|
|
635
|
-
case("L4", "origin_status", "全部退出用例跑完,最后确认连接", has=["connected", "open_pages"])
|
|
636
|
-
case("L4", "origin_instances", "收尾清点:还有几个实例", has=["count", "probe"])
|