smartpush 1.1.1__tar.gz → 1.1.4__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.
@@ -1,5 +1,5 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: smartpush
3
- Version: 1.1.1
3
+ Version: 1.1.4
4
4
  Summary: 用于smartpush自动化测试工具包
5
5
  Author: 卢泽彬、邵宇飞、周彦龙
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='smartpush',
5
- version='1.1.1',
5
+ version='1.1.4',
6
6
  description='用于smartpush自动化测试工具包',
7
7
  author='卢泽彬、邵宇飞、周彦龙',
8
8
  packages=find_packages(),
@@ -0,0 +1,259 @@
1
+ import copy
2
+ import json
3
+ from urllib.parse import unquote
4
+
5
+ from smartpush.export.basic.ReadExcel import *
6
+
7
+ """
8
+ 用于excel校验
9
+ """
10
+ warnings.simplefilter("ignore")
11
+
12
+
13
+ def check_excel(check_type="content", **kwargs):
14
+ """对比excel
15
+ :param: type: 需要对比类型,
16
+ 枚举:content:对比两表格内容
17
+ 方式1:传参actual_oss和expected_oss,参数类型str,url
18
+ 放松1:传参actual和expected,参数类型list or dict
19
+ excelName: 对比两表格文件名称
20
+ all: 对比所有内容
21
+ """
22
+ try:
23
+ if check_type == "content":
24
+ if "actual" in kwargs.keys() and "expected" in kwargs.keys():
25
+ return check_excel_content(actual=kwargs["actual"], expected=kwargs["expected"])
26
+ else:
27
+ return check_excel_content(
28
+ actual=read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["actual_oss"]),
29
+ **kwargs),
30
+ expected=read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["expected_oss"]),
31
+ **kwargs)
32
+ )
33
+ elif check_type == "excelName":
34
+ return check_excel_name(actual_oss=kwargs["actual_oss"], expected_oss=kwargs["expected_oss"])
35
+ elif check_type == "all":
36
+ actual_content = read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["actual_oss"]),
37
+ **kwargs)
38
+ expected_content = read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["expected_oss"]),
39
+ **kwargs)
40
+ flag1, content_result = check_excel_content(actual=actual_content, expected=expected_content)
41
+ flag2, name_result = check_excel_name(actual_oss=kwargs["actual_oss"], expected_oss=kwargs["expected_oss"])
42
+ flag3, header_result = check_excel_header(actual=actual_content, expected=expected_content, **kwargs)
43
+ return all([flag1, flag2, flag3]), {"文件名称": name_result, "导出内容": content_result, "表头比较:": header_result}
44
+ else:
45
+ return False, f"不支持此类型: {check_type}"
46
+ except Exception as e:
47
+ print(f"对比excel异常:{e}")
48
+ return False, [e]
49
+
50
+
51
+ # # 定义比较类型和对应处理函数的映射
52
+ # comparison_functions = {
53
+ # # 内容
54
+ # "content": lambda kwargs: check_excel_content(kwargs["actual"], kwargs["expected"]),
55
+ # # excelName
56
+ # "excelName": lambda kwargs: check_excel_name(kwargs["actual_oss"], kwargs["expected_oss"]),
57
+ # 'header': lambda kwargs: check_excel_header(kwargs["actual"], kwargs["expected"]),
58
+ # # 全部
59
+ # "all": lambda kwargs: check_excel_all(kwargs["actual_oss"], kwargs["expected_oss"])
60
+ # }
61
+ #
62
+ #
63
+ # def check_excel_for_lu(check_type="content", **kwargs):
64
+ # """对比excel
65
+ # :param: type: 需要对比类型,
66
+ # 枚举:
67
+ # content:对比两表格内容
68
+ # 方式1:传参actual_oss和expected_oss,参数类型str,url
69
+ # 放松1:传参actual和expected,参数类型list or dict
70
+ # excelName: 对比两表格文件名称,传oss链接
71
+ # all: 对比所有内容,传oss链接
72
+ # """
73
+ # try:
74
+ # # 根据 check_type 获取对应的处理函数
75
+ # compare_func = comparison_functions.get(check_type)
76
+ # if compare_func:
77
+ # return compare_func(kwargs)
78
+ # else:
79
+ # return False, f"不支持此类型: {check_type}"
80
+ # except KeyError as ke:
81
+ # # raise ke
82
+ # print(f"类型对应参数缺失异常:{ke}")
83
+ # return False, [str(ke)]
84
+ # except Exception as e:
85
+ # print(f"对比 Excel 异常:{e}")
86
+ # return False, [str(e)]
87
+
88
+
89
+ def check_excel_content_form_dict(actual, expected, **kwargs):
90
+ """
91
+ 通过 OSS URL 比较 Excel 内容,支持多sheet并且包含表头
92
+ """
93
+ actual, expected = read_excel_and_write_to_dict(actual, **kwargs), read_excel_and_write_to_dict(
94
+ expected, **kwargs)
95
+ return check_excel_content(actual, expected)
96
+
97
+
98
+ def check_excel_content_form_list(actual, expected):
99
+ """
100
+ 通过 内容 比较 Excel 内容,不包含表头
101
+ """
102
+ expected, actual = read_excel_and_write_to_list(actual), read_excel_and_write_to_list(expected)
103
+ return check_excel_content(actual=actual, expected=expected)
104
+
105
+
106
+ def check_excel_all(actual_oss, expected_oss):
107
+ """
108
+ 校验所有内容
109
+ """
110
+ file_type = check_and_get_file_suffix_name(expected_oss, actual_oss)
111
+ actual, expected = read_excel_from_oss(actual_oss), read_excel_from_oss(expected_oss)
112
+ actual_data_copy = copy.deepcopy(actual)
113
+ expected_data_copy = copy.deepcopy(expected)
114
+ flag1, content_result = check_excel_content_form_dict(actual, expected, type=file_type)
115
+ flag2, name_result = check_excel_name(actual_oss, expected_oss)
116
+ flag3, header_result = check_excel_header(actual_data_copy,expected_data_copy, type=file_type)
117
+ return all([flag1, flag2]), json.dumps({f"文件名称-{flag1}": name_result, f"导出内容-{flag2}": content_result,f"表头校验-{flag3}": header_result},
118
+ ensure_ascii=False)
119
+
120
+
121
+ def check_and_get_file_suffix_name(actual_oss, expected_oss) -> str:
122
+ """
123
+ 校验并获取oss的后缀类型
124
+ @param actual_oss:
125
+ @param expected_oss:
126
+ @return:
127
+ """
128
+ actual_file_suffix_name = get_file_suffix_name(actual_oss)
129
+ expected_file_suffix_name = get_file_suffix_name(expected_oss)
130
+ try:
131
+ assert actual_file_suffix_name == expected_file_suffix_name
132
+ return actual_file_suffix_name
133
+ except Exception:
134
+ raise Exception("oss文件类型不一致,请检查oss链接是否为相同类型")
135
+
136
+
137
+ def check_excel_name(actual_oss, expected_oss):
138
+ """校验excel文件名称
139
+ :param actual_oss:实际oss链接
140
+ :param actual_oss:预期oss链接
141
+ """
142
+ try:
143
+ actual_name = unquote(actual_oss.split("/")[-1])
144
+ expected_name = unquote(expected_oss.split("/")[-1])
145
+ if actual_name == expected_name:
146
+ return True, "excel文件名称-完成匹配"
147
+ else:
148
+ return False, f"excel文件名称-不匹配, 实际: {actual_name}, 预期: {expected_name}"
149
+ except BaseException as msg:
150
+ return False, f"excel文件名称-服务异常: {msg}"
151
+
152
+
153
+ def check_excel_content(actual, expected):
154
+ """校验excel内容
155
+ :param actual: 实际内容,list或dict类型
156
+ :param expected:预期内容:list或dict类型
157
+ """
158
+ try:
159
+ if actual == expected:
160
+ return True, ["excel内容-完全匹配"]
161
+ else:
162
+ errors = []
163
+ # 断言1:校验行数
164
+ actual_num = len(actual)
165
+ expected_num = len(expected)
166
+ check_row = actual_num - expected_num
167
+ if check_row == 0:
168
+ errors.append("excel内容-预期和实际行数相等,为" + str(actual_num) + "行")
169
+ else:
170
+ errors.append(
171
+ "excel内容-行数和预期对比差" + check_row.__str__() + "行" + ", 实际:" + str(
172
+ actual_num) + "预期: " + str(
173
+ expected_num))
174
+ # 断言不匹配行
175
+ if check_row >= 0:
176
+ num = len(expected)
177
+ else:
178
+ num = len(actual)
179
+ if isinstance(actual, list) and isinstance(expected, list):
180
+ for i in range(num):
181
+ if actual[i] == expected[i]:
182
+ continue
183
+ else:
184
+ errors.append(
185
+ "excel内容-第" + str(i + 1) + "行不匹配,预期为:" + str(expected[i]) + ", 实际为: " + str(
186
+ actual[i]))
187
+ return False, errors
188
+ else:
189
+ return False, compare_dicts(actual, expected)
190
+ except Exception as e:
191
+ print(f":excel内容-服务异常{e}")
192
+ return False, [e]
193
+
194
+
195
+ def check_excel_header(actual, expected, **kwargs):
196
+ """
197
+ 比较两个文档第一列的header是否一致
198
+ @param actual:
199
+ @param expected:
200
+ @return:
201
+ @return:
202
+ """
203
+ try:
204
+ if all([isinstance(actual, str), isinstance(expected, str)]):
205
+ actual1, expected1 = read_excel_header(read_excel_from_oss(actual), **kwargs), read_excel_header(
206
+ read_excel_from_oss(
207
+ expected), **kwargs)
208
+ else:
209
+ actual1, expected1 = read_excel_header(actual, **kwargs), read_excel_header(expected, **kwargs)
210
+ try:
211
+ assert actual1 == expected1
212
+ return True, "表头校验值与顺序一致"
213
+ except Exception as e:
214
+ return False, f"表头校验值与顺序失败 {e}"
215
+ except Exception as e:
216
+ return False, f"表头校验异常 {e}"
217
+
218
+
219
+ def del_temp_file(file_name=""):
220
+ """删除temp下临时文件"""
221
+ file_path = os.path.join(os.path.dirname(os.getcwd()) + "/temp_file/" + file_name)
222
+ try:
223
+ os.remove(file_path)
224
+ print(f"文件 {file_path} 已成功删除。")
225
+ except FileNotFoundError:
226
+ print(f"文件 {file_path} 不存在。")
227
+ except Exception as e:
228
+ print(f"删除文件 {file_path} 时出错:{e}")
229
+
230
+
231
+ def compare_dicts(dict1, dict2):
232
+ diff = {}
233
+ # 找出只在 dict1 中存在的键
234
+ only_in_dict1 = set(dict1.keys()) - set(dict2.keys())
235
+ if only_in_dict1:
236
+ diff['only_in_dict1'] = {key: dict1[key] for key in only_in_dict1}
237
+ # 找出只在 dict2 中存在的键
238
+ only_in_dict2 = set(dict2.keys()) - set(dict1.keys())
239
+ if only_in_dict2:
240
+ diff['only_in_dict2'] = {key: dict2[key] for key in only_in_dict2}
241
+ # 处理两个字典都有的键
242
+ common_keys = set(dict1.keys()) & set(dict2.keys())
243
+ for key in common_keys:
244
+ value1 = dict1[key]
245
+ value2 = dict2[key]
246
+ if isinstance(value1, dict) and isinstance(value2, dict):
247
+ # 如果值是字典,递归比较
248
+ sub_diff = compare_dicts(value1, value2)
249
+ if sub_diff:
250
+ diff[f'different_sub_dicts_at_{key}'] = sub_diff
251
+ elif isinstance(value1, list) and isinstance(value2, list):
252
+ # 如果值是列表,比较列表元素
253
+ if value1 != value2:
254
+ diff[f'different_lists_at_{key}'] = (value1, value2)
255
+ else:
256
+ # 其他情况,直接比较值
257
+ if value1 != value2:
258
+ diff[f'different_values_at_{key}'] = (value1, value2)
259
+ return diff
@@ -0,0 +1,98 @@
1
+ # from retry import retry
2
+ import json
3
+
4
+ import requests
5
+ import tenacity
6
+ from tenacity import retry, stop_after_attempt, wait_fixed
7
+
8
+ from smartpush.utils.StringUtils import StringUtils
9
+
10
+
11
+ # 用于技术第几次重试,无需修改
12
+ def log_attempt(retry_state):
13
+ """
14
+ 回调函数,在每次重试时记录并打印重试次数
15
+ """
16
+ attempt_number = retry_state.attempt_number
17
+ print(f"当前重试次数: {attempt_number}")
18
+
19
+
20
+ def get_oss_address_with_retry(target_id, url, requestHeader, requestParam, **kwargs) -> str:
21
+ """
22
+ 创建带有动态重试配置的获取 OSS 地址
23
+ **kwargs 可传参:tries=10, delay=2, backoff=1
24
+ :param requestParam:
25
+ :param url:
26
+ :param target_id:
27
+ :param requestHeader:
28
+ :return: 带有重试配置的获取 OSS 地址的
29
+ """
30
+ tries = kwargs.get('tries', 10) # 重试次数
31
+ delay = kwargs.get('delay', 2)
32
+
33
+
34
+ @retry(stop=stop_after_attempt(tries), wait=wait_fixed(delay), after=log_attempt)
35
+ def get_oss_address():
36
+ _url = url + '/bulkOps/query'
37
+ result = None
38
+ if StringUtils.is_empty(target_id):
39
+ print(f"缺少参数:target_id")
40
+ return
41
+ try:
42
+ response = requests.request(url=_url, headers=requestHeader, data=json.dumps(requestParam),
43
+ method="post")
44
+ response.raise_for_status()
45
+ result = response.json()
46
+ id_url_dict = {item["id"]: item["url"] for item in result["resultData"]["datas"]}
47
+ if target_id in id_url_dict:
48
+ if len(id_url_dict[target_id]) == 1:
49
+ print(f"{target_id} oss链接为:{id_url_dict[target_id][0]}")
50
+ return id_url_dict[target_id][0]
51
+ else:
52
+ raise ValueError(f"存在多条 id 为 {target_id} 的记录,记录为:{id_url_dict[target_id]}")
53
+ else:
54
+ raise ValueError(f"未找到 id 为 {target_id} 的记录,未包含有效的 OSS 地址,")
55
+ except (KeyError, json.JSONDecodeError) as e:
56
+ raise ValueError(f"响应数据格式错误,响应结果: {result},异常: {e}")
57
+ except requests.RequestException as e:
58
+ print(f"请求发生异常: {e},正在重试...")
59
+ raise
60
+
61
+ def cancel_export_file(_target_id):
62
+ """
63
+ 用于失败后取消导出
64
+ :param _target_id:
65
+ :return:
66
+ """
67
+ cancel_url = url + '/bulkOps/cancel'
68
+ response = requests.request(url=cancel_url, headers=requestHeader, params={'id': _target_id}, method="get")
69
+ response.raise_for_status()
70
+ result = response.json()
71
+ print(f"获取Oss Url失败,取消 {_target_id} 的导出记录,响应:{result}")
72
+ return result
73
+
74
+ try:
75
+ return get_oss_address()
76
+ except Exception as e:
77
+ # print(f"最终失败,错误信息: {e}")
78
+ if isinstance(e, tenacity.RetryError):
79
+ cancel_export_file(target_id)
80
+ return None
81
+
82
+
83
+ if __name__ == '__main__':
84
+ url = "https://test.smartpushedm.com/api-em-ec2"
85
+ requestHeader = {
86
+ "cookie": "osudb_appid=SMARTPUSH;osudb_oar=#01#SID0000122BBLon+0gwvStide+qtdJAK57ZSK1ty+iW8b7tv/Uwl6Zo4gDfUg6B83n+jgqTVjoZ5qRGyRsuLaXc9woDN2WRh3mu1yn7anglBmaFoemhCy/ttS8nqv/y0kj8khbu6mtBmQrseNfnO/Mir8PQP+S;osudb_subappid=1;osudb_uid=4213785247;ecom_http_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDI1Mjk2NTQsImp0aSI6ImM2MTA4MGJkLTU4MGUtNDJiNi05NzU5LTU0ZTNmZDExZDA4OSIsInVzZXJJbmZvIjp7ImlkIjowLCJ1c2VySWQiOiI0MjEzNzg1MjQ3IiwidXNlcm5hbWUiOiIiLCJlbWFpbCI6ImZlbGl4LnNoYW9Ac2hvcGxpbmVhcHAuY29tIiwidXNlclJvbGUiOiJvd25lciIsInBsYXRmb3JtVHlwZSI6Nywic3ViUGxhdGZvcm0iOjEsInBob25lIjoiIiwibGFuZ3VhZ2UiOiJ6aC1oYW5zLWNuIiwiYXV0aFR5cGUiOiIiLCJhdHRyaWJ1dGVzIjp7ImNvdW50cnlDb2RlIjoiQ04iLCJjdXJyZW5jeSI6IkpQWSIsImN1cnJlbmN5U3ltYm9sIjoiSlDCpSIsImRvbWFpbiI6InNtYXJ0cHVzaDQubXlzaG9wbGluZXN0Zy5jb20iLCJsYW5ndWFnZSI6ImVuIiwibWVyY2hhbnRFbWFpbCI6ImZlbGl4LnNoYW9Ac2hvcGxpbmUuY29tIiwibWVyY2hhbnROYW1lIjoiU21hcnRQdXNoNF9lYzJf6Ieq5Yqo5YyW5bqX6ZO6IiwicGhvbmUiOiIiLCJzY29wZUNoYW5nZWQiOmZhbHNlLCJzdGFmZkxhbmd1YWdlIjoiemgtaGFucy1jbiIsInN0YXR1cyI6MCwidGltZXpvbmUiOiJBc2lhL01hY2FvIn0sInN0b3JlSWQiOiIxNjQ0Mzk1OTIwNDQ0IiwiaGFuZGxlIjoic21hcnRwdXNoNCIsImVudiI6IkNOIiwic3RlIjoiIiwidmVyaWZ5IjoiIn0sImxvZ2luVGltZSI6MTczOTkzNzY1NDc2Mywic2NvcGUiOlsiZW1haWwtbWFya2V0IiwiY29va2llIiwic2wtZWNvbS1lbWFpbC1tYXJrZXQtbmV3LXRlc3QiLCJlbWFpbC1tYXJrZXQtbmV3LWRldi1mcyIsImFwaS11Yy1lYzIiLCJhcGktc3UtZWMyIiwiYXBpLWVtLWVjMiIsImZsb3ctcGx1Z2luIl0sImNsaWVudF9pZCI6ImVtYWlsLW1hcmtldCJ9.X2Birt-jiWILAvEjjwknUchil2ys8Y11omeRYgZ3K0I;",
87
+ "Content-Type": "application/json"
88
+ }
89
+ requestParam = {
90
+ "page": 1,
91
+ "pageSize": 20,
92
+ "type": "EXPORT",
93
+ "status": None,
94
+ "startTime": 1740033265288,
95
+ "endTime": 1740044065288
96
+ }
97
+ id = "2334659"
98
+ get_oss_address_with_retry(2334659, url, requestHeader, requestParam)
@@ -0,0 +1,139 @@
1
+ import io
2
+ import os
3
+ import re
4
+ import warnings
5
+ from io import BytesIO
6
+ import pandas as pd
7
+ from requests import request
8
+
9
+ warnings.simplefilter("ignore")
10
+ excel_extensions = ['.xlsb', '.xlsx', '.xlsm', '.xls', '.xltx', '.xltm', '.xlam', None]
11
+ csv_extensions = ['.csv']
12
+
13
+
14
+ def read_excel_from_oss(url="", method="get"):
15
+ """读取oss的excel内容转为io流数据"""
16
+ try:
17
+ result = request(method=method, url=url)
18
+ excel_data = BytesIO(result.content)
19
+ print(f"成功读取oss文件内容: {url}")
20
+ return excel_data
21
+ except Exception as e:
22
+ print(f"读取oss报错 {url} 时出错:{e}")
23
+
24
+
25
+ def read_excel_header(excel_data, **kwargs) -> list:
26
+ """
27
+ 1、读出excel的头列 list
28
+ """
29
+ try:
30
+ dfs = read_excel_csv_data(excel_data,**kwargs)
31
+ result = []
32
+ if kwargs['type'] in excel_extensions:
33
+ for sheet_name, df in dfs.items():
34
+ result.append(df.keys().values.tolist())
35
+ else:
36
+ result = dfs.keys().values.tolist()
37
+ return result
38
+ except Exception as e:
39
+ print(f"excel生成header-list出错:{e}")
40
+ raise
41
+
42
+
43
+ def read_excel_csv_data(excel_data, **kwargs):
44
+ with warnings.catch_warnings():
45
+ warnings.filterwarnings("ignore", category=UserWarning, module=re.escape('openpyxl.styles.stylesheet'))
46
+ if kwargs['type'] in excel_extensions:
47
+ dfs = pd.read_excel(excel_data, sheet_name=None, na_filter=False) if isinstance(excel_data,
48
+ io.BytesIO) \
49
+ else excel_data
50
+ else:
51
+ dfs = pd.read_csv(excel_data, na_filter=False)
52
+ return dfs
53
+
54
+
55
+ def read_excel_and_write_to_dict(excel_data=None, file_name=None, **kwargs):
56
+ """excel内容并写入到内存dict中
57
+ :param excel_data:excel的io对象, 参数和file_name互斥
58
+ :file_name: excel文件名称,目前读取check_file目录下文件,参数和excel_data互斥
59
+ """
60
+ try:
61
+ if excel_data is not None and file_name is not None:
62
+ pass
63
+ elif file_name is not None:
64
+ excel_data = os.path.join(os.path.dirname(os.getcwd()) + "/check_file/" + file_name)
65
+ dfs = read_excel_csv_data(excel_data, **kwargs)
66
+ if kwargs['type'] in excel_extensions:
67
+ # 将DataFrame转换为字典,以行为单位存储数据
68
+ row_dict = {} # 创建一个空字典来存储按行转换的数据
69
+ for sheet_name, row in dfs.items():
70
+ row_dict[sheet_name] = row.to_dict(orient='records')
71
+ else:
72
+ row_dict = dfs.to_dict()
73
+ return row_dict
74
+ except Exception as e:
75
+ print(f"excel写入dict时出错:{e}")
76
+
77
+
78
+ def read_excel_and_write_to_list(excel_data=None, sheet_name=None, file_name=None, **kwargs):
79
+ """excel内容并写入到内存list中
80
+ :param excel_data:excel的io对象, 参数和file_name互斥
81
+ :file_name: excel文件名称,目前读取check_file目录下文件,参数和excel_data互斥
82
+ """
83
+ try:
84
+ if excel_data is not None and file_name is not None:
85
+ pass
86
+ elif file_name is not None:
87
+ excel_data = os.path.join(os.path.dirname(os.getcwd()) + "/check_file/" + file_name)
88
+ dfs = read_excel_csv_data(excel_data, **kwargs)
89
+ rows_list = []
90
+ # 多sheet处理
91
+ for name, df in dfs.items():
92
+ rows_list.append(df.values.tolist())
93
+ if len(dfs) <= 1:
94
+ rows_list = rows_list[0]
95
+ return rows_list
96
+ except Exception as e:
97
+ print(f"excel写入list时出错:{e}")
98
+
99
+
100
+ def read_excel_and_write_to_csv(excel_data, file_name, **kwargs):
101
+ """excel内容并写入到csv中"""
102
+ try:
103
+ df = pd.read_excel(excel_data, engine="openpyxl")
104
+ local_csv_path = os.path.join(os.path.dirname(os.getcwd()) + "/temp_file/" + file_name)
105
+ df.to_csv(local_csv_path, index=False, **kwargs)
106
+ return local_csv_path
107
+ except Exception as e:
108
+ print(f"excel写入csv时出错:{e}")
109
+
110
+
111
+ def read_excel_data_for_oss_write_to_dict(oss, **kwargs) -> dict:
112
+ """
113
+ 1、根据oss link 直接读出 dict-list
114
+ 2、支持多sheet,默认sheet_name =None查全部
115
+ 3、返回dict结构 {'sheet_name':[rows_list]}
116
+ """
117
+ try:
118
+ dfs = read_excel_csv_data(read_excel_from_oss(oss), **kwargs)
119
+ result = {}
120
+ for sheet_name, df in dfs.items():
121
+ rows_list = df.values.tolist()
122
+ result[sheet_name] = rows_list
123
+ return result
124
+ except Exception as e:
125
+ print(f"excel生成dict出错:{e}")
126
+
127
+
128
+ # 从 URL 中提取文件名
129
+ def get_file_suffix_name(url):
130
+ last_filename = ""
131
+ filename = url.split("/")[-1]
132
+ # 从文件名中提取文件后缀
133
+ if '.' in filename:
134
+ last_filename = '.' + filename.split('.')[-1].lower()
135
+ support_types = excel_extensions + csv_extensions
136
+ if last_filename in support_types:
137
+ return last_filename
138
+ else:
139
+ raise Exception(f"[{last_filename}] 该类型暂不支持!目前只支持 {support_types}")
@@ -0,0 +1,19 @@
1
+ # -*- codeing = utf-8 -*-
2
+ # @Time :2025/2/20 00:27
3
+ # @Author :luzebin
4
+ from smartpush.export.basic.ExcelExportChecker import check_excel_all
5
+ from smartpush.export.basic.ReadExcel import read_excel_from_oss
6
+ from smartpush.export.basic.ReadExcel import read_excel_and_write_to_dict
7
+ from smartpush.export.basic.GetOssUrl import get_oss_address_with_retry
8
+
9
+ if __name__ == '__main__':
10
+ oss1 = "https://cdn.smartpushedm.com/material_ec2/2025-02-19/4d98418295524ab1b52340c2ed2afa4a/AutoTest-%E5%9B%BA%E5%AE%9AB-2025-02-14%20%E5%88%9B%E5%BB%BA%E7%9A%84Email33%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx"
11
+ # oss2 = "https://cdn.smartpushedm.com/material_ec2/2025-02-19/ddbe9965d83840199e678a66dc414518/%E8%90%A5%E9%94%80%E4%BB%BB%E5%8A%A1%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx"
12
+ print(check_excel_all(oss1, oss1))
13
+
14
+ # expected_oss ="https://cdn.smartpushedm.com/material_ec2_prod/2025-02-20/dae941ec20964ca5b106407858676f89/%E7%BE%A4%E7%BB%84%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx"
15
+ # actual_oss = "https://cdn.smartpushedm.com/material_ec2_prod/2025-02-20/dae941ec20964ca5b106407858676f89/%E7%BE%A4%E7%BB%84%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx"
16
+ # #actual_oss= get_oss_address_with_retry("23161","https://cdn.smartpushedm.com/material_ec2_prod/2025-02-20/dae941ec20964ca5b106407858676f89/%E7%BE%A4%E7%BB%84%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx","",'{"page":1,"pageSize":10,"type":null,"status":null,"startTime":null,"endTime":null}')
17
+ # res=read_excel_and_write_to_dict(read_excel_from_oss(actual_oss))
18
+ # print(res)
19
+ # print(check_excel_all(actual_oss,expected_oss))
@@ -1,5 +1,5 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: smartpush
3
- Version: 1.1.1
3
+ Version: 1.1.4
4
4
  Summary: 用于smartpush自动化测试工具包
5
5
  Author: 卢泽彬、邵宇飞、周彦龙
@@ -10,6 +10,7 @@ smartpush.egg-info/top_level.txt
10
10
  smartpush/export/__init__.py
11
11
  smartpush/export/basic/ExcelExportChecker.py
12
12
  smartpush/export/basic/GetOssUrl.py
13
+ smartpush/export/basic/ReadExcel.py
13
14
  smartpush/export/basic/__init__.py
14
15
  smartpush/utils/StringUtils.py
15
16
  smartpush/utils/__init__.py
@@ -1,317 +0,0 @@
1
- import os
2
- import re
3
- import warnings
4
- from io import BytesIO
5
- from urllib.parse import unquote
6
- import pandas as pd
7
- from requests import request
8
-
9
- """
10
- 用于excel校验
11
- """
12
- warnings.simplefilter("ignore")
13
-
14
-
15
- def read_excel_from_oss(url="", method="get"):
16
- """读取oss的excel内容并写入到本地csv"""
17
- try:
18
- result = request(method=method, url=url)
19
- excel_data = BytesIO(result.content)
20
- print(f"成功读取oss文件内容: {url}")
21
- return excel_data
22
- except Exception as e:
23
- print(f"读取oss报错 {url} 时出错:{e}")
24
-
25
-
26
- def read_excel_data(excel_data, **kwargs):
27
- with warnings.catch_warnings():
28
- warnings.filterwarnings("ignore", category=UserWarning, module=re.escape('openpyxl.styles.stylesheet'))
29
- dfs = pd.read_excel(excel_data, sheet_name=None, engine="openpyxl", na_filter=False, **kwargs)
30
- return dfs
31
-
32
-
33
- def read_excel_and_write_to_dict(excel_data=None, file_name=None, **kwargs):
34
- """excel内容并写入到内存dict中
35
- :param excel_data:excel的io对象, 参数和file_name互斥
36
- :file_name: excel文件名称,目前读取check_file目录下文件,参数和excel_data互斥
37
- """
38
- try:
39
- if excel_data is not None and file_name is not None:
40
- pass
41
- elif file_name is not None:
42
- excel_data = os.path.join(os.path.dirname(os.getcwd()) + "/check_file/" + file_name)
43
- dfs = read_excel_data(excel_data)
44
- # 将DataFrame转换为字典,以行为单位存储数据
45
- row_dict = {} # 创建一个空字典来存储按行转换的数据
46
- for index, row in dfs.iterrows(): # 遍历DataFrame中的每一行
47
- row_dict[index] = row.to_dict() # 将每一行转换为字典并存储在row_dict中
48
- return row_dict
49
- except Exception as e:
50
- print(f"excel写入dict时出错:{e}")
51
-
52
-
53
- def read_excel_and_write_to_list(excel_data=None, sheet_name=None, file_name=None, **kwargs):
54
- """excel内容并写入到内存list中
55
- :param excel_data:excel的io对象, 参数和file_name互斥
56
- :file_name: excel文件名称,目前读取check_file目录下文件,参数和excel_data互斥
57
-
58
- io:可以是文件路径、文件对象或 ExcelFile 对象,代表要读取的 Excel 文件。
59
- sheet_name:指定要读取的工作表,默认为第一个工作表(索引为 0)。
60
- header:指定哪一行作为列名,默认为第一行(索引为 0)。
61
- names:可以为列提供自定义名称,如果设置了这个,会覆盖文件中的列名。
62
- index_col:可以指定某一列或多列作为索引。
63
- usecols:可以指定要读取的列,可以是列的索引、列名或一个筛选函数。
64
- dtype:可以指定数据类型,控制数据的类型转换。
65
- engine:指定使用的 Excel 引擎,比如 xlrd、openpyxl 等。
66
- converters:可以为不同的列指定自定义的转换函数,以字典形式存储。
67
- true_values 和 false_values:定义哪些值会被视为 True 或 False。
68
- skiprows:可以指定要跳过的行,可以是一个整数序列、一个整数或一个函数。
69
- nrows:可以指定要读取的行数。
70
- na_values:可以指定哪些值会被视为 NaN。
71
- keep_default_na:决定是否使用默认的 NaN 值。
72
- na_filter:决定是否过滤 NaN 值。
73
- verbose:决定是否输出详细信息。
74
- parse_dates:决定是否解析日期,可以是一个列表、字典或布尔值。
75
- date_parser:自定义的日期解析函数。
76
- date_format:日期的格式设置。
77
- thousands:千位分隔符。
78
- decimal:小数点分隔符。
79
- comment:注释字符,以该字符开头的行将被跳过。
80
- skipfooter:指定要跳过的文件末尾的行数。
81
- storage_options:存储选项。
82
- dtype_backend:数据类型后端。
83
- engine_kwargs:传递给引擎的额外参数。
84
- @param sheet_name:
85
-
86
-
87
- """
88
- try:
89
- if excel_data is not None and file_name is not None:
90
- pass
91
- elif file_name is not None:
92
- excel_data = os.path.join(os.path.dirname(os.getcwd()) + "/check_file/" + file_name)
93
-
94
- dfs = read_excel_data(excel_data)
95
- rows_list = []
96
- # 多sheet处理
97
- for name, df in dfs.items():
98
- rows_list.append(df.values.tolist())
99
- if len(dfs) <= 1:
100
- rows_list = rows_list[0]
101
- return rows_list
102
- except Exception as e:
103
- print(f"excel写入list时出错:{e}")
104
-
105
-
106
- def read_excel_and_write_to_csv(excel_data, file_name, **kwargs):
107
- """excel内容并写入到csv中"""
108
- try:
109
- df = pd.read_excel(excel_data, engine="openpyxl")
110
- local_csv_path = os.path.join(os.path.dirname(os.getcwd()) + "/temp_file/" + file_name)
111
- df.to_csv(local_csv_path, index=False, **kwargs)
112
- return local_csv_path
113
- except Exception as e:
114
- print(f"excel写入csv时出错:{e}")
115
-
116
-
117
- def read_excel_data_for_oss_write_to_dict(oss, **kwargs) -> dict:
118
- """
119
- 1、根据oss link 直接读出 dict-list
120
- 2、支持多sheet,默认sheet_name =None查全部
121
- 3、返回dict结构 {'sheet_name':[rows_list]}
122
- """
123
- try:
124
- dfs = read_excel_data(read_excel_from_oss(oss))
125
- result = {}
126
- for sheet_name, df in dfs.items():
127
- rows_list = df.values.tolist()
128
- result[sheet_name] = rows_list
129
- return result
130
- except Exception as e:
131
- print(f"excel生成dict出错:{e}")
132
-
133
-
134
- def read_excel_header_for_oss_write_to_list(oss) -> list:
135
- """
136
- 1、根据oss link 直接读出excel的头列 list
137
- """
138
- try:
139
- dfs = read_excel_data(read_excel_from_oss(oss))
140
- result = []
141
- for sheet_name, df in dfs.items():
142
- result.append(df.keys().values.tolist())
143
- return result
144
- except Exception as e:
145
- print(f"excel生成header-dict出错:{e}")
146
-
147
-
148
- def check_excel(check_type="content", **kwargs):
149
- """对比excel
150
- :param: type: 需要对比类型,
151
- 枚举:content:对比两表格内容
152
- 方式1:传参actual_oss和expected_oss,参数类型str,url
153
- 放松1:传参actual和expected,参数类型list or dict
154
- excelName: 对比两表格文件名称
155
- all: 对比所有内容
156
- """
157
- try:
158
- if check_type == "content":
159
- if "actual" in kwargs.keys() and "expected" in kwargs.keys():
160
- return check_excel_content(actual=kwargs["actual"], expected=kwargs["expected"])
161
- else:
162
- return check_excel_content(
163
- actual=read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["actual_oss"])),
164
- expected=read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["expected_oss"]))
165
- )
166
- elif check_type == "excelName":
167
- return check_excel_name(actual_oss=kwargs["actual_oss"], expected_oss=kwargs["expected_oss"])
168
- elif check_type == "all":
169
- actual_content = read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["actual_oss"]))
170
- expected_content = read_excel_and_write_to_list(excel_data=read_excel_from_oss(url=kwargs["expected_oss"]))
171
- flag1, content_result = check_excel_content(actual=actual_content, expected=expected_content)
172
- flag2, name_result = check_excel_name(actual_oss=kwargs["actual_oss"], expected_oss=kwargs["expected_oss"])
173
- flag3 = check_excel_header(actual_oss=kwargs["actual_oss"], expected_oss=kwargs["expected_oss"])
174
- return all([flag1, flag2, flag3]), {"文件名称": name_result, "导出内容": content_result}
175
- else:
176
- return False, f"不支持此类型: {check_type}"
177
- except Exception as e:
178
- print(f"对比excel异常:{e}")
179
- return False, [e]
180
-
181
-
182
- # 定义比较类型和对应处理函数的映射
183
- comparison_functions = {
184
- # 内容
185
- "content": lambda kwargs: check_excel_content(kwargs["actual"], kwargs[
186
- "expected"])
187
- if "actual" in kwargs and "expected" in kwargs
188
- else check_excel_content(kwargs["actual_oss"], kwargs["expected_oss"]),
189
- # excelName
190
- "excelName": lambda kwargs: check_excel_name(kwargs["actual_oss"], kwargs["expected_oss"]),
191
- 'header': lambda kwargs: check_excel_header(kwargs["actual_oss"], kwargs["expected_oss"]),
192
- # 全部
193
- "all": lambda kwargs: check_excel_all(kwargs["actual_oss"], kwargs["expected_oss"])
194
- }
195
-
196
-
197
- def check_excel_for_lu(check_type="content", **kwargs):
198
- """对比excel
199
- :param: type: 需要对比类型,
200
- 枚举:
201
- content:对比两表格内容
202
- 方式1:传参actual_oss和expected_oss,参数类型str,url
203
- 放松1:传参actual和expected,参数类型list or dict
204
- excelName: 对比两表格文件名称,传oss链接
205
- all: 对比所有内容,传oss链接
206
- """
207
- try:
208
- # 根据 check_type 获取对应的处理函数
209
- compare_func = comparison_functions.get(check_type)
210
- if compare_func:
211
- return compare_func(kwargs)
212
- else:
213
- return False, f"不支持此类型: {check_type}"
214
- except KeyError as ke:
215
- # raise ke
216
- print(f"类型对应参数缺失异常:{ke}")
217
- return False, [str(ke)]
218
- except Exception as e:
219
- print(f"对比 Excel 异常:{e}")
220
- return False, [str(e)]
221
-
222
-
223
- def check_excel_content_form_oss(actual_oss, expected_oss):
224
- """通过 OSS URL 比较 Excel 内容"""
225
- expected, actual = read_excel_and_write_to_list(read_excel_from_oss(expected_oss)), read_excel_and_write_to_list(
226
- read_excel_from_oss(actual_oss))
227
- return check_excel_content(actual=actual, expected=expected)
228
-
229
-
230
- def check_excel_all(actual_oss, expected_oss):
231
- """
232
- 校验所有内容
233
- """
234
- flag1, content_result = check_excel_content_form_oss(actual_oss, expected_oss)
235
- flag2, name_result = check_excel_name(actual_oss, expected_oss)
236
- flag3 = check_excel_header(actual_oss, expected_oss)
237
- return all([flag1, flag2, flag3]), {"文件名称": name_result, "导出内容": content_result,
238
- "校验结果": [flag1, flag2, flag3]}
239
-
240
-
241
- def check_excel_name(actual_oss, expected_oss):
242
- """校验excel文件名称
243
- :param actual_oss:实际oss链接
244
- :param actual_oss:预期oss链接
245
- """
246
- try:
247
- actual_name = unquote(actual_oss.split("/")[-1])
248
- expected_name = unquote(expected_oss.split("/")[-1])
249
- if actual_name == expected_name:
250
- return True, "excel文件名称-完成匹配"
251
- else:
252
- return False, f"excel文件名称-不匹配, 实际: {actual_name}, 预期: {expected_name}"
253
- except BaseException as msg:
254
- return False, f"excel文件名称-服务异常: {msg}"
255
-
256
-
257
- def check_excel_content(actual, expected):
258
- """校验excel内容
259
- :param actual: 实际内容,list或dict类型
260
- :param expected:预期内容:list或dict类型
261
- """
262
- try:
263
- # TODO 嵌套list -dict 比较失败
264
- if actual == expected:
265
- return True, ["excel内容-完全匹配"]
266
- else:
267
- errors = []
268
- # 断言1:校验行数
269
- actual_num = len(actual)
270
- expected_num = len(expected)
271
- check_row = actual_num - expected_num
272
- if check_row == 0:
273
- errors.append("excel内容-预期和实际行数相等,为" + str(actual_num) + "行")
274
- else:
275
- errors.append(
276
- "excel内容-行数和预期对比差" + check_row.__str__() + "行" + ", 实际:" + str(
277
- actual_num) + "预期: " + str(
278
- expected_num))
279
- # 断言不匹配行
280
- if check_row >= 0:
281
- num = len(expected)
282
- else:
283
- num = len(actual)
284
- for i in range(num):
285
- if actual[i] == expected[i]:
286
- continue
287
- else:
288
- errors.append(
289
- "excel内容-第" + str(i + 1) + "行不匹配,预期为:" + str(expected[i]) + ", 实际为: " + str(actual[i]))
290
- return False, errors
291
- except Exception as e:
292
- print(f":excel内容-服务异常{e}")
293
- return False, [e]
294
-
295
-
296
- def check_excel_header(actual_oss, expected_oss):
297
- """
298
- 比较两个文档第一列的header是否一致
299
- @param actual_oss:
300
- @param expected_oss:
301
- @return:
302
- """
303
- actual, expected = read_excel_data_for_oss_write_to_dict(actual_oss), read_excel_data_for_oss_write_to_dict(
304
- expected_oss)
305
- return actual == expected
306
-
307
-
308
- def del_temp_file(file_name=""):
309
- """删除temp下临时文件"""
310
- file_path = os.path.join(os.path.dirname(os.getcwd()) + "/temp_file/" + file_name)
311
- try:
312
- os.remove(file_path)
313
- print(f"文件 {file_path} 已成功删除。")
314
- except FileNotFoundError:
315
- print(f"文件 {file_path} 不存在。")
316
- except Exception as e:
317
- print(f"删除文件 {file_path} 时出错:{e}")
@@ -1,37 +0,0 @@
1
- import requests
2
- from retry import retry
3
- import json
4
- from smartpush.utils.StringUtils import StringUtils
5
-
6
-
7
- def get_oss_address_with_retry(target_id, url, requestHeader, requestParam, **kwargs) -> str:
8
- """
9
- 创建带有动态重试配置的获取 OSS 地址
10
- **kwargs 可传参:tries=10, delay=2, backoff=1
11
- :param requestParam:
12
- :param url:
13
- :param target_id:
14
- :param requestHeader:
15
- :return: 带有重试配置的获取 OSS 地址的
16
- """
17
-
18
- @retry(tries=10, delay=2, backoff=1)
19
- def get_oss_address():
20
- if StringUtils.is_empty(target_id):
21
- print(f"缺少参数:target_id")
22
- return
23
- try:
24
- response = requests.request(url=url, headers=requestHeader, data=json.dumps(requestParam), method="post")
25
- response.raise_for_status()
26
- result = response.json()
27
- id_url_dict = {item["id"]: item["url"] for item in result["resultData"]["datas"]}
28
- if target_id in id_url_dict:
29
- if len(id_url_dict[target_id]) == 1:
30
- return id_url_dict[target_id][0]
31
- else:
32
- raise ValueError(f"存在多条 id 为 {target_id} 的记录,记录为:{id_url_dict[target_id]}")
33
- else:
34
- raise ValueError(f"未找到 id 为 {target_id} 的记录,未包含有效的 OSS 地址,")
35
- except (KeyError, json.JSONDecodeError) as e:
36
- raise ValueError(f"响应数据格式错误,响应结果: {result},异常: {e}")
37
- return get_oss_address()
@@ -1,18 +0,0 @@
1
- from smartpush.export.basic.ExcelExportChecker import *
2
- from smartpush.export.basic.GetOssUrl import get_oss_address_with_retry
3
-
4
- import urllib3
5
-
6
- if __name__ == '__main__':
7
- # print(check_excel_for_lu("content",actual_oss="https://sl-smartfile.oss-ap-southeast-1.aliyuncs.com/material_ec2_prod/2025-01-20/fcb98e2965314ef2862db65760dcce1f/ab%E5%BC%B9%E7%AA%97%E6%B4%BB%E5%8A%A8-%E8%BD%AC%E5%8C%96%E7%8E%87%E8%8E%B7%E8%83%9C%E9%94%80%E5%94%AE%E9%A2%9D%E6%98%8E%E7%BB%86%E6%95%B0%E6%8D%AE.xlsx",expected_oss="https://sl-smartfile.oss-ap-southeast-1.aliyuncs.com/material_ec2_prod/2025-01-20/fcb98e2965314ef2862db65760dcce1f/ab%E5%BC%B9%E7%AA%97%E6%B4%BB%E5%8A%A8-%E8%BD%AC%E5%8C%96%E7%8E%87%E8%8E%B7%E8%83%9C%E9%94%80%E5%94%AE%E9%A2%9D%E6%98%8E%E7%BB%86%E6%95%B0%E6%8D%AE.xlsx"))
8
- _id = 10901
9
- url = "https://test.smartpushedm.com/api-em-ec2/bulkOps/query"
10
- requestHeaders = {
11
- 'cookie': 'osudb_appid=SMARTPUSH;osudb_oar=#01#SID0000121BJe/0W0PdWQj0Wo/Cr4G9H5S58u/YpvUYbOxsyvHQXmU5iToD8h3GX0+/3Af1efOroDv2jIwJIPVx2F1/XCP08l/NOaWMIZ/xm1/ugKB7eA1k1akIdCSTOHJcJ95Ahp7Yz0cBgOwtr8OgF77WNxX;osudb_subappid=1;osudb_uid=4213785247;ecom_http_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDIwMTEyNDcsImp0aSI6IjY4M2E1NDg1LTEwYjAtNDRhZS04MGMxLWQ1MmFkN2YxNmViNCIsInVzZXJJbmZvIjp7ImlkIjowLCJ1c2VySWQiOiI0MjEzNzg1MjQ3IiwidXNlcm5hbWUiOiIiLCJlbWFpbCI6ImZlbGl4LnNoYW9Ac2hvcGxpbmVhcHAuY29tIiwidXNlclJvbGUiOiJvd25lciIsInBsYXRmb3JtVHlwZSI6Nywic3ViUGxhdGZvcm0iOjEsInBob25lIjoiIiwibGFuZ3VhZ2UiOiJ6aC1oYW5zLWNuIiwiYXV0aFR5cGUiOiIiLCJhdHRyaWJ1dGVzIjp7ImNvdW50cnlDb2RlIjoiQ04iLCJjdXJyZW5jeSI6IkpQWSIsImN1cnJlbmN5U3ltYm9sIjoiSlDCpSIsImRvbWFpbiI6InNtYXJ0cHVzaDQubXlzaG9wbGluZXN0Zy5jb20iLCJsYW5ndWFnZSI6ImVuIiwibWVyY2hhbnRFbWFpbCI6ImZlbGl4LnNoYW9Ac2hvcGxpbmUuY29tIiwibWVyY2hhbnROYW1lIjoiU21hcnRQdXNoNF9lYzJf6Ieq5Yqo5YyW5bqX6ZO6IiwicGhvbmUiOiIiLCJzY29wZUNoYW5nZWQiOmZhbHNlLCJzdGFmZkxhbmd1YWdlIjoiemgtaGFucy1jbiIsInN0YXR1cyI6MCwidGltZXpvbmUiOiJBc2lhL01hY2FvIn0sInN0b3JlSWQiOiIxNjQ0Mzk1OTIwNDQ0IiwiaGFuZGxlIjoic21hcnRwdXNoNCIsImVudiI6IkNOIiwic3RlIjoiIiwidmVyaWZ5IjoiIn0sImxvZ2luVGltZSI6MTczOTQxOTI0Nzg2OSwic2NvcGUiOlsiZW1haWwtbWFya2V0IiwiY29va2llIiwic2wtZWNvbS1lbWFpbC1tYXJrZXQtbmV3LXRlc3QiLCJlbWFpbC1tYXJrZXQtbmV3LWRldi1mcyIsImFwaS11Yy1lYzIiLCJhcGktc3UtZWMyIiwiYXBpLWVtLWVjMiIsImZsb3ctcGx1Z2luIl0sImNsaWVudF9pZCI6ImVtYWlsLW1hcmtldCJ9.PJGM1sSZyvxTriMK4e1g90krqBUq9OVNc5vEyKxsXyQ;',
12
- 'Content-Type': 'application/json'}
13
- requestParams = {'page': 1, 'pageSize': 10, 'type': 'EXPORT', 'status': None, 'startTime': None, 'endTime': None}
14
- oss=get_oss_address_with_retry(_id, url, requestHeaders, requestParams, tries=1, delay=1, backoff=1)
15
- check_excel_for_lu("all",oss,oss)
16
- # oss = "https://cdn.smartpushedm.com/material_sf/2025-02-19/c70bb6f3588b4c89bde6ed75813ea4f3/%E5%AF%BC%E5%87%BA%E5%85%A8%E9%83%A8%E5%AE%A2%E6%88%B7.csv"
17
- # eexcelxcel =read_excel_and_write_to_list(read_excel_from_oss(oss))
18
- print(eexcelxcel)
File without changes
File without changes