mindstudio-probe 1.0.3__py3-none-any.whl → 1.1.0__py3-none-any.whl

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.
Files changed (278) hide show
  1. {mindstudio_probe-1.0.3.dist-info → mindstudio_probe-1.1.0.dist-info}/LICENSE +201 -201
  2. {mindstudio_probe-1.0.3.dist-info → mindstudio_probe-1.1.0.dist-info}/METADATA +36 -34
  3. mindstudio_probe-1.1.0.dist-info/RECORD +287 -0
  4. {mindstudio_probe-1.0.3.dist-info → mindstudio_probe-1.1.0.dist-info}/WHEEL +1 -1
  5. {mindstudio_probe-1.0.3.dist-info → mindstudio_probe-1.1.0.dist-info}/entry_points.txt +1 -0
  6. msprobe/README.md +131 -237
  7. msprobe/__init__.py +16 -1
  8. msprobe/{config/config.json → config.json} +47 -49
  9. msprobe/core/advisor/advisor.py +124 -124
  10. msprobe/core/advisor/advisor_const.py +58 -59
  11. msprobe/core/advisor/advisor_result.py +58 -58
  12. msprobe/core/common/const.py +402 -318
  13. msprobe/core/common/exceptions.py +99 -99
  14. msprobe/core/common/{file_check.py → file_utils.py} +523 -283
  15. msprobe/core/common/inplace_op_checker.py +38 -0
  16. msprobe/core/common/inplace_ops.yaml +251 -0
  17. msprobe/core/common/log.py +86 -69
  18. msprobe/core/common/utils.py +371 -616
  19. msprobe/core/common_config.py +78 -71
  20. msprobe/core/compare/acc_compare.py +472 -298
  21. msprobe/core/compare/check.py +180 -95
  22. msprobe/core/compare/compare_cli.py +69 -49
  23. msprobe/core/compare/highlight.py +259 -222
  24. msprobe/core/compare/multiprocessing_compute.py +174 -149
  25. msprobe/core/compare/npy_compare.py +310 -295
  26. msprobe/core/compare/utils.py +464 -429
  27. msprobe/core/data_dump/data_collector.py +153 -144
  28. msprobe/core/data_dump/data_processor/base.py +337 -293
  29. msprobe/core/data_dump/data_processor/factory.py +76 -59
  30. msprobe/core/data_dump/data_processor/mindspore_processor.py +192 -198
  31. msprobe/core/data_dump/data_processor/pytorch_processor.py +383 -389
  32. msprobe/core/data_dump/json_writer.py +117 -116
  33. msprobe/core/data_dump/scope.py +194 -178
  34. msprobe/core/grad_probe/constant.py +74 -70
  35. msprobe/core/grad_probe/grad_compare.py +170 -175
  36. msprobe/core/grad_probe/utils.py +77 -52
  37. msprobe/docs/01.installation.md +99 -0
  38. msprobe/docs/02.config_introduction.md +137 -0
  39. msprobe/docs/03.config_examples.md +237 -0
  40. msprobe/docs/04.acl_config_examples.md +78 -0
  41. msprobe/docs/05.data_dump_PyTorch.md +326 -0
  42. msprobe/docs/06.data_dump_MindSpore.md +285 -0
  43. msprobe/docs/07.accuracy_checker_PyTorch.md +297 -0
  44. msprobe/docs/08.accuracy_checker_online_PyTorch.md +238 -0
  45. msprobe/docs/09.accuracy_checker_MindSpore.md +68 -0
  46. msprobe/docs/10.accuracy_compare_PyTorch.md +327 -0
  47. msprobe/docs/11.accuracy_compare_MindSpore.md +333 -0
  48. msprobe/docs/12.overflow_check_PyTorch.md +79 -0
  49. msprobe/docs/13.overflow_check_MindSpore.md +31 -0
  50. msprobe/{pytorch/doc/parse_tool.md → docs/14.data_parse_PyTorch.md} +283 -286
  51. msprobe/docs/15.free_benchmarking_PyTorch.md +170 -0
  52. msprobe/docs/16.free_benchmarking_MindSpore.md +140 -0
  53. msprobe/{doc/grad_probe/grad_probe.md → docs/17.grad_probe.md} +205 -207
  54. msprobe/{pytorch/doc//321/205/320/254/320/270/321/207/342/225/221/342/224/220/321/207/342/226/223/342/225/233/321/205/342/225/221/320/266/321/206/320/277/320/244/321/205/320/277/342/225/243.md → docs/18.online_dispatch.md} +89 -90
  55. msprobe/docs/FAQ.md +189 -0
  56. msprobe/docs/S02.report_free_benchmarking_validation_performance_baseline.md +146 -0
  57. msprobe/docs/img/free_benchmark_framework.png +0 -0
  58. msprobe/docs/img/ms_dump.png +0 -0
  59. msprobe/docs/img/ms_layer.png +0 -0
  60. msprobe/docs/img/pt_dump.png +0 -0
  61. msprobe/mindspore/__init__.py +2 -1
  62. msprobe/mindspore/api_accuracy_checker/api_accuracy_checker.py +278 -245
  63. msprobe/mindspore/api_accuracy_checker/api_info.py +76 -69
  64. msprobe/mindspore/api_accuracy_checker/api_runner.py +155 -151
  65. msprobe/mindspore/api_accuracy_checker/base_compare_algorithm.py +196 -196
  66. msprobe/mindspore/api_accuracy_checker/cmd_parser.py +6 -0
  67. msprobe/mindspore/api_accuracy_checker/compute_element.py +238 -223
  68. msprobe/mindspore/api_accuracy_checker/main.py +8 -15
  69. msprobe/mindspore/api_accuracy_checker/type_mapping.py +113 -113
  70. msprobe/mindspore/api_accuracy_checker/utils.py +79 -62
  71. msprobe/mindspore/cell_processor.py +58 -34
  72. msprobe/mindspore/common/const.py +108 -87
  73. msprobe/mindspore/common/log.py +37 -37
  74. msprobe/mindspore/common/utils.py +97 -57
  75. msprobe/mindspore/compare/distributed_compare.py +62 -75
  76. msprobe/mindspore/compare/layer_mapping.py +146 -0
  77. msprobe/mindspore/compare/modify_mapping.py +107 -0
  78. msprobe/mindspore/compare/ms_compare.py +357 -117
  79. msprobe/mindspore/compare/ms_graph_compare.py +364 -317
  80. msprobe/mindspore/compare/ms_to_pt_api.yaml +399 -399
  81. msprobe/mindspore/debugger/debugger_config.py +69 -74
  82. msprobe/mindspore/debugger/precision_debugger.py +150 -107
  83. msprobe/mindspore/dump/dump_tool_factory.py +50 -35
  84. msprobe/mindspore/dump/hook_cell/api_registry.py +128 -104
  85. msprobe/mindspore/dump/hook_cell/hook_cell.py +55 -53
  86. msprobe/mindspore/dump/hook_cell/primitive_hooks.py +206 -0
  87. msprobe/mindspore/dump/hook_cell/support_wrap_ops.yaml +994 -925
  88. msprobe/mindspore/dump/hook_cell/wrap_api.py +121 -0
  89. msprobe/mindspore/dump/jit_dump.py +96 -56
  90. msprobe/mindspore/dump/kernel_graph_dump.py +75 -60
  91. msprobe/mindspore/dump/kernel_kbyk_dump.py +79 -65
  92. msprobe/mindspore/free_benchmark/api_pynative_self_check.py +131 -116
  93. msprobe/mindspore/free_benchmark/common/config.py +27 -12
  94. msprobe/mindspore/free_benchmark/common/handler_params.py +32 -17
  95. msprobe/mindspore/free_benchmark/common/utils.py +85 -71
  96. msprobe/mindspore/free_benchmark/data/support_wrap_ops.yaml +842 -842
  97. msprobe/mindspore/free_benchmark/decorator/dec_forward.py +57 -42
  98. msprobe/mindspore/free_benchmark/decorator/decorator_factory.py +122 -107
  99. msprobe/mindspore/free_benchmark/handler/base_handler.py +105 -90
  100. msprobe/mindspore/free_benchmark/handler/check_handler.py +56 -41
  101. msprobe/mindspore/free_benchmark/handler/fix_handler.py +51 -36
  102. msprobe/mindspore/free_benchmark/handler/handler_factory.py +36 -21
  103. msprobe/mindspore/free_benchmark/perturbation/add_noise.py +82 -67
  104. msprobe/mindspore/free_benchmark/perturbation/base_perturbation.py +36 -21
  105. msprobe/mindspore/free_benchmark/perturbation/bit_noise.py +78 -63
  106. msprobe/mindspore/free_benchmark/perturbation/exchange_value.py +77 -0
  107. msprobe/mindspore/free_benchmark/perturbation/improve_precision.py +49 -34
  108. msprobe/mindspore/free_benchmark/perturbation/no_change.py +27 -12
  109. msprobe/mindspore/free_benchmark/perturbation/perturbation_factory.py +44 -27
  110. msprobe/mindspore/free_benchmark/self_check_tool_factory.py +48 -33
  111. msprobe/mindspore/grad_probe/global_context.py +100 -91
  112. msprobe/mindspore/grad_probe/grad_analyzer.py +231 -231
  113. msprobe/mindspore/grad_probe/grad_monitor.py +27 -27
  114. msprobe/mindspore/grad_probe/grad_stat_csv.py +131 -131
  115. msprobe/mindspore/grad_probe/hook.py +94 -92
  116. msprobe/mindspore/grad_probe/utils.py +29 -28
  117. msprobe/mindspore/ms_config.py +128 -126
  118. msprobe/mindspore/overflow_check/kernel_graph_overflow_check.py +60 -45
  119. msprobe/mindspore/overflow_check/overflow_check_tool_factory.py +49 -34
  120. msprobe/mindspore/runtime.py +4 -4
  121. msprobe/mindspore/service.py +297 -354
  122. msprobe/mindspore/task_handler_factory.py +24 -24
  123. msprobe/msprobe.py +105 -107
  124. msprobe/pytorch/__init__.py +23 -4
  125. msprobe/pytorch/api_accuracy_checker/common/config.py +70 -55
  126. msprobe/pytorch/api_accuracy_checker/common/utils.py +246 -165
  127. msprobe/pytorch/api_accuracy_checker/compare/algorithm.py +230 -213
  128. msprobe/pytorch/api_accuracy_checker/compare/api_precision_compare.py +632 -581
  129. msprobe/pytorch/api_accuracy_checker/compare/api_precision_standard.yaml +132 -132
  130. msprobe/pytorch/api_accuracy_checker/compare/api_precision_threshold.yaml +390 -390
  131. msprobe/pytorch/api_accuracy_checker/compare/compare.py +416 -381
  132. msprobe/pytorch/api_accuracy_checker/compare/compare_column.py +90 -73
  133. msprobe/pytorch/api_accuracy_checker/compare/compare_utils.py +265 -244
  134. msprobe/pytorch/api_accuracy_checker/config.yaml +10 -10
  135. msprobe/pytorch/api_accuracy_checker/run_ut/data_generate.py +370 -332
  136. msprobe/pytorch/api_accuracy_checker/run_ut/multi_run_ut.py +221 -199
  137. msprobe/pytorch/api_accuracy_checker/run_ut/run_overflow_check.py +150 -134
  138. msprobe/pytorch/api_accuracy_checker/run_ut/run_ut.py +518 -581
  139. msprobe/pytorch/api_accuracy_checker/run_ut/run_ut_utils.py +213 -74
  140. msprobe/pytorch/api_accuracy_checker/run_ut/torch_ut_setting.json +7 -4
  141. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/attl.py +218 -202
  142. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/client.py +370 -324
  143. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/device_dispatch.py +227 -204
  144. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/dump_dispatch.py +110 -0
  145. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/server.py +244 -218
  146. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/torch_ops_config.yaml +63 -0
  147. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/utils.py +44 -0
  148. msprobe/pytorch/bench_functions/__init__.py +30 -15
  149. msprobe/pytorch/bench_functions/apply_adam_w.py +43 -28
  150. msprobe/pytorch/bench_functions/confusion_transpose.py +34 -19
  151. msprobe/pytorch/bench_functions/fast_gelu.py +70 -55
  152. msprobe/pytorch/bench_functions/layer_norm_eval.py +21 -6
  153. msprobe/pytorch/bench_functions/linear.py +27 -12
  154. msprobe/pytorch/bench_functions/matmul_backward.py +63 -48
  155. msprobe/pytorch/bench_functions/npu_fusion_attention.py +538 -421
  156. msprobe/pytorch/bench_functions/rms_norm.py +30 -15
  157. msprobe/pytorch/bench_functions/rotary_mul.py +71 -52
  158. msprobe/pytorch/bench_functions/scaled_mask_softmax.py +41 -26
  159. msprobe/pytorch/bench_functions/swiglu.py +70 -55
  160. msprobe/pytorch/common/__init__.py +17 -2
  161. msprobe/pytorch/common/compare_script.template +14 -14
  162. msprobe/pytorch/common/log.py +33 -32
  163. msprobe/pytorch/common/parse_json.py +54 -39
  164. msprobe/pytorch/common/utils.py +310 -300
  165. msprobe/pytorch/compare/distributed_compare.py +66 -66
  166. msprobe/pytorch/compare/mapping.yaml +607 -607
  167. msprobe/pytorch/compare/match.py +49 -33
  168. msprobe/pytorch/compare/pt_compare.py +82 -40
  169. msprobe/pytorch/debugger/debugger_config.py +108 -95
  170. msprobe/pytorch/debugger/precision_debugger.py +173 -125
  171. msprobe/pytorch/free_benchmark/__init__.py +23 -8
  172. msprobe/pytorch/free_benchmark/common/constant.py +70 -70
  173. msprobe/pytorch/free_benchmark/common/counter.py +71 -71
  174. msprobe/pytorch/free_benchmark/common/enums.py +65 -37
  175. msprobe/pytorch/free_benchmark/common/params.py +144 -129
  176. msprobe/pytorch/free_benchmark/common/utils.py +118 -102
  177. msprobe/pytorch/free_benchmark/compare/grad_saver.py +200 -179
  178. msprobe/pytorch/free_benchmark/compare/single_benchmark.py +119 -104
  179. msprobe/pytorch/free_benchmark/main.py +120 -105
  180. msprobe/pytorch/free_benchmark/perturbed_layers/base_layer.py +28 -13
  181. msprobe/pytorch/free_benchmark/perturbed_layers/layer_factory.py +56 -41
  182. msprobe/pytorch/free_benchmark/perturbed_layers/npu/add_noise.py +105 -90
  183. msprobe/pytorch/free_benchmark/perturbed_layers/npu/bit_noise.py +119 -104
  184. msprobe/pytorch/free_benchmark/perturbed_layers/npu/change_value.py +87 -63
  185. msprobe/pytorch/free_benchmark/perturbed_layers/npu/improve_precision.py +83 -68
  186. msprobe/pytorch/free_benchmark/perturbed_layers/npu/no_change.py +43 -28
  187. msprobe/pytorch/free_benchmark/perturbed_layers/npu/npu_base_layser.py +60 -45
  188. msprobe/pytorch/free_benchmark/perturbed_layers/run_cpu.py +34 -19
  189. msprobe/pytorch/free_benchmark/result_handlers/base_handler.py +256 -217
  190. msprobe/pytorch/free_benchmark/result_handlers/check_handler.py +54 -39
  191. msprobe/pytorch/free_benchmark/result_handlers/fix_handler.py +38 -23
  192. msprobe/pytorch/free_benchmark/result_handlers/handler_factory.py +45 -30
  193. msprobe/pytorch/free_benchmark/result_handlers/preheat_handler.py +185 -170
  194. msprobe/pytorch/function_factory.py +91 -75
  195. msprobe/pytorch/functional/module_dump.py +84 -0
  196. msprobe/pytorch/grad_probe/grad_monitor.py +91 -90
  197. msprobe/pytorch/grad_probe/grad_stat_csv.py +128 -128
  198. msprobe/pytorch/hook_module/__init__.py +16 -1
  199. msprobe/pytorch/hook_module/api_registry.py +166 -161
  200. msprobe/pytorch/hook_module/hook_module.py +118 -120
  201. msprobe/pytorch/hook_module/support_wrap_ops.yaml +1879 -1877
  202. msprobe/pytorch/hook_module/utils.py +28 -29
  203. msprobe/pytorch/hook_module/wrap_aten.py +111 -110
  204. msprobe/pytorch/hook_module/wrap_distributed.py +77 -78
  205. msprobe/pytorch/hook_module/wrap_functional.py +104 -105
  206. msprobe/pytorch/hook_module/wrap_npu_custom.py +85 -84
  207. msprobe/pytorch/hook_module/wrap_tensor.py +69 -71
  208. msprobe/pytorch/hook_module/wrap_torch.py +84 -86
  209. msprobe/pytorch/hook_module/wrap_vf.py +60 -62
  210. msprobe/pytorch/module_processer.py +153 -138
  211. msprobe/pytorch/online_dispatch/__init__.py +20 -20
  212. msprobe/pytorch/online_dispatch/compare.py +235 -236
  213. msprobe/pytorch/online_dispatch/dispatch.py +271 -271
  214. msprobe/pytorch/online_dispatch/dump_compare.py +155 -156
  215. msprobe/pytorch/online_dispatch/single_compare.py +391 -391
  216. msprobe/pytorch/online_dispatch/torch_ops_config.yaml +57 -49
  217. msprobe/pytorch/online_dispatch/utils.py +127 -146
  218. msprobe/pytorch/parse.py +19 -4
  219. msprobe/pytorch/parse_tool/cli.py +31 -32
  220. msprobe/pytorch/parse_tool/lib/compare.py +259 -271
  221. msprobe/pytorch/parse_tool/lib/config.py +52 -52
  222. msprobe/pytorch/parse_tool/lib/file_desc.py +31 -31
  223. msprobe/pytorch/parse_tool/lib/interactive_cli.py +102 -102
  224. msprobe/pytorch/parse_tool/lib/parse_exception.py +54 -54
  225. msprobe/pytorch/parse_tool/lib/parse_tool.py +161 -158
  226. msprobe/pytorch/parse_tool/lib/utils.py +320 -321
  227. msprobe/pytorch/parse_tool/lib/visualization.py +85 -91
  228. msprobe/pytorch/pt_config.py +317 -187
  229. msprobe/pytorch/service.py +311 -252
  230. mindstudio_probe-1.0.3.dist-info/RECORD +0 -272
  231. msprobe/config/README.md +0 -539
  232. msprobe/mindspore/doc/compare.md +0 -58
  233. msprobe/mindspore/doc/dump.md +0 -217
  234. msprobe/mindspore/dump/hook_cell/wrap_functional.py +0 -91
  235. msprobe/mindspore/dump/hook_cell/wrap_tensor.py +0 -63
  236. msprobe/pytorch/api_accuracy_checker/tensor_transport_layer/ssl_config.py +0 -10
  237. msprobe/pytorch/doc/FAQ.md +0 -193
  238. msprobe/pytorch/doc/api_accuracy_checker.md +0 -313
  239. msprobe/pytorch/doc/api_accuracy_checker_online.md +0 -187
  240. msprobe/pytorch/doc/dump.md +0 -260
  241. msprobe/pytorch/doc/msprobe/321/207/342/226/223/342/225/233/321/205/342/225/221/320/266/321/205/342/225/226/320/265/321/205/320/225/342/225/226/321/206/320/245/342/226/221/321/206/320/235/320/276dump/321/206/320/260/320/227/321/205/320/227/320/226/321/206/320/220/320/267/321/210/320/223/342/225/234/321/205/320/257/342/225/221/321/207/342/225/221/342/224/220/321/206/320/232/320/265/321/205/320/241/320/232.md +0 -182
  242. msprobe/pytorch/doc/ptdbg_ascend_compare.md +0 -240
  243. msprobe/pytorch/doc/ptdbg_ascend_overview.md +0 -68
  244. msprobe/pytorch/doc/ptdbg_ascend_quickstart.md +0 -381
  245. msprobe/pytorch/doc/run_overflow_check.md +0 -25
  246. msprobe/pytorch/doc//321/206/320/247/320/260/321/206/320/260/320/227/321/206/320/255/320/226/321/205/342/225/226/320/265/321/205/320/225/342/225/226/321/205/320/254/342/225/221/321/206/320/251/320/277/321/211/320/272/320/234/321/210/320/277/320/221/321/205/320/242/320/234/321/206/320/220/320/267/321/210/320/223/342/225/234/321/205/320/257/342/225/221/321/207/342/225/221/342/224/220/321/206/320/232/320/265/321/205/320/241/320/232.md +0 -151
  247. msprobe/pytorch/functional/data_processor.py +0 -0
  248. msprobe/pytorch/functional/dump_module.py +0 -39
  249. {mindstudio_probe-1.0.3.dist-info → mindstudio_probe-1.1.0.dist-info}/top_level.txt +0 -0
  250. /msprobe/{pytorch/doc → docs}/img/BLOOM-7B_1.png +0 -0
  251. /msprobe/{pytorch/doc → docs}/img/BLOOM-7B_2.png +0 -0
  252. /msprobe/{pytorch/doc → docs}/img/BLOOM-7B_3.png +0 -0
  253. /msprobe/{pytorch/doc → docs}/img/BLOOM-7B_4.png +0 -0
  254. /msprobe/{pytorch/doc → docs}/img/GPT-3_1.png +0 -0
  255. /msprobe/{pytorch/doc → docs}/img/GPT-3_2.png +0 -0
  256. /msprobe/{pytorch/doc → docs}/img/GPT-3_3.png +0 -0
  257. /msprobe/{pytorch/doc → docs}/img/GPT-3_4.png +0 -0
  258. /msprobe/{pytorch/doc → docs}/img/GPT-3_5.png +0 -0
  259. /msprobe/{pytorch/doc → docs}/img/GPT-3_6.png +0 -0
  260. /msprobe/{pytorch/doc → docs}/img/GPT-3_7.png +0 -0
  261. /msprobe/{pytorch/doc → docs}/img/GPT-3_8.png +0 -0
  262. /msprobe/{pytorch/doc → docs}/img/YOLOV5S_1.png +0 -0
  263. /msprobe/{pytorch/doc → docs}/img/YOLOV5S_2.png +0 -0
  264. /msprobe/{pytorch/doc → docs}/img/accuracy_checking_details.png +0 -0
  265. /msprobe/{pytorch/doc → docs}/img/accuracy_checking_result.png +0 -0
  266. /msprobe/{pytorch/doc → docs}/img/api_precision_compare_details.png +0 -0
  267. /msprobe/{pytorch/doc → docs}/img/api_precision_compare_result.png +0 -0
  268. /msprobe/{pytorch/doc → docs}/img/auto_analyze_log.png +0 -0
  269. /msprobe/{pytorch/doc → docs}/img/compare_result_pkl.png +0 -0
  270. /msprobe/{pytorch/doc → docs}/img/compare_result_pkl_md5.png.png +0 -0
  271. /msprobe/{pytorch/doc → docs}/img/cpu_info.png +0 -0
  272. /msprobe/{config → docs}/img/free_benchmark.png +0 -0
  273. /msprobe/{doc/grad_probe/img/image-1.png → docs/img/grad_probe_image-1.png} +0 -0
  274. /msprobe/{doc/grad_probe/img/image-2.png → docs/img/grad_probe_image-2.png} +0 -0
  275. /msprobe/{doc/grad_probe/img/image-3.png → docs/img/grad_probe_image-3.png} +0 -0
  276. /msprobe/{doc/grad_probe/img/image-4.png → docs/img/grad_probe_image-4.png} +0 -0
  277. /msprobe/{doc/grad_probe/img/image.png → docs/img/grad_probe_image.png} +0 -0
  278. /msprobe/{pytorch/doc → docs}/img/module_compare.png +0 -0
@@ -1,283 +1,523 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- # Copyright (C) 2022-2023. Huawei Technologies Co., Ltd. All rights reserved.
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- """
17
- import os
18
- import re
19
-
20
- from msprobe.core.common.log import logger
21
- from msprobe.core.common.exceptions import FileCheckException
22
- from msprobe.core.common.const import FileCheckConst
23
-
24
-
25
- class FileChecker:
26
- """
27
- The class for check file.
28
-
29
- Attributes:
30
- file_path: The file or dictionary path to be verified.
31
- path_type: file or dictionary
32
- ability(str): FileCheckConst.WRITE_ABLE or FileCheckConst.READ_ABLE to set file has writability or readability
33
- file_type(str): The correct file type for file
34
- """
35
- def __init__(self, file_path, path_type, ability=None, file_type=None, is_script=True):
36
- self.file_path = file_path
37
- self.path_type = self._check_path_type(path_type)
38
- self.ability = ability
39
- self.file_type = file_type
40
- self.is_script = is_script
41
-
42
- @staticmethod
43
- def _check_path_type(path_type):
44
- if path_type not in [FileCheckConst.DIR, FileCheckConst.FILE]:
45
- logger.error(f'The path_type must be {FileCheckConst.DIR} or {FileCheckConst.FILE}.')
46
- raise FileCheckException(FileCheckException.ILLEGAL_PARAM_ERROR)
47
- return path_type
48
-
49
- def common_check(self):
50
- """
51
- 功能:用户校验基本文件权限:软连接、文件长度、是否存在、读写权限、文件属组、文件特殊字符
52
- 注意:文件后缀的合法性,非通用操作,可使用其他独立接口实现
53
- """
54
- check_path_exists(self.file_path)
55
- check_link(self.file_path)
56
- self.file_path = os.path.realpath(self.file_path)
57
- check_path_length(self.file_path)
58
- check_path_type(self.file_path, self.path_type)
59
- self.check_path_ability()
60
- if self.is_script:
61
- check_path_owner_consistent(self.file_path)
62
- check_path_pattern_vaild(self.file_path)
63
- check_common_file_size(self.file_path)
64
- check_file_suffix(self.file_path, self.file_type)
65
- return self.file_path
66
-
67
- def check_path_ability(self):
68
- if self.ability == FileCheckConst.WRITE_ABLE:
69
- check_path_writability(self.file_path)
70
- if self.ability == FileCheckConst.READ_ABLE:
71
- check_path_readability(self.file_path)
72
- if self.ability == FileCheckConst.READ_WRITE_ABLE:
73
- check_path_readability(self.file_path)
74
- check_path_writability(self.file_path)
75
-
76
-
77
- class FileOpen:
78
- """
79
- The class for open file by a safe way.
80
-
81
- Attributes:
82
- file_path: The file or dictionary path to be opened.
83
- mode(str): The file open mode
84
- """
85
- SUPPORT_READ_MODE = ["r", "rb"]
86
- SUPPORT_WRITE_MODE = ["w", "wb", "a", "ab"]
87
- SUPPORT_READ_WRITE_MODE = ["r+", "rb+", "w+", "wb+", "a+", "ab+"]
88
-
89
- def __init__(self, file_path, mode, encoding='utf-8'):
90
- self.file_path = file_path
91
- self.mode = mode
92
- self.encoding = encoding
93
- self._handle = None
94
-
95
- def __enter__(self):
96
- self.check_file_path()
97
- binary_mode = "b"
98
- if binary_mode not in self.mode:
99
- self._handle = open(self.file_path, self.mode, encoding=self.encoding)
100
- else:
101
- self._handle = open(self.file_path, self.mode)
102
- return self._handle
103
-
104
- def __exit__(self, exc_type, exc_val, exc_tb):
105
- if self._handle:
106
- self._handle.close()
107
-
108
- def check_file_path(self):
109
- support_mode = self.SUPPORT_READ_MODE + self.SUPPORT_WRITE_MODE + self.SUPPORT_READ_WRITE_MODE
110
- if self.mode not in support_mode:
111
- logger.error("File open not support %s mode" % self.mode)
112
- raise FileCheckException(FileCheckException.ILLEGAL_PARAM_ERROR)
113
- check_link(self.file_path)
114
- self.file_path = os.path.realpath(self.file_path)
115
- check_path_length(self.file_path)
116
- self.check_ability_and_owner()
117
- check_path_pattern_vaild(self.file_path)
118
- if os.path.exists(self.file_path):
119
- check_common_file_size(self.file_path)
120
-
121
- def check_ability_and_owner(self):
122
- if self.mode in self.SUPPORT_READ_MODE:
123
- check_path_exists(self.file_path)
124
- check_path_readability(self.file_path)
125
- check_path_owner_consistent(self.file_path)
126
- if self.mode in self.SUPPORT_WRITE_MODE and os.path.exists(self.file_path):
127
- check_path_writability(self.file_path)
128
- check_path_owner_consistent(self.file_path)
129
- if self.mode in self.SUPPORT_READ_WRITE_MODE and os.path.exists(self.file_path):
130
- check_path_readability(self.file_path)
131
- check_path_writability(self.file_path)
132
- check_path_owner_consistent(self.file_path)
133
-
134
-
135
- def check_link(path):
136
- abs_path = os.path.abspath(path)
137
- if os.path.islink(abs_path):
138
- logger.error('The file path {} is a soft link.'.format(path))
139
- raise FileCheckException(FileCheckException.SOFT_LINK_ERROR)
140
-
141
-
142
- def check_path_length(path, name_length=None):
143
- file_max_name_length = name_length if name_length else FileCheckConst.FILE_NAME_LENGTH
144
- if len(path) > FileCheckConst.DIRECTORY_LENGTH or \
145
- len(os.path.basename(path)) > file_max_name_length:
146
- logger.error('The file path length exceeds limit.')
147
- raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR)
148
-
149
-
150
- def check_path_exists(path):
151
- if not os.path.exists(path):
152
- logger.error('The file path %s does not exist.' % path)
153
- raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR)
154
-
155
-
156
- def check_path_readability(path):
157
- if not os.access(path, os.R_OK):
158
- logger.error('The file path %s is not readable.' % path)
159
- raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
160
-
161
-
162
- def check_path_writability(path):
163
- if not os.access(path, os.W_OK):
164
- logger.error('The file path %s is not writable.' % path)
165
- raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
166
-
167
-
168
- def check_path_executable(path):
169
- if not os.access(path, os.X_OK):
170
- logger.error('The file path %s is not executable.' % path)
171
- raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
172
-
173
-
174
- def check_other_user_writable(path):
175
- st = os.stat(path)
176
- if st.st_mode & 0o002:
177
- logger.error('The file path %s may be insecure because other users have write permissions. ' % path)
178
- raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
179
-
180
-
181
- def check_path_owner_consistent(path):
182
- file_owner = os.stat(path).st_uid
183
- if file_owner != os.getuid():
184
- logger.error('The file path %s may be insecure because is does not belong to you.' % path)
185
- raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
186
-
187
-
188
- def check_path_pattern_vaild(path):
189
- if not re.match(FileCheckConst.FILE_VALID_PATTERN, path):
190
- logger.error('The file path %s contains special characters.' %(path))
191
- raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR)
192
-
193
-
194
- def check_file_size(file_path, max_size):
195
- file_size = os.path.getsize(file_path)
196
- if file_size >= max_size:
197
- logger.error(f'The size of file path {file_path} exceeds {max_size} bytes.')
198
- raise FileCheckException(FileCheckException.FILE_TOO_LARGE_ERROR)
199
-
200
-
201
- def check_common_file_size(file_path):
202
- if os.path.isfile(file_path):
203
- for suffix, max_size in FileCheckConst.FILE_SIZE_DICT.items():
204
- if file_path.endswith(suffix):
205
- check_file_size(file_path, max_size)
206
- break
207
-
208
-
209
- def check_file_suffix(file_path, file_suffix):
210
- if file_suffix:
211
- if not file_path.endswith(file_suffix):
212
- logger.error(f"The {file_path} should be a {file_suffix} file!")
213
- raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
214
-
215
-
216
- def check_path_type(file_path, file_type):
217
- if file_type == FileCheckConst.FILE:
218
- if not os.path.isfile(file_path):
219
- logger.error(f"The {file_path} should be a file!")
220
- raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
221
- if file_type == FileCheckConst.DIR:
222
- if not os.path.isdir(file_path):
223
- logger.error(f"The {file_path} should be a dictionary!")
224
- raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
225
-
226
-
227
- def create_directory(dir_path):
228
- """
229
- Function Description:
230
- creating a directory with specified permissions
231
- Parameter:
232
- dir_path: directory path
233
- Exception Description:
234
- when invalid data throw exception
235
- """
236
- dir_path = os.path.realpath(dir_path)
237
- try:
238
- os.makedirs(dir_path, mode=FileCheckConst.DATA_DIR_AUTHORITY, exist_ok=True)
239
- except OSError as ex:
240
- raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR,
241
- 'Failed to create {}. Please check the path permission or disk space .{}'.format(dir_path, str(ex))) from ex
242
-
243
-
244
- def check_path_before_create(path):
245
- if path_len_exceeds_limit(path):
246
- raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR, 'The file path length exceeds limit.')
247
-
248
- if not re.match(FileCheckConst.FILE_PATTERN, os.path.realpath(path)):
249
- raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR,
250
- 'The file path {} contains special characters.'.format(path))
251
-
252
-
253
- def change_mode(path, mode):
254
- if not os.path.exists(path) or os.path.islink(path):
255
- return
256
- try:
257
- os.chmod(path, mode)
258
- except PermissionError as ex:
259
- raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR,
260
- 'Failed to change {} authority. {}'.format(path, str(ex))) from ex
261
-
262
-
263
- def path_len_exceeds_limit(file_path):
264
- return len(os.path.realpath(file_path)) > FileCheckConst.DIRECTORY_LENGTH or \
265
- len(os.path.basename(file_path)) > FileCheckConst.FILE_NAME_LENGTH
266
-
267
-
268
- def check_file_type(path):
269
- """
270
- Function Description:
271
- determine if it is a file or a directory
272
- Parameter:
273
- path: path
274
- Exception Description:
275
- when neither a file nor a directory throw exception
276
- """
277
- if os.path.isdir(path):
278
- return FileCheckConst.DIR
279
- elif os.path.isfile(path):
280
- return FileCheckConst.FILE
281
- else:
282
- logger.error('Neither a file nor a directory.')
283
- raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ # Copyright (C) 2022-2023. Huawei Technologies Co., Ltd. All rights reserved.
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ import csv
18
+ import fcntl
19
+ import os
20
+ import json
21
+ import re
22
+ import shutil
23
+ import yaml
24
+ import numpy as np
25
+ import pandas as pd
26
+
27
+ from msprobe.core.common.log import logger
28
+ from msprobe.core.common.exceptions import FileCheckException
29
+ from msprobe.core.common.const import FileCheckConst
30
+
31
+
32
+ class FileChecker:
33
+ """
34
+ The class for check file.
35
+
36
+ Attributes:
37
+ file_path: The file or dictionary path to be verified.
38
+ path_type: file or dictionary
39
+ ability(str): FileCheckConst.WRITE_ABLE or FileCheckConst.READ_ABLE to set file has writability or readability
40
+ file_type(str): The correct file type for file
41
+ """
42
+
43
+ def __init__(self, file_path, path_type, ability=None, file_type=None, is_script=True):
44
+ self.file_path = file_path
45
+ self.path_type = self._check_path_type(path_type)
46
+ self.ability = ability
47
+ self.file_type = file_type
48
+ self.is_script = is_script
49
+
50
+ @staticmethod
51
+ def _check_path_type(path_type):
52
+ if path_type not in [FileCheckConst.DIR, FileCheckConst.FILE]:
53
+ logger.error(f'The path_type must be {FileCheckConst.DIR} or {FileCheckConst.FILE}.')
54
+ raise FileCheckException(FileCheckException.ILLEGAL_PARAM_ERROR)
55
+ return path_type
56
+
57
+ def common_check(self):
58
+ """
59
+ 功能:用户校验基本文件权限:软连接、文件长度、是否存在、读写权限、文件属组、文件特殊字符
60
+ 注意:文件后缀的合法性,非通用操作,可使用其他独立接口实现
61
+ """
62
+ check_path_exists(self.file_path)
63
+ check_link(self.file_path)
64
+ self.file_path = os.path.realpath(self.file_path)
65
+ check_path_length(self.file_path)
66
+ check_path_type(self.file_path, self.path_type)
67
+ self.check_path_ability()
68
+ if self.is_script:
69
+ check_path_owner_consistent(self.file_path)
70
+ check_path_pattern_vaild(self.file_path)
71
+ check_common_file_size(self.file_path)
72
+ check_file_suffix(self.file_path, self.file_type)
73
+ return self.file_path
74
+
75
+ def check_path_ability(self):
76
+ if self.ability == FileCheckConst.WRITE_ABLE:
77
+ check_path_writability(self.file_path)
78
+ if self.ability == FileCheckConst.READ_ABLE:
79
+ check_path_readability(self.file_path)
80
+ if self.ability == FileCheckConst.READ_WRITE_ABLE:
81
+ check_path_readability(self.file_path)
82
+ check_path_writability(self.file_path)
83
+
84
+
85
+ class FileOpen:
86
+ """
87
+ The class for open file by a safe way.
88
+
89
+ Attributes:
90
+ file_path: The file or dictionary path to be opened.
91
+ mode(str): The file open mode
92
+ """
93
+ SUPPORT_READ_MODE = ["r", "rb"]
94
+ SUPPORT_WRITE_MODE = ["w", "wb", "a", "ab"]
95
+ SUPPORT_READ_WRITE_MODE = ["r+", "rb+", "w+", "wb+", "a+", "ab+"]
96
+
97
+ def __init__(self, file_path, mode, encoding='utf-8'):
98
+ self.file_path = file_path
99
+ self.mode = mode
100
+ self.encoding = encoding
101
+ self._handle = None
102
+
103
+ def __enter__(self):
104
+ self.check_file_path()
105
+ binary_mode = "b"
106
+ if binary_mode not in self.mode:
107
+ self._handle = open(self.file_path, self.mode, encoding=self.encoding)
108
+ else:
109
+ self._handle = open(self.file_path, self.mode)
110
+ return self._handle
111
+
112
+ def __exit__(self, exc_type, exc_val, exc_tb):
113
+ if self._handle:
114
+ self._handle.close()
115
+
116
+ def check_file_path(self):
117
+ support_mode = self.SUPPORT_READ_MODE + self.SUPPORT_WRITE_MODE + self.SUPPORT_READ_WRITE_MODE
118
+ if self.mode not in support_mode:
119
+ logger.error("File open not support %s mode" % self.mode)
120
+ raise FileCheckException(FileCheckException.ILLEGAL_PARAM_ERROR)
121
+ check_link(self.file_path)
122
+ self.file_path = os.path.realpath(self.file_path)
123
+ check_path_length(self.file_path)
124
+ self.check_ability_and_owner()
125
+ check_path_pattern_vaild(self.file_path)
126
+ if os.path.exists(self.file_path):
127
+ check_common_file_size(self.file_path)
128
+
129
+ def check_ability_and_owner(self):
130
+ if self.mode in self.SUPPORT_READ_MODE:
131
+ check_path_exists(self.file_path)
132
+ check_path_readability(self.file_path)
133
+ check_path_owner_consistent(self.file_path)
134
+ if self.mode in self.SUPPORT_WRITE_MODE and os.path.exists(self.file_path):
135
+ check_path_writability(self.file_path)
136
+ check_path_owner_consistent(self.file_path)
137
+ if self.mode in self.SUPPORT_READ_WRITE_MODE and os.path.exists(self.file_path):
138
+ check_path_readability(self.file_path)
139
+ check_path_writability(self.file_path)
140
+ check_path_owner_consistent(self.file_path)
141
+
142
+
143
+ def check_link(path):
144
+ abs_path = os.path.abspath(path)
145
+ if os.path.islink(abs_path):
146
+ logger.error('The file path {} is a soft link.'.format(path))
147
+ raise FileCheckException(FileCheckException.SOFT_LINK_ERROR)
148
+
149
+
150
+ def check_path_length(path, name_length=None):
151
+ file_max_name_length = name_length if name_length else FileCheckConst.FILE_NAME_LENGTH
152
+ if len(path) > FileCheckConst.DIRECTORY_LENGTH or \
153
+ len(os.path.basename(path)) > file_max_name_length:
154
+ logger.error('The file path length exceeds limit.')
155
+ raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR)
156
+
157
+
158
+ def check_path_exists(path):
159
+ if not os.path.exists(path):
160
+ logger.error('The file path %s does not exist.' % path)
161
+ raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR)
162
+
163
+
164
+ def check_path_readability(path):
165
+ if not os.access(path, os.R_OK):
166
+ logger.error('The file path %s is not readable.' % path)
167
+ raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
168
+
169
+
170
+ def check_path_writability(path):
171
+ if not os.access(path, os.W_OK):
172
+ logger.error('The file path %s is not writable.' % path)
173
+ raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
174
+
175
+
176
+ def check_path_executable(path):
177
+ if not os.access(path, os.X_OK):
178
+ logger.error('The file path %s is not executable.' % path)
179
+ raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
180
+
181
+
182
+ def check_other_user_writable(path):
183
+ st = os.stat(path)
184
+ if st.st_mode & 0o002:
185
+ logger.error('The file path %s may be insecure because other users have write permissions. ' % path)
186
+ raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
187
+
188
+
189
+ def check_path_owner_consistent(path):
190
+ file_owner = os.stat(path).st_uid
191
+ if file_owner != os.getuid() and os.getuid() != 0:
192
+ logger.error('The file path %s may be insecure because is does not belong to you.' % path)
193
+ raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR)
194
+
195
+
196
+ def check_path_pattern_vaild(path):
197
+ if not re.match(FileCheckConst.FILE_VALID_PATTERN, path):
198
+ logger.error('The file path %s contains special characters.' % (path))
199
+ raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR)
200
+
201
+
202
+ def check_file_size(file_path, max_size):
203
+ try:
204
+ file_size = os.path.getsize(file_path)
205
+ except OSError as os_error:
206
+ logger.error(f'Failed to open "{file_path}". {str(os_error)}')
207
+ raise FileCheckException(FileCheckException.INVALID_FILE_ERROR) from os_error
208
+ if file_size >= max_size:
209
+ logger.error(f'The size ({file_size}) of {file_path} exceeds ({max_size}) bytes, tools not support.')
210
+ raise FileCheckException(FileCheckException.FILE_TOO_LARGE_ERROR)
211
+
212
+
213
+ def check_common_file_size(file_path):
214
+ if os.path.isfile(file_path):
215
+ for suffix, max_size in FileCheckConst.FILE_SIZE_DICT.items():
216
+ if file_path.endswith(suffix):
217
+ check_file_size(file_path, max_size)
218
+ return
219
+ check_file_size(file_path, FileCheckConst.COMMOM_FILE_SIZE)
220
+
221
+
222
+
223
+ def check_file_suffix(file_path, file_suffix):
224
+ if file_suffix:
225
+ if not file_path.endswith(file_suffix):
226
+ logger.error(f"The {file_path} should be a {file_suffix} file!")
227
+ raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
228
+
229
+
230
+ def check_path_type(file_path, file_type):
231
+ if file_type == FileCheckConst.FILE:
232
+ if not os.path.isfile(file_path):
233
+ logger.error(f"The {file_path} should be a file!")
234
+ raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
235
+ if file_type == FileCheckConst.DIR:
236
+ if not os.path.isdir(file_path):
237
+ logger.error(f"The {file_path} should be a dictionary!")
238
+ raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
239
+
240
+
241
+ def make_dir(dir_path):
242
+ dir_path = os.path.realpath(dir_path)
243
+ check_path_before_create(dir_path)
244
+ if os.path.isdir(dir_path):
245
+ return
246
+ try:
247
+ os.makedirs(dir_path, mode=FileCheckConst.DATA_DIR_AUTHORITY, exist_ok=True)
248
+ except OSError as ex:
249
+ raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR,
250
+ f"Failed to create {dir_path}. "
251
+ f"Please check the path permission or disk space. {str(ex)}") from ex
252
+ file_check = FileChecker(dir_path, FileCheckConst.DIR)
253
+ file_check.common_check()
254
+
255
+
256
+ def create_directory(dir_path):
257
+ """
258
+ Function Description:
259
+ creating a safe directory with specified permissions
260
+ Parameter:
261
+ dir_path: directory path
262
+ Exception Description:
263
+ when invalid data throw exception
264
+ """
265
+ dir_path = os.path.realpath(dir_path)
266
+ check_path_before_create(dir_path)
267
+ parent_dir = os.path.dirname(dir_path)
268
+ if not os.path.isdir(parent_dir):
269
+ create_directory(parent_dir)
270
+ make_dir(dir_path)
271
+
272
+
273
+ def check_path_before_create(path):
274
+ if path_len_exceeds_limit(path):
275
+ raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR, 'The file path length exceeds limit.')
276
+
277
+ if not re.match(FileCheckConst.FILE_PATTERN, os.path.realpath(path)):
278
+ raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR,
279
+ 'The file path {} contains special characters.'.format(path))
280
+
281
+
282
+ def check_file_or_directory_path(path, isdir=False):
283
+ """
284
+ Function Description:
285
+ check whether the path is valid
286
+ Parameter:
287
+ path: the path to check
288
+ isdir: the path is dir or file
289
+ Exception Description:
290
+ when invalid data throw exception
291
+ """
292
+ if isdir:
293
+ path_checker = FileChecker(path, FileCheckConst.DIR, FileCheckConst.WRITE_ABLE)
294
+ else:
295
+ path_checker = FileChecker(path, FileCheckConst.FILE, FileCheckConst.READ_ABLE)
296
+ path_checker.common_check()
297
+
298
+
299
+ def change_mode(path, mode):
300
+ if not os.path.exists(path) or os.path.islink(path):
301
+ return
302
+ try:
303
+ os.chmod(path, mode)
304
+ except PermissionError as ex:
305
+ raise FileCheckException(FileCheckException.FILE_PERMISSION_ERROR,
306
+ 'Failed to change {} authority. {}'.format(path, str(ex))) from ex
307
+
308
+
309
+ def path_len_exceeds_limit(file_path):
310
+ return len(os.path.realpath(file_path)) > FileCheckConst.DIRECTORY_LENGTH or \
311
+ len(os.path.basename(file_path)) > FileCheckConst.FILE_NAME_LENGTH
312
+
313
+
314
+ def check_file_type(path):
315
+ """
316
+ Function Description:
317
+ determine if it is a file or a directory
318
+ Parameter:
319
+ path: path
320
+ Exception Description:
321
+ when neither a file nor a directory throw exception
322
+ """
323
+ if os.path.isdir(path):
324
+ return FileCheckConst.DIR
325
+ elif os.path.isfile(path):
326
+ return FileCheckConst.FILE
327
+ else:
328
+ logger.error(f'{path} does not exist, please check!')
329
+ raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
330
+
331
+
332
+ def load_yaml(yaml_path):
333
+ path_checker = FileChecker(yaml_path, FileCheckConst.FILE, FileCheckConst.READ_ABLE, FileCheckConst.YAML_SUFFIX)
334
+ checked_path = path_checker.common_check()
335
+ try:
336
+ with FileOpen(checked_path, "r") as f:
337
+ yaml_data = yaml.safe_load(f)
338
+ except Exception as e:
339
+ logger.error(f"The yaml file failed to load. Please check the path: {checked_path}.")
340
+ raise RuntimeError(f"Load yaml file {checked_path} failed.") from e
341
+ return yaml_data
342
+
343
+
344
+ def load_npy(filepath):
345
+ check_file_or_directory_path(filepath)
346
+ try:
347
+ npy = np.load(filepath)
348
+ except Exception as e:
349
+ logger.error(f"The numpy file failed to load. Please check the path: {filepath}.")
350
+ raise RuntimeError(f"Load numpy file {filepath} failed.") from e
351
+ return npy
352
+
353
+
354
+ def load_json(json_path):
355
+ try:
356
+ with FileOpen(json_path, "r") as f:
357
+ fcntl.flock(f, fcntl.LOCK_EX)
358
+ data = json.load(f)
359
+ fcntl.flock(f, fcntl.LOCK_UN)
360
+ except Exception as e:
361
+ logger.error(f'load json file "{os.path.basename(json_path)}" failed.')
362
+ raise RuntimeError(f"Load json file {json_path} failed.") from e
363
+ return data
364
+
365
+
366
+ def save_json(json_path, data, indent=None):
367
+ json_path = os.path.realpath(json_path)
368
+ check_path_before_create(json_path)
369
+ try:
370
+ with FileOpen(json_path, 'w') as f:
371
+ fcntl.flock(f, fcntl.LOCK_EX)
372
+ json.dump(data, f, indent=indent)
373
+ fcntl.flock(f, fcntl.LOCK_UN)
374
+ except Exception as e:
375
+ logger.error(f'Save json file "{os.path.basename(json_path)}" failed.')
376
+ raise RuntimeError(f"Save json file {json_path} failed.") from e
377
+ change_mode(json_path, FileCheckConst.DATA_FILE_AUTHORITY)
378
+
379
+
380
+ def save_yaml(yaml_path, data):
381
+ yaml_path = os.path.realpath(yaml_path)
382
+ check_path_before_create(yaml_path)
383
+ try:
384
+ with FileOpen(yaml_path, 'w') as f:
385
+ fcntl.flock(f, fcntl.LOCK_EX)
386
+ yaml.dump(data, f, sort_keys=False)
387
+ fcntl.flock(f, fcntl.LOCK_UN)
388
+ except Exception as e:
389
+ logger.error(f'Save yaml file "{os.path.basename(yaml_path)}" failed.')
390
+ raise RuntimeError(f"Save yaml file {yaml_path} failed.") from e
391
+ change_mode(yaml_path, FileCheckConst.DATA_FILE_AUTHORITY)
392
+
393
+
394
+ def move_file(src_path, dst_path):
395
+ check_file_or_directory_path(src_path)
396
+ check_path_before_create(dst_path)
397
+ try:
398
+ shutil.move(src_path, dst_path)
399
+ except Exception as e:
400
+ logger.error(f"move file {src_path} to {dst_path} failed")
401
+ raise RuntimeError(f"move file {src_path} to {dst_path} failed") from e
402
+ change_mode(dst_path, FileCheckConst.DATA_FILE_AUTHORITY)
403
+
404
+
405
+ def save_npy(data, filepath):
406
+ filepath = os.path.realpath(filepath)
407
+ check_path_before_create(filepath)
408
+ try:
409
+ np.save(filepath, data)
410
+ except Exception as e:
411
+ logger.error(f"The numpy file failed to save. Please check the path: {filepath}.")
412
+ raise RuntimeError(f"Save numpy file {filepath} failed.") from e
413
+ change_mode(filepath, FileCheckConst.DATA_FILE_AUTHORITY)
414
+
415
+
416
+ def save_npy_to_txt(data, dst_file='', align=0):
417
+ if os.path.exists(dst_file):
418
+ logger.info("Dst file %s exists, will not save new one." % dst_file)
419
+ return
420
+ shape = data.shape
421
+ data = data.flatten()
422
+ if align == 0:
423
+ align = 1 if len(shape) == 0 else shape[-1]
424
+ elif data.size % align != 0:
425
+ pad_array = np.zeros((align - data.size % align,))
426
+ data = np.append(data, pad_array)
427
+ check_path_before_create(dst_file)
428
+ try:
429
+ np.savetxt(dst_file, data.reshape((-1, align)), delimiter=' ', fmt='%g')
430
+ except Exception as e:
431
+ logger.error("An unexpected error occurred: %s when savetxt to %s" % (str(e), dst_file))
432
+ change_mode(dst_file, FileCheckConst.DATA_FILE_AUTHORITY)
433
+
434
+
435
+ def save_workbook(workbook, file_path):
436
+ """
437
+ 保存工作簿到指定的文件路径
438
+ workbook: 要保存的工作簿对象
439
+ file_path: 文件保存路径
440
+ """
441
+ file_path = os.path.realpath(file_path)
442
+ check_path_before_create(file_path)
443
+ try:
444
+ workbook.save(file_path)
445
+ except Exception as e:
446
+ logger.error(f'Save result file "{os.path.basename(file_path)}" failed')
447
+ raise RuntimeError(f"Save result file {file_path} failed.") from e
448
+ change_mode(file_path, FileCheckConst.DATA_FILE_AUTHORITY)
449
+
450
+
451
+ def write_csv(data, filepath, mode="a+", malicious_check=False):
452
+ def csv_value_is_valid(value: str) -> bool:
453
+ if not isinstance(value, str):
454
+ return True
455
+ try:
456
+ # -1.00 or +1.00 should be consdiered as digit numbers
457
+ float(value)
458
+ except ValueError:
459
+ # otherwise, they will be considered as formular injections
460
+ return not bool(re.compile(FileCheckConst.CSV_BLACK_LIST).search(value))
461
+ return True
462
+
463
+ if malicious_check:
464
+ for row in data:
465
+ for cell in row:
466
+ if not csv_value_is_valid(cell):
467
+ raise RuntimeError(f"Malicious value [{cell}] is not allowed " \
468
+ f"to be written into the csv: {filepath}.")
469
+
470
+ file_path = os.path.realpath(filepath)
471
+ check_path_before_create(filepath)
472
+ try:
473
+ with FileOpen(filepath, mode, encoding='utf-8-sig') as f:
474
+ writer = csv.writer(f)
475
+ writer.writerows(data)
476
+ except Exception as e:
477
+ logger.error(f'Save csv file "{os.path.basename(file_path)}" failed')
478
+ raise RuntimeError(f"Save csv file {file_path} failed.") from e
479
+ change_mode(filepath, FileCheckConst.DATA_FILE_AUTHORITY)
480
+
481
+
482
+ def read_csv(filepath):
483
+ check_file_or_directory_path(filepath)
484
+ try:
485
+ csv_data = pd.read_csv(filepath)
486
+ except Exception as e:
487
+ logger.error(f"The csv file failed to load. Please check the path: {filepath}.")
488
+ raise RuntimeError(f"Read csv file {filepath} failed.") from e
489
+ return csv_data
490
+
491
+
492
+ def remove_path(path):
493
+ if not os.path.exists(path):
494
+ return
495
+ try:
496
+ if os.path.islink(path) or os.path.isfile(path):
497
+ os.remove(path)
498
+ else:
499
+ shutil.rmtree(path)
500
+ except PermissionError as err:
501
+ logger.error("Failed to delete {}. Please check the permission.".format(path))
502
+ raise FileCheckException(FileCheckException.ILLEGAL_PATH_ERROR) from err
503
+ except Exception as e:
504
+ logger.error("Failed to delete {}. Please check.".format(path))
505
+ raise RuntimeError(f"Delete {path} failed.") from e
506
+
507
+
508
+ def get_json_contents(file_path):
509
+ ops = get_file_content_bytes(file_path)
510
+ try:
511
+ json_obj = json.loads(ops)
512
+ except ValueError as error:
513
+ logger.error('Failed to load json.')
514
+ raise FileCheckException(FileCheckException.INVALID_FILE_ERROR) from error
515
+ if not isinstance(json_obj, dict):
516
+ logger.error('Json file content is not a dictionary!')
517
+ raise FileCheckException(FileCheckException.INVALID_FILE_ERROR)
518
+ return json_obj
519
+
520
+
521
+ def get_file_content_bytes(file):
522
+ with FileOpen(file, 'rb') as file_handle:
523
+ return file_handle.read()