Functions-d 1.2.4__tar.gz → 1.27__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.
@@ -148,6 +148,7 @@ class DataProcessingAndMessaging:
148
148
  self.logger.info('\n' * 10)
149
149
 
150
150
  # -------------------------- 企业微信消息发送 --------------------------
151
+ # 仅展示修改后的 uxin_wx 方法,其余代码不变
151
152
  def uxin_wx(self, name, message, mentioned_list=None):
152
153
  sender = WeComMsg.WeChatWorkSender(self.corpid, self.corpsecret, self.agentid)
153
154
  try:
@@ -158,6 +159,43 @@ class DataProcessingAndMessaging:
158
159
  target_type = "群聊(Webhook)" if name.startswith("https://") else "单个用户"
159
160
  self.logger.info(f"开始向{target_type}发送消息,目标:{name}")
160
161
 
162
+ # ========== 新增:Markdown消息识别与处理 ==========
163
+ # 识别规则:message以特定标识开头(如「MD:」),或显式传入markdown类型
164
+ is_markdown = False
165
+ md_content = ""
166
+ if isinstance(message, dict) and message.get("type") == "markdown":
167
+ # 支持字典格式传参:{"type": "markdown", "content": "markdown内容"}
168
+ is_markdown = True
169
+ md_content = message.get("content", "")
170
+ elif isinstance(message, str) and message.startswith("MD:"):
171
+ # 支持字符串前缀标识:"MD:### 标题\n内容"
172
+ is_markdown = True
173
+ md_content = message[3:].strip() # 去掉前缀"MD:"
174
+
175
+ if is_markdown:
176
+ # 处理Markdown消息
177
+ if isinstance(name, str) and name.startswith("https://"):
178
+ # 群聊Webhook发送Markdown
179
+ self.logger.info(f"发送群聊Markdown消息:内容={md_content}")
180
+ result = sender.send_markdown_to_group(name, md_content)
181
+ else:
182
+ # 个人/多用户发送Markdown
183
+ receivers = name if isinstance(name, list) else [name]
184
+ self.logger.info(f"发送个人Markdown消息:内容={md_content},接收者:{receivers}")
185
+ result = sender.send_markdown(receivers, md_content)
186
+
187
+ msg_id = result.get('msgid', '未知')
188
+ self.logger.info(
189
+ f"Markdown消息发送结果:{'成功' if result.get('errcode') == 0 else '失败'},错误信息:{result.get('errmsg')},消息ID:{msg_id}")
190
+
191
+ if result.get('errcode') == 0:
192
+ print(f"给 {target_type} 的Markdown消息发送成功,消息ID:{msg_id}")
193
+ else:
194
+ print(
195
+ f"给 {target_type} 的Markdown消息发送失败,错误码:{result.get('errcode')},错误信息:{result.get('errmsg')},消息ID:{msg_id}")
196
+ return
197
+
198
+ # ========== 原有逻辑(文本/文件/图片)保持不变 ==========
161
199
  if isinstance(name, str) and name.startswith("https://"):
162
200
  if isinstance(message, str) and message.endswith(('.xlsx', '.docx', '.pdf', '.txt')) and os.path.isfile(
163
201
  message):
@@ -319,26 +357,116 @@ class DataProcessingAndMessaging:
319
357
  return result
320
358
 
321
359
  # -------------------------- 发送邮件(旧版) --------------------------
322
- def sende_email(self, name, contact_name, title, rec, file, cc=False, bcc=None):
323
- yag = yagmail.SMTP(user='cc_yingxiao@xin.com', password='cw46pfeznNQx', host='mail.xin.com', port='587',
324
- smtp_ssl=False, smtp_starttls=True)
325
- contents = f'{name} 好:\n \n ' \
326
- f'附件为{title},请查收!\n \n' \
327
- f'如有疑问请联系{contact_name},谢谢~'
360
+ def sende_email(self, name, contact_name, title, rec, file=None, cc=None, bcc=None, remarks=None):
361
+ """
362
+ 简洁版邮件发送(支持重复调用,自动过滤无效参数)
363
+ :param name: 收件人称呼(如"各位")
364
+ :param contact_name: 联系人姓名(如"董养")
365
+ :param title: 邮件主题
366
+ :param rec: 收件人邮箱(单个字符串或列表)
367
+ :param file: 附件路径(单个字符串、列表,或None)
368
+ :param cc: 抄送邮箱(单个字符串、列表,或None)
369
+ :param bcc: 密送邮箱(单个字符串、列表,或None)
370
+ :param remarks: 附加备注(可选,默认None,传入文本字符串时追加到正文)
371
+ """
372
+
373
+ # 1. 内部工具:格式化邮箱(转列表+过滤无效值)
374
+ def format_email(emails):
375
+ if not emails:
376
+ return None
377
+ # 单个邮箱转列表,列表直接使用
378
+ email_list = [emails] if isinstance(emails, str) else emails
379
+ # 过滤:非空字符串 + 简单格式校验(含@和.)
380
+ valid_emails = [
381
+ e.strip() for e in email_list
382
+ if isinstance(e, str) and e.strip() and '@' in e.strip() and '.' in e.strip()
383
+ ]
384
+ return valid_emails if valid_emails else None
385
+
386
+ # 2. 格式化所有邮箱参数
387
+ to_emails = format_email(rec)
388
+ cc_emails = format_email(cc)
389
+ bcc_emails = format_email(bcc)
390
+
391
+ # 3. 核心参数校验(提前报错,避免无效连接)
392
+ if not to_emails:
393
+ err_msg = "邮件发送失败:无有效收件人邮箱"
394
+ self.logger.error(err_msg)
395
+ raise ValueError(err_msg)
396
+ if not title.strip():
397
+ err_msg = "邮件发送失败:邮件主题不能为空"
398
+ self.logger.error(err_msg)
399
+ raise ValueError(err_msg)
400
+
401
+ # 4. 附件处理(校验存在性,支持单个/列表)
402
+ attachments = None
403
+ if file:
404
+ file_list = [file] if isinstance(file, str) else file
405
+ attachments = []
406
+ for f in file_list:
407
+ f = f.strip()
408
+ if not os.path.exists(f):
409
+ err_msg = f"邮件发送失败:附件不存在 -> {f}"
410
+ self.logger.error(err_msg)
411
+ raise FileNotFoundError(err_msg)
412
+ attachments.append(f)
413
+
414
+ # 5. SMTP固定配置(重复调用无需修改)
415
+ smtp_conf = {
416
+ "user": 'cc_yingxiao@xin.com',
417
+ "password": 'cw46pfeznNQx',
418
+ "host": 'mail.xin.com',
419
+ "port": 587,
420
+ "smtp_ssl": False,
421
+ "smtp_starttls": True
422
+ }
423
+
424
+ # 6. 邮件内容(新增remarks逻辑:有值则追加到"请查收!"下方,保持缩进一致)
425
+ email_content = f"{name} 好:\n附件为《{title}》,请查收!"
426
+ if remarks and isinstance(remarks, str) and remarks.strip():
427
+ formatted_remarks = remarks.strip().replace('\n', '\n') # 处理多行备注
428
+ email_content += f"\n{formatted_remarks}"
429
+ email_content += f"\n\n如有疑问请联系{contact_name},谢谢~"
430
+
328
431
  try:
329
- if cc and bcc:
330
- yag.send(rec, title, contents, file, cc, bcc)
331
- elif cc:
332
- yag.send(rec, title, contents, file, cc)
333
- elif bcc:
334
- yag.send(rec, title, contents, file, bcc)
335
- else:
336
- yag.send(rec, title, contents, file)
337
- self.logger.info(f'邮件主题:{title} \n邮件附件:{file} 发送完成')
338
- print(f'邮件主题:{title} \n邮件附件:{file} 发送完成')
432
+ # 上下文管理器:自动关闭连接,重复调用不泄露资源
433
+ with yagmail.SMTP(**smtp_conf) as yag:
434
+ yag.send(
435
+ to=to_emails,
436
+ subject=title.strip(),
437
+ contents=email_content,
438
+ attachments=attachments,
439
+ cc=cc_emails,
440
+ bcc=bcc_emails
441
+ )
442
+ # 简洁日志:关键信息+统计,便于排查
443
+ log_msg = f"邮件发送成功 | 主题:{title.strip()} | 收件人:{len(to_emails)}人"
444
+ if cc_emails:
445
+ log_msg += f" | 抄送:{len(cc_emails)}人"
446
+ if bcc_emails:
447
+ log_msg += f" | 密送:{len(bcc_emails)}人"
448
+ if attachments:
449
+ log_msg += f" | 附件:{len(attachments)}个"
450
+ if remarks and remarks.strip():
451
+ log_msg += f" | 包含备注:{remarks.strip()[:20]}..." # 日志显示备注前20字(避免过长)
452
+ self.logger.info(log_msg)
453
+ print(log_msg)
454
+
455
+ # 7. 分类异常捕获(易排查问题)
456
+ except yagmail.SMTPAuthenticationError:
457
+ err_msg = "邮件发送失败:SMTP账号/密码/授权码错误"
458
+ self.logger.error(err_msg)
459
+ raise ValueError(err_msg)
460
+ except yagmail.SMTPConnectionError:
461
+ err_msg = "邮件发送失败:SMTP服务器连接失败(检查host/port/防火墙)"
462
+ self.logger.error(err_msg)
463
+ raise ConnectionError(err_msg)
464
+ except FileNotFoundError:
465
+ raise # 附件错误已提前处理,直接抛出
339
466
  except Exception as e:
340
- self.logger.error(f"邮件发送失败: {str(e)}", exc_info=True)
341
- raise
467
+ err_msg = f"邮件发送失败:{str(e)}"
468
+ self.logger.error(err_msg, exc_info=True)
469
+ raise RuntimeError(err_msg)
342
470
 
343
471
  # 新增:提取Hive核心错误信息方法
344
472
  def extract_core_hive_error(self, err_msg):
@@ -938,15 +1066,55 @@ class DataProcessingAndMessaging:
938
1066
  self._wechat_doc_log(error_msg)
939
1067
  raise Exception(error_msg)
940
1068
  docid = result.get("docid")
941
- self._wechat_doc_log(f"智能表格:{sheet_name} 创建成功,docid={docid}")
942
- print(f"智能表格:{sheet_name} 创建成功,docid={docid}")
943
- return {"智能表格": sheet_name, "docid": docid, "url": result.get("url")}
1069
+ # ========== 新增:添加创建时间 ==========
1070
+ # 获取当前时间(北京时间,格式:YYYY-MM-DD HH:MM:SS)
1071
+ create_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
1072
+
1073
+ # ========== 核心新增:创建成功后自动查询子sheet ==========
1074
+ self._wechat_doc_log(f"开始查询新创建表格[{docid}]的子表信息")
1075
+ # 然后修改wx_create_table中调用wx_get_sheets的代码,传入send_notice=False:
1076
+ sheet_list = self.wx_get_sheets(docid, send_notice=False)
1077
+
1078
+ # ========== 构造包含子sheet的完整消息内容 ==========
1079
+ # 基础信息
1080
+ msg_content = f"✅ 智能表格创建成功\n表格名称:{sheet_name}\n创建时间:{create_time}\ndocid:{docid}\n\n子表信息:"
1081
+ # 子sheet信息
1082
+ if sheet_list:
1083
+ for idx, sheet in enumerate(sheet_list, 1):
1084
+ sheet_visibility = '可见' if sheet['is_visible'] else '不可见'
1085
+ msg_content += f"\n{idx}. ID: {sheet['sheet_id']} | 标题: {sheet['title']} | 类型: {sheet['type']} | 可见性: {sheet_visibility}"
1086
+ else:
1087
+ msg_content += "\n暂无子表信息"
1088
+
1089
+ self._wechat_doc_log(
1090
+ f"智能表格:{sheet_name} 创建成功,docid={docid},创建时间={create_time},子表数量:{len(sheet_list)}")
1091
+ print(f"智能表格:{sheet_name} 创建成功,docid={docid},创建时间={create_time}")
1092
+ print(f"该表格的子表信息:")
1093
+ if sheet_list:
1094
+ for idx, sheet in enumerate(sheet_list, 1):
1095
+ sheet_visibility = '可见' if sheet['is_visible'] else '不可见'
1096
+ print(
1097
+ f" {idx}. ID: {sheet['sheet_id']} | 标题: {sheet['title']} | 类型: {sheet['type']} | 可见性: {sheet_visibility}")
1098
+ else:
1099
+ print(" 暂无子表信息")
1100
+
1101
+ # 调用uxin_wx发送包含子sheet的完整消息
1102
+ self.uxin_wx('dongyang', msg_content)
1103
+
1104
+ return {
1105
+ "智能表格": sheet_name,
1106
+ "docid": docid,
1107
+ "url": result.get("url"),
1108
+ "创建时间": create_time,
1109
+ "子表列表": sheet_list # 返回值新增子sheet列表
1110
+ }
944
1111
  except Exception as e:
945
1112
  self._wechat_doc_log(f"创建异常: {str(e)}")
946
1113
  raise
947
1114
 
948
1115
  # -------------------------- 企微文档:查询子表 --------------------------
949
- def wx_get_sheets(self, docid):
1116
+ # 修改wx_get_sheets方法的定义,新增send_notice参数
1117
+ def wx_get_sheets(self, docid, send_notice=True):
950
1118
  self._wechat_doc_log(f"查询文档[{docid}]的子表信息")
951
1119
  self._wechat_doc_refresh_token_if_needed()
952
1120
 
@@ -962,10 +1130,30 @@ class DataProcessingAndMessaging:
962
1130
  if result.get("errcode") != 0:
963
1131
  error_msg = f"查询子表失败: {result.get('errmsg')}"
964
1132
  self._wechat_doc_log(error_msg)
1133
+ # 失败时仍发送通知
1134
+ fail_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
1135
+ fail_content = f"⚠️ 企微文档子表查询失败\n查询时间:{fail_time}\n文档ID:{docid}\n错误信息:{result.get('errmsg')}"
1136
+ self.uxin_wx('dongyang', fail_content)
965
1137
  raise Exception(error_msg)
966
1138
 
967
1139
  sheet_list = result.get("sheet_list", [])
1140
+ query_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
968
1141
  self._wechat_doc_log(f"查询文档[{docid}]子表完成,共找到{len(sheet_list)}个子表")
1142
+
1143
+ # 构造通知内容
1144
+ msg_content = f"✅ 企微文档子表查询完成\n查询时间:{query_time}\n文档ID:{docid}\n子表总数:{len(sheet_list)}\n\n子表详细信息:"
1145
+ if sheet_list:
1146
+ for idx, sheet in enumerate(sheet_list, 1):
1147
+ sheet_visibility = '可见' if sheet['is_visible'] else '不可见'
1148
+ msg_content += f"\n{idx}. ID: {sheet['sheet_id']} | 标题: {sheet['title']} | 类型: {sheet['type']} | 可见性: {sheet_visibility}"
1149
+ else:
1150
+ msg_content += "\n暂无子表信息"
1151
+
1152
+ # 仅当send_notice为True时发送通知
1153
+ if send_notice:
1154
+ self.uxin_wx('dongyang', msg_content)
1155
+
1156
+ # 原有日志和打印逻辑
969
1157
  for sheet in sheet_list:
970
1158
  sheet_info = (f"子表信息 - ID: {sheet['sheet_id']}, 标题: {sheet['title']}, "
971
1159
  f"类型: {sheet['type']}, 可见性: {'可见' if sheet['is_visible'] else '不可见'}")
@@ -1119,8 +1307,12 @@ class DataProcessingAndMessaging:
1119
1307
  self._wechat_doc_log(error_msg)
1120
1308
  raise Exception(error_msg)
1121
1309
 
1122
- self._wechat_doc_log(f"文档删除成功:docid={docid}")
1123
- print(f"文档删除成功:docid={docid}")
1310
+ # 获取当前时间(北京时间,格式:YYYY-MM-DD HH:MM:SS)
1311
+ create_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
1312
+ msg_content = f"企微文档删除成功:docid={docid} \n 删除时间:{create_time}"
1313
+ self._wechat_doc_log(msg_content)
1314
+ print(msg_content)
1315
+ self.uxin_wx('dongyang', msg_content)
1124
1316
  return True
1125
1317
 
1126
1318
  # -------------------------- 辅助方法:检查文件是否被占用 --------------------------
@@ -1,4 +1,4 @@
1
- # WeComMsg/__init__.py
1
+ # Functions_d/__init__.py
2
2
 
3
3
  # 从核心代码文件中导入需要对外暴露的类/函数
4
4
  from .Functions_d import DataProcessingAndMessaging
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Functions_d
3
- Version: 1.2.4
3
+ Version: 1.27
4
4
  Summary: 包含数据处理、Hive交互、企业微信消息发送、Excel操作等功能的工具类库
5
5
  Author: DongYang
6
6
  Author-email: 649898871@qq.com
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Functions_d
3
- Version: 1.2.4
3
+ Version: 1.27
4
4
  Summary: 包含数据处理、Hive交互、企业微信消息发送、Excel操作等功能的工具类库
5
5
  Author: DongYang
6
6
  Author-email: 649898871@qq.com
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = Functions_d
3
- version = 1.2.4
3
+ version = 1.27
4
4
  author = DongYang
5
5
  author_email = 649898871@qq.com
6
6
  description = 包含数据处理、Hive交互、企业微信消息发送、Excel操作等功能的工具类库
File without changes
File without changes
File without changes