mangotools 1.0.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.
Files changed (62) hide show
  1. mangotools-1.0.0/LICENSE +21 -0
  2. mangotools-1.0.0/MANIFEST.in +3 -0
  3. mangotools-1.0.0/PKG-INFO +34 -0
  4. mangotools-1.0.0/README.md +13 -0
  5. mangotools-1.0.0/mangotools/__init__.py +6 -0
  6. mangotools-1.0.0/mangotools/assertion/__init__.py +26 -0
  7. mangotools-1.0.0/mangotools/assertion/_custom_assertion.py +27 -0
  8. mangotools-1.0.0/mangotools/assertion/_public_assertion.py +291 -0
  9. mangotools-1.0.0/mangotools/assertion/_sql_assertion.py +29 -0
  10. mangotools-1.0.0/mangotools/data_processor/__init__.py +123 -0
  11. mangotools-1.0.0/mangotools/data_processor/_cache_tool.py +38 -0
  12. mangotools-1.0.0/mangotools/data_processor/_coding_tool.py +21 -0
  13. mangotools-1.0.0/mangotools/data_processor/_encryption_tool.py +44 -0
  14. mangotools-1.0.0/mangotools/data_processor/_json_tool.py +60 -0
  15. mangotools-1.0.0/mangotools/data_processor/_random_character_info_data.py +69 -0
  16. mangotools-1.0.0/mangotools/data_processor/_random_number_data.py +79 -0
  17. mangotools-1.0.0/mangotools/data_processor/_random_string_data.py +65 -0
  18. mangotools-1.0.0/mangotools/data_processor/_random_time_data.py +219 -0
  19. mangotools-1.0.0/mangotools/data_processor/_sql_cache.py +133 -0
  20. mangotools-1.0.0/mangotools/database/__init__.py +16 -0
  21. mangotools-1.0.0/mangotools/database/_mysql_connect.py +64 -0
  22. mangotools-1.0.0/mangotools/database/_sqlite_connect.py +41 -0
  23. mangotools-1.0.0/mangotools/decorator/__init__.py +24 -0
  24. mangotools-1.0.0/mangotools/decorator/convert_args.py +29 -0
  25. mangotools-1.0.0/mangotools/decorator/inject_to_class.py +23 -0
  26. mangotools-1.0.0/mangotools/decorator/method_callback.py +65 -0
  27. mangotools-1.0.0/mangotools/decorator/retry.py +45 -0
  28. mangotools-1.0.0/mangotools/decorator/singleton.py +21 -0
  29. mangotools-1.0.0/mangotools/enums/__init__.py +17 -0
  30. mangotools-1.0.0/mangotools/enums/_base_enum.py +38 -0
  31. mangotools-1.0.0/mangotools/enums/_enums.py +44 -0
  32. mangotools-1.0.0/mangotools/exceptions/__init__.py +13 -0
  33. mangotools-1.0.0/mangotools/exceptions/_error_msg.py +15 -0
  34. mangotools-1.0.0/mangotools/exceptions/_exceptions.py +29 -0
  35. mangotools-1.0.0/mangotools/log_collector/__init__.py +66 -0
  36. mangotools-1.0.0/mangotools/log_collector/_log_control.py +59 -0
  37. mangotools-1.0.0/mangotools/mangos/__init__.py +74 -0
  38. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_linux/__init__.py +5 -0
  39. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_linux/mango.py +3 -0
  40. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_linux/pyarmor_runtime_000000/__init__.py +2 -0
  41. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_linux/pyarmor_runtime_000000/pyarmor_runtime.so +0 -0
  42. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_windows/__init__.py +5 -0
  43. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_windows/mango.py +3 -0
  44. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_windows/pyarmor_runtime_000000/__init__.py +2 -0
  45. mangotools-1.0.0/mangotools/mangos/pyarmor_runtime_windows/pyarmor_runtime_000000/pyarmor_runtime.pyd +0 -0
  46. mangotools-1.0.0/mangotools/method.py +96 -0
  47. mangotools-1.0.0/mangotools/models/__init__.py +21 -0
  48. mangotools-1.0.0/mangotools/models/_models.py +61 -0
  49. mangotools-1.0.0/mangotools/notice/__init__.py +17 -0
  50. mangotools-1.0.0/mangotools/notice/_mail_send.py +70 -0
  51. mangotools-1.0.0/mangotools/notice/_wechat_send.py +98 -0
  52. mangotools-1.0.0/mangotools.egg-info/PKG-INFO +34 -0
  53. mangotools-1.0.0/mangotools.egg-info/SOURCES.txt +60 -0
  54. mangotools-1.0.0/mangotools.egg-info/dependency_links.txt +1 -0
  55. mangotools-1.0.0/mangotools.egg-info/requires.txt +11 -0
  56. mangotools-1.0.0/mangotools.egg-info/top_level.txt +2 -0
  57. mangotools-1.0.0/setup.cfg +4 -0
  58. mangotools-1.0.0/setup.py +51 -0
  59. mangotools-1.0.0/tests/__init__.py +5 -0
  60. mangotools-1.0.0/tests/cache_test.py +50 -0
  61. mangotools-1.0.0/tests/test.py +72 -0
  62. mangotools-1.0.0/tests/test_sql_cache.py +73 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 maopeng
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,3 @@
1
+ exclude mangotools/mango/setup.py
2
+ exclude mangotools/mango/mango.pyx
3
+ exclude mangotools/mango/mango.c
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.1
2
+ Name: mangotools
3
+ Version: 1.0.0
4
+ Summary: 测试工具
5
+ Home-page: https://gitee.com/mao-peng/testkit
6
+ Author: 毛鹏
7
+ Author-email: 729164035@qq.com
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ License-File: LICENSE
10
+ Requires-Dist: aiomysql==0.2.0
11
+ Requires-Dist: PyMySQL==1.1.1
12
+ Requires-Dist: jsonpath==0.82.2
13
+ Requires-Dist: cachetools==5.3.1
14
+ Requires-Dist: Faker==24.1.0
15
+ Requires-Dist: diskcache==5.6.3
16
+ Requires-Dist: pydantic==2.9.2
17
+ Requires-Dist: colorlog==6.7.0
18
+ Requires-Dist: pyarmor==9.0.6
19
+ Requires-Dist: assertpy==1.1
20
+ Requires-Dist: deepdiff==8.0.1
21
+
22
+ # testkit
23
+
24
+ #### 介绍
25
+
26
+ 测试工具
27
+
28
+ #### 安装教程
29
+
30
+ 1. pip install mangokit
31
+
32
+ #### 使用说明
33
+
34
+ 1.
@@ -0,0 +1,13 @@
1
+ # testkit
2
+
3
+ #### 介绍
4
+
5
+ 测试工具
6
+
7
+ #### 安装教程
8
+
9
+ 1. pip install mangokit
10
+
11
+ #### 使用说明
12
+
13
+ 1.
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description:
4
+ # @Time : 2024-09-07 22:15
5
+ # @Author : 毛鹏
6
+
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台# @Description:
3
+ # @Time : 2023/4/6 13:36
4
+ # @Author : 毛鹏
5
+
6
+ from ..assertion._custom_assertion import CustomAssertion
7
+ from ..assertion._public_assertion import WhatIsItAssertion, ContainAssertion, MatchingAssertion, \
8
+ WhatIsEqualToAssertion, PublicAssertion
9
+ from ..assertion._sql_assertion import SqlAssertion
10
+ import sys
11
+
12
+ python_version = sys.version_info
13
+ if f"{python_version.major}.{python_version.minor}" != "3.10":
14
+ raise Exception("必须使用>Python3.10.4")
15
+
16
+
17
+ class Assertion(WhatIsItAssertion, ContainAssertion, MatchingAssertion, WhatIsEqualToAssertion):
18
+ pass
19
+
20
+
21
+ __all__ = [
22
+ 'Assertion',
23
+ 'CustomAssertion',
24
+ 'SqlAssertion',
25
+ 'PublicAssertion',
26
+ ]
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description:
4
+ # @Time : 2024-01-05 18:05
5
+ # @Author : 毛鹏
6
+ from ..decorator import sync_method_callback
7
+ from ..exceptions import ERROR_MSG_0061, MangoKitError
8
+ from ..models import MethodModel
9
+
10
+
11
+ class CustomAssertion:
12
+ """自定义断言"""
13
+
14
+ @staticmethod
15
+ @sync_method_callback('ass', '自定义断言', 7, [
16
+ MethodModel(f='func_str', p='请输入一个函数,在函数里面自己断言', d=True),
17
+ MethodModel(f='func_name', p='请输入这个函数的名称', d=True), ])
18
+ def ass_func(func_str, func_name='func'):
19
+ """输入断言代码"""
20
+ try:
21
+ global_namespace = {}
22
+ exec(func_str, global_namespace)
23
+ return global_namespace[func_name]
24
+ except (KeyError, SyntaxError, TypeError):
25
+ import traceback
26
+ traceback.print_exc()
27
+ raise MangoKitError(*ERROR_MSG_0061)
@@ -0,0 +1,291 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台# @Description:
3
+ # @Time : 2023-09-09 23:17
4
+ # @Author : 毛鹏
5
+ from assertpy import assert_that
6
+ from deepdiff import DeepDiff
7
+
8
+ from mangokit.decorator import sync_method_callback
9
+ from mangokit.models import MethodModel
10
+
11
+
12
+ class WhatIsItAssertion:
13
+ """是什么"""
14
+
15
+ @staticmethod
16
+ @sync_method_callback('ass', '是什么', 0, [
17
+ MethodModel(f='actual', d=True)])
18
+ def p_is_not_none(actual):
19
+ """不是null"""
20
+ try:
21
+ assert_that(actual).is_not_none()
22
+ except AssertionError as e:
23
+ raise AssertionError(f'实际={actual}, 预期=不是null') from e
24
+
25
+ @staticmethod
26
+ @sync_method_callback('ass', '是什么', 1, [
27
+ MethodModel(f='actual', d=True)])
28
+ def p_is_none(actual):
29
+ """是null"""
30
+ try:
31
+ assert_that(actual).is_none()
32
+ except AssertionError as e:
33
+ raise AssertionError(f'实际={actual}, 预期=是null') from e
34
+
35
+ @staticmethod
36
+ @sync_method_callback('ass', '是什么', 2, [
37
+ MethodModel(f='actual', d=True)])
38
+ def p_is_empty(actual):
39
+ """是空字符串"""
40
+ try:
41
+ assert_that(actual).is_empty()
42
+ except AssertionError as e:
43
+ raise AssertionError(f'实际={actual}, 预期=是空字符串') from e
44
+
45
+ @staticmethod
46
+ @sync_method_callback('ass', '是什么', 3, [
47
+ MethodModel(f='actual', d=True)])
48
+ def p_is_not_empty(actual):
49
+ """不是空符串"""
50
+ try:
51
+ assert_that(actual).is_not_empty()
52
+ except AssertionError as e:
53
+ raise AssertionError(f'实际={actual}, 预期=不是空符串') from e
54
+
55
+ @staticmethod
56
+ @sync_method_callback('ass', '是什么', 4, [
57
+ MethodModel(f='actual', d=True)])
58
+ def p_is_false(actual):
59
+ """是false"""
60
+ try:
61
+ assert_that(actual).is_false()
62
+ except AssertionError as e:
63
+ raise AssertionError(f'实际={actual}, 预期=是false') from e
64
+
65
+ @staticmethod
66
+ @sync_method_callback('ass', '是什么', 5, [
67
+ MethodModel(f='actual', d=True)])
68
+ def p_is_true(actual):
69
+ """是true"""
70
+ try:
71
+ assert_that(actual).is_true()
72
+ except AssertionError as e:
73
+ raise AssertionError(f'实际={actual}, 预期=是true') from e
74
+
75
+ @staticmethod
76
+ @sync_method_callback('ass', '是什么', 6, [
77
+ MethodModel(f='actual', d=True)])
78
+ def p_is_alpha(actual):
79
+ """是字母"""
80
+ try:
81
+ assert_that(actual).is_alpha()
82
+ except AssertionError as e:
83
+ raise AssertionError(f'实际={actual}, 预期=是字母') from e
84
+
85
+ @staticmethod
86
+ @sync_method_callback('ass', '是什么', 7, [
87
+ MethodModel(f='actual', d=True)])
88
+ def p_is_digit(actual):
89
+ """是数字"""
90
+ try:
91
+ assert_that(actual).is_digit()
92
+ except AssertionError as e:
93
+ raise AssertionError(f'实际={actual}, 预期=是数字') from e
94
+
95
+
96
+ class WhatIsEqualToAssertion:
97
+ """等于什么"""
98
+
99
+ @staticmethod
100
+ @sync_method_callback('ass', '等于什么', 0, [
101
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
102
+ def p_is_equal_to(actual: str, expect: str):
103
+ """等于expect"""
104
+ try:
105
+ assert_that(actual).is_equal_to(expect),
106
+ except AssertionError as e:
107
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
108
+
109
+ @staticmethod
110
+ @sync_method_callback('ass', '等于什么', 1, [
111
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
112
+ def p_is_not_equal_to(actual: str, expect: str):
113
+ """不等于expect"""
114
+ try:
115
+ assert_that(actual).is_not_equal_to(expect)
116
+ except AssertionError as e:
117
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
118
+
119
+ @staticmethod
120
+ @sync_method_callback('ass', '等于什么', 2, [
121
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
122
+ def p_is_length(actual: str, expect: str):
123
+ """长度等于expect"""
124
+ try:
125
+ assert_that(actual).is_length(int(expect))
126
+ except AssertionError as e:
127
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
128
+
129
+ @staticmethod
130
+ @sync_method_callback('ass', '等于什么', 3, [
131
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
132
+ def p_sum_equal_expect(actual: list, expect: str):
133
+ """长度等于expect"""
134
+ try:
135
+ assert_that(sum(actual)).is_equal_to(expect)
136
+ except AssertionError as e:
137
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
138
+
139
+
140
+ class ContainAssertion:
141
+ """包含什么"""
142
+
143
+ @staticmethod
144
+ @sync_method_callback('ass', '包含什么', 0, [
145
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
146
+ def p_contains(actual: str, expect: str):
147
+ """包含expect"""
148
+ try:
149
+ assert_that(actual).contains(expect)
150
+ except AssertionError as e:
151
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
152
+
153
+ @staticmethod
154
+ @sync_method_callback('ass', '包含什么', 1, [
155
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
156
+ def p_is_equal_to_ignoring_case(actual: str, expect: str):
157
+ """忽略大小写等于expect"""
158
+ try:
159
+ assert_that(actual).is_equal_to_ignoring_case(expect)
160
+ except AssertionError as e:
161
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
162
+
163
+ @staticmethod
164
+ @sync_method_callback('ass', '包含什么', 2, [
165
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
166
+ def p_contains_ignoring_case(actual: str, expect: str):
167
+ """包含忽略大小写expect"""
168
+ try:
169
+ assert_that(actual).contains_ignoring_case(expect)
170
+ except AssertionError as e:
171
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
172
+
173
+ @staticmethod
174
+ @sync_method_callback('ass', '包含什么', 3, [
175
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
176
+ def p_contains_only(actual: str, expect: str):
177
+ """仅包含expect"""
178
+ try:
179
+ assert_that(actual).contains_only(expect)
180
+ except AssertionError as e:
181
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
182
+
183
+ @staticmethod
184
+ @sync_method_callback('ass', '包含什么', 4, [
185
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
186
+ def p_does_not_contain(actual: str, expect: str):
187
+ """不包含expect"""
188
+ try:
189
+ assert_that(actual).does_not_contain(expect)
190
+ except AssertionError as e:
191
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
192
+
193
+
194
+ class MatchingAssertion:
195
+ """匹配什么"""
196
+
197
+ @staticmethod
198
+ @sync_method_callback('ass', '匹配什么', 0, [
199
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
200
+ def p_in_dict(actual: dict, expect: dict):
201
+ """JSON匹配"""
202
+ filtered_actual = filter_dict(dict(actual), dict(expect))
203
+ diff = DeepDiff(filtered_actual, expect, ignore_order=True)
204
+ assert not diff, f'实际={actual}, 预期={expect}'
205
+
206
+ @staticmethod
207
+ @sync_method_callback('ass', '匹配什么', 1, [
208
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
209
+ def p_is_in(actual: str, expect: str):
210
+ """在expect里面"""
211
+ try:
212
+ assert_that(actual).is_in(expect)
213
+ except AssertionError as e:
214
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
215
+
216
+ @staticmethod
217
+ @sync_method_callback('ass', '匹配什么', 2, [
218
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
219
+ def p_is_not_in(actual: str, expect: str):
220
+ """不在expect里面"""
221
+ try:
222
+ assert_that(actual).is_not_in(expect)
223
+ except AssertionError as e:
224
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
225
+
226
+ @staticmethod
227
+ @sync_method_callback('ass', '匹配什么', 3, [
228
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
229
+ def p_starts_with(actual: str, expect: str):
230
+ """以expect开头"""
231
+ try:
232
+ assert_that(actual).starts_with(expect)
233
+ except AssertionError as e:
234
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
235
+
236
+ @staticmethod
237
+ @sync_method_callback('ass', '匹配什么', 4, [
238
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
239
+ def p_ends_with(actual: str, expect: str):
240
+ """以expect结尾"""
241
+ try:
242
+ assert_that(actual).ends_with(expect)
243
+ except AssertionError as e:
244
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
245
+
246
+ @staticmethod
247
+ @sync_method_callback('ass', '匹配什么', 5, [
248
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
249
+ def p_matches(actual: str, expect: str):
250
+ """正则匹配等于expect"""
251
+ try:
252
+ assert_that(actual).matches(expect)
253
+ except AssertionError as e:
254
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
255
+
256
+ @staticmethod
257
+ @sync_method_callback('ass', '匹配什么', 6, [
258
+ MethodModel(f='actual', d=True), MethodModel(f='expect', p='请输入断言值', d=True)])
259
+ def p_does_not_match(actual: str, expect: str):
260
+ """正则不匹配expect"""
261
+ try:
262
+ assert_that(actual).does_not_match(expect)
263
+ except AssertionError as e:
264
+ raise AssertionError(f'实际={actual}, 预期={expect}') from e
265
+
266
+
267
+ def filter_dict(actual: dict, expect: dict) -> dict:
268
+ filtered = {}
269
+ for key in expect.keys():
270
+ if key in actual:
271
+ if isinstance(expect[key], dict):
272
+ filtered[key] = filter_dict(actual[key], expect[key])
273
+ elif isinstance(expect[key], list) and isinstance(actual[key], list):
274
+ filtered[key] = []
275
+ for item in actual[key]:
276
+ if isinstance(item, dict):
277
+ filtered_item = filter_dict(item, expect[key][0])
278
+ filtered[key].append(filtered_item)
279
+ else:
280
+ filtered[key].append(item)
281
+ else:
282
+ filtered[key] = actual[key]
283
+ return filtered
284
+
285
+
286
+ class PublicAssertion(WhatIsItAssertion, ContainAssertion, MatchingAssertion, WhatIsEqualToAssertion):
287
+ pass
288
+
289
+
290
+ if __name__ == '__main__':
291
+ PublicAssertion.p_is_equal_to('1', '2')
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description:
4
+ # @Time : 2023-11-20 9:47
5
+ # @Author : 毛鹏
6
+
7
+ from mangokit.database import MysqlConnect
8
+ from mangokit.decorator import sync_method_callback
9
+ from mangokit.models import MethodModel
10
+
11
+
12
+ class SqlAssertion:
13
+ """sql断言"""
14
+ mysql_connect: MysqlConnect = None
15
+
16
+ @staticmethod
17
+ @sync_method_callback('ass', 'sql断言', 0, [
18
+ MethodModel(f='sql', p='请输入sql语句,确保只会查出一个值', d=True),
19
+ MethodModel(f='expect', p='期望的json', d=True), ])
20
+ async def sql_is_equal(sql: str, expect: list[dict]):
21
+ """值相等"""
22
+ result = SqlAssertion.mysql_connect.condition_execute(sql)
23
+ assert all(dict2 in result for dict2 in expect), f'实际={result}, 预期=列表个数相等'
24
+
25
+
26
+ if __name__ == '__main__':
27
+ _sql = "SELECT id,`name`,`status` FROM `project`;"
28
+ _expect = [{'id': 2, 'name': '1CDXP', 'status': 1}, {'id': 5, 'name': 'AIGC', 'status': 1},
29
+ {'id': 10, 'name': 'DESK', 'status': 1}, {'id': 11, 'name': 'AIGC-SaaS', 'status': 1}]
@@ -0,0 +1,123 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description:
4
+ # @Time : 2023-03-07 8:24
5
+ # @Author : 毛鹏
6
+ import json
7
+ import re
8
+
9
+ import sys
10
+
11
+ from ..data_processor._cache_tool import CacheTool
12
+ from ..data_processor._coding_tool import CodingTool
13
+ from ..data_processor._encryption_tool import EncryptionTool
14
+ from ..data_processor._json_tool import JsonTool
15
+ from ..data_processor._random_character_info_data import RandomCharacterInfoData
16
+ from ..data_processor._random_number_data import RandomNumberData
17
+ from ..data_processor._random_string_data import RandomStringData
18
+ from ..data_processor._random_time_data import RandomTimeData
19
+ from ..data_processor._sql_cache import SqlCache
20
+ from ..exceptions import ERROR_MSG_0002, ERROR_MSG_0047, MangoKitError
21
+
22
+ """
23
+ ObtainRandomData类的函数注释必须是: “”“中间写值”“”
24
+ """
25
+
26
+ python_version = sys.version_info
27
+ if f"{python_version.major}.{python_version.minor}" != "3.10":
28
+ raise Exception("必须使用>Python3.10.4")
29
+
30
+
31
+ class ObtainRandomData(RandomNumberData, RandomCharacterInfoData, RandomTimeData, RandomStringData):
32
+ """ 获取随机数据 """
33
+
34
+ def regular(self, func: str):
35
+ """
36
+ 反射并执行函数
37
+ :param func: 函数
38
+ :return:
39
+ """
40
+ match = re.search(r'\((.*?)\)', func)
41
+ if match:
42
+ try:
43
+ content = json.loads(match.group(1))
44
+ if not isinstance(content, dict):
45
+ content = {'data': match.group(1)}
46
+ except json.decoder.JSONDecodeError:
47
+ content = {'data': match.group(1)}
48
+
49
+ func = re.sub(r'\(' + match.group(1) + r'\)', '', func)
50
+ try:
51
+ if content['data'] != '':
52
+ return getattr(self, func)(**content)
53
+ return getattr(self, func)()
54
+ except AttributeError:
55
+ raise MangoKitError(*ERROR_MSG_0047)
56
+
57
+
58
+ class DataClean(JsonTool, CacheTool, EncryptionTool, CodingTool):
59
+ """存储或处理随机数据"""
60
+ pass
61
+
62
+
63
+ class DataProcessor(ObtainRandomData, DataClean):
64
+
65
+ def __init__(self):
66
+ ObtainRandomData.__init__(self)
67
+ DataClean.__init__(self)
68
+
69
+ def replace(self, data: list | dict | str | None) -> list | dict | str | None:
70
+ if not data:
71
+ return data
72
+ if isinstance(data, list):
73
+ return [self.replace(item) for item in data]
74
+ elif isinstance(data, dict):
75
+ return {key: self.replace(value) for key, value in data.items()}
76
+ else:
77
+ return self.replace_str(data)
78
+
79
+ def replace_str(self, data: str) -> str:
80
+ replace_list = re.findall(r"\${{.*?}}", str(data))
81
+ for replace_value in replace_list:
82
+ key_text = self.remove_parentheses(replace_value)
83
+ args = key_text.split(",")
84
+ key_text, key = (args[0], args[1]) if len(args) == 2 else (args[0], None)
85
+ if key and (key_value := self.get_cache(key)):
86
+ return key_value
87
+
88
+ value = self.regular(key_text) if self.identify_parentheses(key_text) else self.get_cache(key_text)
89
+ if value is None:
90
+ raise MangoKitError(*ERROR_MSG_0002, value=(key_text,))
91
+
92
+ if key:
93
+ self.set_cache(key, value)
94
+ data = data.replace(replace_value, str(value))
95
+ return data
96
+
97
+ @classmethod
98
+ def remove_parentheses(cls, data: str) -> str:
99
+ return data.replace("${{", "").replace("}}", "").strip()
100
+
101
+ @classmethod
102
+ def identify_parentheses(cls, value: str):
103
+ return re.search(r'\((.*?)\)', str(value))
104
+
105
+ @classmethod
106
+ def is_extract(cls, string: str) -> bool:
107
+ return bool(re.search(r'\$\{\{.*\}\}', string))
108
+
109
+
110
+ __all__ = [
111
+ 'CacheTool',
112
+ 'CodingTool',
113
+ 'EncryptionTool',
114
+ 'JsonTool',
115
+ 'RandomCharacterInfoData',
116
+ 'RandomNumberData',
117
+ 'RandomStringData',
118
+ 'RandomTimeData',
119
+ 'ObtainRandomData',
120
+ 'DataClean',
121
+ 'DataProcessor',
122
+ 'SqlCache'
123
+ ]
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台# @Description:
3
+ # @Time : 2023-08-29 10:23
4
+ # @Author : 毛鹏
5
+
6
+ from cachetools import LRUCache
7
+
8
+
9
+ class CacheTool:
10
+ """ 内存缓存 """
11
+
12
+ def __init__(self):
13
+ self._cache: LRUCache = LRUCache(maxsize=500)
14
+
15
+ def get_cache(self, key: str) -> any:
16
+ """得到缓存key的value"""
17
+ return self._cache.get(key)
18
+
19
+ def set_cache(self, key: str, value: any) -> None:
20
+ """设置一个内容到缓存"""
21
+ self._cache[key] = value
22
+
23
+ def delete_cache(self, key: str) -> None:
24
+ """删除一个缓存"""
25
+ if key in self._cache:
26
+ del self._cache[key]
27
+
28
+ def clear_cache(self) -> None:
29
+ """清理所有缓存"""
30
+ self._cache.clear()
31
+
32
+ def has_cache(self, key: str) -> bool:
33
+ """判断缓存是否存在"""
34
+ return key in self._cache
35
+
36
+ def get_all(self, ) -> dict:
37
+ """获取全部的缓存数据"""
38
+ return {k: v for k, v in self._cache.items()}
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description:
4
+ # @Time : 2023-08-30 14:14
5
+ # @Author : 毛鹏
6
+ import base64
7
+ import json
8
+
9
+
10
+ class CodingTool:
11
+ """编码"""
12
+
13
+ @classmethod
14
+ def base64_encode(cls, data: str) -> str:
15
+ """编码字符串"""
16
+ return base64.b64encode(json.dumps(data).encode('utf-8')).decode('utf-8')
17
+
18
+ @classmethod
19
+ def response_decoding(cls, data) -> str:
20
+ """解码字符串"""
21
+ return data.encode('latin-1').decode('unicode_escape').encode('utf-8', 'ignore').decode('utf-8')