dddtools 0.1.1__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.
@@ -0,0 +1,869 @@
1
+ Metadata-Version: 2.4
2
+ Name: dddtools
3
+ Version: 0.1.1
4
+ Summary: 常用工具函数集合
5
+ Author-email: Owner <owner@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/owner/dtools
8
+ Keywords: utils,tools
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: pycryptodome>=3.19.0
21
+
22
+ # dddtools
23
+
24
+ 常用工具函数集合。支持 Python 3.8+。
25
+
26
+ ---
27
+
28
+ ## 目录
29
+
30
+ - [安装](#安装)
31
+ - [快速开始](#快速开始)
32
+ - [日志模块 (logging)](#日志模块-logging)
33
+ - [装饰器 (decorator)](#装饰器-decorator)
34
+ - [FTP操作 (ftp)](#ftp操作-ftp)
35
+ - [邮件发送 (mail)](#邮件发送-mail)
36
+ - [HTML模板 (mail.template)](#html模板-mailtemplate)
37
+ - [缓存管理 (redis)](#缓存管理-redis)
38
+ - [文件结构](#文件结构)
39
+ - [常见问题](#常见问题)
40
+
41
+ ---
42
+
43
+ ## 安装
44
+
45
+ ### PyPI 安装(稳定版)
46
+
47
+ ```bash
48
+ pip install dddtools
49
+ ```
50
+
51
+ ### 本地安装(开发版)
52
+
53
+ ```bash
54
+ cd /path/to/dddtools
55
+ pip install -e .
56
+ ```
57
+
58
+ ### 从源码安装
59
+
60
+ ```bash
61
+ git clone https://github.com/yourname/dddtools.git
62
+ cd dddtools
63
+ pip install -e .
64
+ ```
65
+
66
+ ---
67
+
68
+ ## 快速开始
69
+
70
+ ```python
71
+ # 导入所有功能
72
+ from dddtools import logger, timer, log_call, ftp, mail
73
+
74
+ # 1. 日志自动启动
75
+ logger.info("dddtools 已就绪")
76
+
77
+ # 2. 使用装饰器
78
+ @timer
79
+ @log_call()
80
+ def fetch_data():
81
+ return {"data": [1, 2, 3]}
82
+
83
+ result = fetch_data()
84
+
85
+ # 3. FTP操作
86
+ with ftp.connect("ftp.example.com", username="user", password="pass") as conn:
87
+ files = conn.list_files("/")
88
+ conn.download_file("/pub/data.csv", "./data.csv")
89
+
90
+ # 4. 发送邮件
91
+ mail.send_simple(
92
+ to_addrs=["admin@example.com"],
93
+ subject="系统通知",
94
+ content="任务已完成",
95
+ username="your@qq.com",
96
+ password="your授权码"
97
+ )
98
+ ```
99
+
100
+ ---
101
+
102
+ ## 日志模块 (logging)
103
+
104
+ 自动创建logs目录,按日期存储,自动清理7天前日志。
105
+
106
+ ### 默认日志器
107
+
108
+ ```python
109
+ from dddtools import logger
110
+
111
+ logger.debug("调试信息")
112
+ logger.info("普通信息")
113
+ logger.warning("警告")
114
+ logger.error("错误")
115
+ logger.critical("严重错误")
116
+ ```
117
+
118
+ ### 自定义日志器
119
+
120
+ ```python
121
+ from dddtools import get_logger
122
+
123
+ # 自定义名称、目录、保留天数
124
+ app_logger = get_logger(
125
+ name="MyApp", # 日志器名称
126
+ log_dir="/var/log/myapp", # 日志目录
127
+ days=30 # 保留30天
128
+ )
129
+
130
+ app_logger.info("自定义日志器")
131
+ ```
132
+
133
+ ### 日志格式
134
+
135
+ ```
136
+ 2026-02-07 14:03 | INFO | dddtools | dddtools 已就绪
137
+ 2026-02-07 14:03 | INFO | MyApp | 自定义日志器
138
+ ```
139
+
140
+ - 自动在运行目录创建 `logs` 文件夹
141
+ - 按日期切割:`2026-02-07.log`
142
+ - 同时输出到控制台和文件
143
+ - 默认保留7天
144
+
145
+ ---
146
+
147
+ ## 装饰器 (decorator)
148
+
149
+ ### timer - 耗时统计
150
+
151
+ 统计函数执行时间(毫秒)。
152
+
153
+ ```python
154
+ from dddtools import timer
155
+
156
+ @timer
157
+ def slow_function():
158
+ time.sleep(2)
159
+ return "完成"
160
+
161
+ result = slow_function()
162
+ # 输出: [slow_function] 耗时: 2002.35ms
163
+ ```
164
+
165
+ ### log_call - 调用日志
166
+
167
+ 记录函数调用详情。
168
+
169
+ ```python
170
+ from dddtools import log_call
171
+
172
+ # 基本用法(使用函数名作为日志名)
173
+ @log_call()
174
+ def add(a, b):
175
+ return a + b
176
+
177
+ # 自定义日志名
178
+ @log_call(name="计算器")
179
+ def multiply(x, y):
180
+ return x * y
181
+
182
+ # 自定义参数截断长度
183
+ @log_call(arg_limit=500, return_limit=800)
184
+ def process(data):
185
+ return {"result": data}
186
+
187
+ # 带关键字参数
188
+ @log_call()
189
+ def create_user(name, age, *, email=None):
190
+ return {"name": name, "age": age, "email": email}
191
+
192
+ # 调用示例
193
+ add(1, 2)
194
+ # 输出:
195
+ # [add] 传入: (a=1, b=2)
196
+ # [add] 返回: 3 | 耗时: 0.05ms
197
+
198
+ create_user("张三", 25, email="zhangsan@example.com")
199
+ # 输出:
200
+ # [create_user] 传入: (name='张三', age=25, email='zhangsan@example.com')
201
+ # [create_user] 返回: {'name': '张三', 'age': 25, 'email': 'zhangsan@example.com'} | 耗时: 0.12ms
202
+ ```
203
+
204
+ #### log_call 参数
205
+
206
+ | 参数 | 类型 | 默认值 | 说明 |
207
+ |------|------|--------|------|
208
+ | `name` | str | 函数名 | 日志名称 |
209
+ | `arg_limit` | int | 1000 | 参数字符串截断长度 |
210
+ | `return_limit` | int | 1000 | 返回值字符串截断长度 |
211
+
212
+ ---
213
+
214
+ ## FTP操作 (ftp)
215
+
216
+ ### 连接管理
217
+
218
+ ```python
219
+ from dddtools import ftp
220
+
221
+ # 基本连接
222
+ with ftp.connect("ftp.example.com") as conn:
223
+ pass
224
+
225
+ # 带认证
226
+ with ftp.connect(
227
+ host="ftp.example.com",
228
+ port=21,
229
+ username="your_user",
230
+ password="your_password",
231
+ timeout=30
232
+ ) as conn:
233
+ pass
234
+
235
+ # 匿名连接
236
+ with ftp.connect("ftp.example.com", username="anonymous", password="") as conn:
237
+ pass
238
+ ```
239
+
240
+ ### 获取文件列表
241
+
242
+ ```python
243
+ from dddtools import ftp
244
+
245
+ with ftp.connect("ftp.example.com", username="user") as conn:
246
+ # 获取当前目录列表
247
+ files = conn.list_files("/")
248
+ for f in files:
249
+ print(f"{'[DIR]' if f.is_dir else 'FILE']} {f.name} ({f.size} bytes)")
250
+
251
+ # 递归获取所有文件
252
+ all_files = conn.list_all("/", recursive=True)
253
+
254
+ # FTPFile 属性
255
+ # - name: 文件名/完整路径
256
+ # - size: 文件大小(字节)
257
+ # - is_dir: 是否为文件夹
258
+ # - modify_time: 修改时间
259
+ ```
260
+
261
+ ### 下载文件
262
+
263
+ ```python
264
+ from dddtools import ftp
265
+
266
+ with ftp.connect("ftp.example.com", username="user") as conn:
267
+ # 下载单个文件
268
+ conn.download_file(
269
+ remote_path="/pub/data/report.csv",
270
+ local_path="./downloads/report.csv",
271
+ overwrite=True # 是否覆盖
272
+ )
273
+
274
+ # 下载整个文件夹
275
+ conn.download_folder(
276
+ remote_folder="/pub/backups",
277
+ local_folder="./backups",
278
+ overwrite=True
279
+ )
280
+ ```
281
+
282
+ ### 上传文件
283
+
284
+ ```python
285
+ from dddtools import ftp
286
+
287
+ with ftp.connect("ftp.example.com", username="user") as conn:
288
+ # 上传单个文件
289
+ conn.upload_file(
290
+ local_path="./data.csv",
291
+ remote_path="/pub/uploads/data.csv",
292
+ overwrite=True
293
+ )
294
+
295
+ # 上传整个文件夹
296
+ conn.upload_folder(
297
+ local_folder="./project",
298
+ remote_path="/pub/projects/project",
299
+ overwrite=True
300
+ )
301
+ ```
302
+
303
+ ### 删除操作
304
+
305
+ ```python
306
+ from dddtools import ftp
307
+
308
+ with ftp.connect("ftp.example.com", username="user") as conn:
309
+ # 删除文件
310
+ conn.delete_file("/pub/old_file.txt")
311
+
312
+ # 删除空文件夹
313
+ conn.delete_folder("/pub/empty_folder")
314
+
315
+ # 递归删除(文件夹及其内容)
316
+ conn.delete_recursive("/pub/to_delete")
317
+ ```
318
+
319
+ ### FTP 完整示例
320
+
321
+ ```python
322
+ from dddtools import ftp, logger
323
+
324
+ def backup_website():
325
+ """备份网站文件"""
326
+ logger.info("开始备份")
327
+
328
+ with ftp.connect("ftp.yoursite.com", username="admin", password="pass") as conn:
329
+ # 获取文件列表
330
+ files = conn.list_all("/public_html", recursive=True)
331
+ logger.info(f"共找到 {len(files)} 个文件")
332
+
333
+ # 下载
334
+ conn.download_folder(
335
+ remote_folder="/public_html",
336
+ local_folder="./backup"
337
+ )
338
+
339
+ logger.info("备份完成")
340
+
341
+ backup_website()
342
+ ```
343
+
344
+ ---
345
+
346
+ ## 邮件发送 (mail)
347
+
348
+ ### 快速发送
349
+
350
+ ```python
351
+ from dddtools import mail
352
+
353
+ # 发送普通文本邮件
354
+ mail.send_simple(
355
+ to_addrs=["admin@example.com", "support@example.com"],
356
+ subject="系统通知",
357
+ content="您的订单已发货,请注意查收。",
358
+ username="123456@qq.com",
359
+ password="your授权码"
360
+ )
361
+
362
+ # 发送HTML邮件
363
+ mail.send_html(
364
+ to_addrs=["user@example.com"],
365
+ subject="欢迎注册",
366
+ html_content="<h1>欢迎使用 dddtools</h1><p>感谢您的注册</p>",
367
+ username="123456@qq.com",
368
+ password="your授权码"
369
+ )
370
+
371
+ # 发送带附件的邮件
372
+ mail.send_with_attachment(
373
+ to_addrs=["boss@example.com"],
374
+ subject="月度报告",
375
+ content="请查收附件中的月度报告。",
376
+ attachments=[
377
+ "/path/to/report.pdf",
378
+ "/path/to/summary.xlsx"
379
+ ],
380
+ username="123456@qq.com",
381
+ password="your授权码"
382
+ )
383
+ ```
384
+
385
+ ### 使用 MailClient
386
+
387
+ ```python
388
+ from dddtools import mail
389
+
390
+ # 创建客户端(重复发送时更高效)
391
+ client = mail.create_client(
392
+ username="123456@qq.com",
393
+ password="your授权码",
394
+ smtp_host="smtp.qq.com",
395
+ smtp_port=465
396
+ )
397
+
398
+ # 多次发送
399
+ client.send(
400
+ to_addrs=["user1@example.com"],
401
+ subject="通知1",
402
+ content="内容1"
403
+ )
404
+
405
+ client.send(
406
+ to_addrs=["user2@example.com"],
407
+ subject="通知2",
408
+ content="内容2",
409
+ is_html=True,
410
+ attachments=["file.pdf"]
411
+ )
412
+ ```
413
+
414
+ ### 参数说明
415
+
416
+ | 参数 | 说明 |
417
+ |------|------|
418
+ | `to_addrs` | 收件人列表,支持多个 |
419
+ | `subject` | 邮件主题 |
420
+ | `content` | 邮件内容(普通或HTML) |
421
+ | `is_html` | 是否为HTML格式,默认False |
422
+ | `attachments` | 附件路径列表 |
423
+ | `username` | 发件人邮箱 |
424
+ | `password` | SMTP授权码(不是密码) |
425
+ | `smtp_host` | SMTP服务器,默认 smtp.qq.com |
426
+ | `smtp_port` | SMTP端口,默认 465 |
427
+
428
+ ### QQ邮箱授权码获取
429
+
430
+ 1. 登录 QQ 邮箱
431
+ 2. 进入「设置」→「账户」
432
+ 3. 找到「POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务」
433
+ 4. 开启「POP3/SMTP服务」
434
+ 5. 点击「生成授权码」
435
+
436
+ ---
437
+
438
+ ## HTML模板 (mail.template)
439
+
440
+ ### 8种内置模板
441
+
442
+ | 模板名 | 用途 | 变量 |
443
+ |--------|------|------|
444
+ | `simple` | 基础模板 | `content`, `now` |
445
+ | `notification` | 通知/公告 | `title`, `content`, `button_url`, `button_text`, `highlights` |
446
+ | `verification` | 验证码 | `title`, `description`, `code` |
447
+ | `welcome` | 欢迎邮件 | `username`, `site_name`, `message`, `feature1`, `feature2`, `feature3` |
448
+ | `data_table` | 表格数据 | `title`, `description`, `table_html`, `summary` |
449
+ | `order` | 订单通知 | `username`, `order_no`, `order_time`, `status`, `tracking_no`, `total_amount`, `order_details` |
450
+ | `password_reset` | 密码重置 | `username`, `reset_url`, `expire_time` |
451
+ | `report` | 周报/月报 | `report_title`, `period`, `metrics_html`, `highlights_html`, `notes` |
452
+
453
+ ### 基础用法
454
+
455
+ ```python
456
+ from dddtools.mail.template import render
457
+
458
+ # 渲染模板
459
+ html = render("simple", content="这是一封测试邮件")
460
+ html = render("notification", title="重要通知", content="您的账户已更新")
461
+ ```
462
+
463
+ ### 验证码模板
464
+
465
+ ```python
466
+ from dddtools.mail.template import render, mail
467
+
468
+ html = render(
469
+ "verification",
470
+ title="验证码",
471
+ description="您的验证码如下,请于5分钟内完成验证:",
472
+ code="852741"
473
+ )
474
+
475
+ mail.send_html(
476
+ to_addrs=["user@example.com"],
477
+ subject="验证码",
478
+ html_content=html,
479
+ username="123456@qq.com",
480
+ password="授权码"
481
+ )
482
+ ```
483
+
484
+ ### 订单通知模板
485
+
486
+ ```python
487
+ from dddtools.mail.template import render, mail
488
+
489
+ html = render(
490
+ "order",
491
+ username="张三",
492
+ order_no="DD20260207001",
493
+ order_time="2026-02-07 14:30:00",
494
+ status="已发货",
495
+ tracking_no="SF1234567890",
496
+ total_amount="299.00"
497
+ )
498
+
499
+ mail.send_html(
500
+ to_addrs=["user@example.com"],
501
+ subject="订单已发货",
502
+ html_content=html,
503
+ username="123456@qq.com",
504
+ password="授权码"
505
+ )
506
+ ```
507
+
508
+ ### 数据表格模板
509
+
510
+ ```python
511
+ from dddtools.mail.template import render, mail, make_table_html
512
+
513
+ # 生成表格HTML
514
+ table = make_table_html(
515
+ headers=["姓名", "数学", "语文", "英语"],
516
+ rows=[
517
+ ["张三", 95, 88, 92],
518
+ ["李四", 85, 90, 87],
519
+ ["王五", 92, 85, 94]
520
+ ]
521
+ )
522
+
523
+ html = render(
524
+ "data_table",
525
+ title="期末考试成绩",
526
+ description="本次考试共3人参加",
527
+ table_html=table,
528
+ summary="平均分: 90.2"
529
+ )
530
+ ```
531
+
532
+ ### 指标卡片模板
533
+
534
+ ```python
535
+ from dddtools.mail.template import render, mail, make_metrics_html
536
+
537
+ # 生成指标HTML
538
+ metrics = make_metrics_html({
539
+ "总访问量": {"value": "12,345", "change": "+15%", "type": "up"},
540
+ "新增用户": {"value": "528", "change": "+8%", "type": "up"},
541
+ "转化率": {"value": "3.2%", "change": "-0.5%", "type": "down"},
542
+ "流失率": {"value": "5.1%", "change": "0%", "type": "neutral"}
543
+ })
544
+
545
+ html = render(
546
+ "report",
547
+ report_title="周报",
548
+ period="2026-02-01 ~ 2026-02-07",
549
+ metrics_html=metrics
550
+ )
551
+ ```
552
+
553
+ ### 辅助函数
554
+
555
+ ```python
556
+ from dddtools.mail.template import make_table_html, make_metrics_html, make_highlights_html
557
+
558
+ # 表格
559
+ make_table_html(
560
+ headers=["列1", "列2", "列3"],
561
+ rows=[["a", "b", "c"], ["d", "e", "f"]]
562
+ )
563
+
564
+ # 指标(up=绿色,down=红色,neutral=黑色)
565
+ make_metrics_html({
566
+ "指标名": {"value": "数值", "change": "+10%", "type": "up"}
567
+ })
568
+
569
+ # 亮点列表
570
+ make_highlights_html(["亮点1", "亮点2", "亮点3"])
571
+ ```
572
+
573
+ ### 注册自定义模板
574
+
575
+ ```python
576
+ from dddtools.mail.template import register
577
+
578
+ # 注册模板
579
+ register("newsletter", """
580
+ <!DOCTYPE html>
581
+ <html>
582
+ <body>
583
+ <h1>{{title}}</h1>
584
+ <div>{{content}}</div>
585
+ <footer>unsubscribe at {{unsubscribe_url}}</footer>
586
+ </body>
587
+ </html>
588
+ """)
589
+
590
+ # 使用
591
+ html = render("newsletter", title="新闻简报", content="...", unsubscribe_url="...")
592
+ ```
593
+
594
+ ---
595
+
596
+ ## 缓存管理 (redis)
597
+
598
+ ### 连接管理
599
+
600
+ ```python
601
+ from dddtools import connect, RedisClient
602
+
603
+ # 方式一:使用 connect 函数
604
+ redis = connect(host="localhost", port=6379, db=0, password="your_password")
605
+
606
+ # 方式二:使用连接字符串
607
+ redis = RedisClient(host="redis.example.com", port=6379, password="pass")
608
+
609
+ # 测试连接
610
+ redis.ping() # True/False
611
+
612
+ # 使用原生 Redis 客户端
613
+ redis.client.set("key", "value")
614
+ ```
615
+
616
+ ### 基础操作
617
+
618
+ ```python
619
+ from dddtools import redis
620
+
621
+ r = redis.connect(host="localhost", password="your_password")
622
+
623
+ # 字符串操作
624
+ r.set("name", "张三", ex=3600) # 1小时过期
625
+ value = r.get("name")
626
+
627
+ # 检查存在
628
+ r.exists("name") # 返回数量
629
+
630
+ # 设置过期
631
+ r.expire("name", 1800) # 30秒
632
+ print(r.ttl("name")) # 查看剩余时间
633
+
634
+ # 删除
635
+ r.delete("name")
636
+ ```
637
+
638
+ ### Hash 操作
639
+
640
+ ```python
641
+ r = redis.connect()
642
+
643
+ # 设置 Hash
644
+ r.hset("user:1", "name", "张三")
645
+ r.hset("user:1", "age", "25")
646
+
647
+ # 获取字段
648
+ r.hget("user:1", "name") # "张三"
649
+
650
+ # 获取全部
651
+ r.hgetall("user:1") # {'name': '张三', 'age': '25'}
652
+
653
+ # 删除字段
654
+ r.hdel("user:1", "age")
655
+ ```
656
+
657
+ ### List 操作
658
+
659
+ ```python
660
+ r = redis.connect()
661
+
662
+ # 插入
663
+ r.lpush("queue", "task1", "task2")
664
+ r.rpush("queue", "task3")
665
+
666
+ # 获取
667
+ r.lrange("queue", 0, -1) # ['task2', 'task1', 'task3']
668
+ r.lpop("queue") # 'task2'
669
+ r.llen("queue") # 长度
670
+ ```
671
+
672
+ ### 缓存装饰器
673
+
674
+ ```python
675
+ from dddtools import cache
676
+
677
+ # 简单缓存
678
+ @cache(key="user:{user_id}", expire=600)
679
+ def get_user(user_id: int):
680
+ # 首次调用:执行函数并缓存结果
681
+ return db.query_user(user_id)
682
+ # 后续调用:直接从 Redis 返回缓存
683
+
684
+ # 动态键
685
+ @cache(key="{id}", expire=300)
686
+ def get_data(id: int):
687
+ return api.fetch(id)
688
+
689
+ # 清除缓存
690
+ from dddtools import clear_cache, clear_prefix
691
+
692
+ clear_cache(key="user:123") # 清除单个
693
+ clear_prefix(prefix="cache") # 清除前缀(谨慎)
694
+ ```
695
+
696
+ ### 缓存装饰器参数
697
+
698
+ | 参数 | 类型 | 默认值 | 说明 |
699
+ |------|------|--------|------|
700
+ | `key` | str | 空 | 缓存键,支持 `{func_name}`, `{args[i]}`, `{kwargs[key]}` |
701
+ | `expire` | int | 300 | 过期时间(秒) |
702
+ | `prefix` | str | "cache" | 缓存前缀 |
703
+
704
+ ---
705
+
706
+ ## 加密模块 (encryption)
707
+
708
+ ### AES加密
709
+
710
+ ```python
711
+ from dddtools import AESEncrypt, encrypt_aes, decrypt_aes
712
+
713
+ # 方式一:使用类
714
+ aes = AESEncrypt(key="16位密钥字符串")
715
+ encrypted = aes.encrypt("Hello World")
716
+ decrypted = aes.decrypt(encrypted)
717
+
718
+ # 方式二:快速函数
719
+ encrypted = encrypt_aes("敏感数据", "密钥")
720
+ decrypted = decrypt_aes(encrypted, "密钥")
721
+ ```
722
+
723
+ ### RSA加密
724
+
725
+ ```python
726
+ from dddtools import RSAEncrypt, generate_rsa_keys, encrypt_rsa, decrypt_rsa
727
+
728
+ # 生成密钥对
729
+ private_key, public_key = generate_rsa_keys(key_size=2048)
730
+
731
+ # 加密/解密
732
+ rsa = RSAEncrypt(private_key=private_key, public_key=public_key)
733
+ encrypted = rsa.encrypt("秘密消息")
734
+ decrypted = rsa.decrypt(encrypted)
735
+
736
+ # 快速函数
737
+ encrypted = encrypt_rsa("消息", public_key)
738
+ decrypted = decrypt_rsa(encrypted, private_key)
739
+ ```
740
+
741
+ ### RSA签名/验签
742
+
743
+ ```python
744
+ from dddtools import sign_data, verify_signature
745
+
746
+ # 签名
747
+ private_key = "-----BEGIN RSA PRIVATE KEY-----..."
748
+ signature = sign_data("要签名的数据", private_key, hash_method="sha256")
749
+
750
+ # 验签
751
+ public_key = "-----BEGIN PUBLIC KEY-----..."
752
+ is_valid = verify_signature("要验证的数据", signature, public_key)
753
+ # 返回 True/False
754
+ ```
755
+
756
+ ### 参数说明
757
+
758
+ | 功能 | 参数 | 说明 |
759
+ |------|------|------|
760
+ | `generate_rsa_keys` | key_size | 密钥长度(1024/2048/4096)|
761
+ | `AESEncrypt` | key | 16/24/32字节(对应AES-128/192/256)|
762
+ | `sign_data` | hash_method | 哈希算法(md5/sha1/sha256)|
763
+
764
+ ---
765
+
766
+ ## 文件结构
767
+
768
+ ```
769
+ dddtools/
770
+ ├── pyproject.toml # Python项目配置
771
+ ├── README.md # 本文档
772
+ ├── .gitignore # Git忽略配置
773
+ └── src/dddtools/
774
+ ├── __init__.py # 统一导出所有功能
775
+ ├── logging/ # 日志模块
776
+ │ └── __init__.py # 自动日志、get_logger
777
+ ├── decorator/ # 装饰器
778
+ │ ├── __init__.py # timer, log_call
779
+ │ ├── timer.py # 耗时统计
780
+ │ └── log_call.py # 调用日志
781
+ ├── ftp/ # FTP操作
782
+ │ ├── __init__.py # 导出所有FTP函数
783
+ │ ├── connection.py # 连接管理
784
+ │ ├── list.py # 文件列表
785
+ │ ├── download.py # 下载
786
+ │ ├── upload.py # 上传
787
+ │ └── delete.py # 删除
788
+ ├── mail/ # 邮件发送
789
+ │ ├── __init__.py # send_simple, send_html, send_with_attachment
790
+ │ └── template/ # HTML模板
791
+ │ └── __init__.py # 8种模板 + 辅助函数
792
+ ├── redis/ # 缓存管理
793
+ │ ├── __init__.py # RedisClient, connect, cache, clear_cache
794
+ │ └── decorator.py # 缓存装饰器
795
+ ├── encryption/ # 加密模块
796
+ │ ├── __init__.py # RSAEncrypt, AESEncrypt
797
+ │ ├── rsa.py # RSA加解密、签名验签
798
+ │ └── aes.py # AES加解密
799
+ ├── file/ # (预留) 文件操作
800
+ ├── string/ # (预留) 字符串处理
801
+ ├── system/ # (预留) 系统工具
802
+ └── datetime/ # (预留) 日期时间
803
+ ```
804
+
805
+ ---
806
+
807
+ ## 常见问题
808
+
809
+ ### Q: 日志文件在哪里?
810
+
811
+ 默认在运行目录下创建 `logs` 文件夹。可通过 `get_logger(log_dir="/path")` 自定义。
812
+
813
+ ### Q: 如何更改日志保留天数?
814
+
815
+ ```python
816
+ logger = get_logger(days=30) # 保留30天
817
+ ```
818
+
819
+ ### Q: log_call 如何自定义日志名?
820
+
821
+ ```python
822
+ @log_call(name="MyFunction")
823
+ def my_func(): ...
824
+ ```
825
+
826
+ ### Q: FTP 连接失败?
827
+
828
+ - 检查用户名密码是否正确
829
+ - 检查服务器地址和端口
830
+ - 确保防火墙开放 FTP 端口(21)
831
+ - 尝试使用主动模式:`ftp.connect(...)._ftp.set_pasv(False)`
832
+
833
+ ### Q: QQ 邮箱发送失败?
834
+
835
+ - 确保已开启 POP3/SMTP 服务
836
+ - 使用授权码而非登录密码
837
+ - 确认 SMTP 地址和端口(smtp.qq.com:465)
838
+
839
+ ### Q: 如何调试 log_call?
840
+
841
+ 设置环境变量或查看控制台输出,它会显示参数和返回值。
842
+
843
+ ### Q: 支持异步吗?
844
+
845
+ 当前版本为同步实现。如需异步支持,可使用 `asyncio.to_thread` 包装。
846
+
847
+ ### Q: Redis 连接失败?
848
+
849
+ - 检查 Redis 服务是否启动
850
+ - 确认 host、port、password 是否正确
851
+ - 检查防火墙是否开放 6379 端口
852
+
853
+ ### Q: 缓存装饰器如何动态生成键?
854
+
855
+ ```python
856
+ @cache(key="{user_id}:{page}", expire=300)
857
+ def get_user_posts(user_id: int, page: int):
858
+ return db.query_posts(user_id, page)
859
+ ```
860
+
861
+ ### Q: 如何查看当前缓存?
862
+
863
+ 直接使用 `redis.client.keys("cache:*")` 或 `scan_iter` 遍历。
864
+
865
+ ---
866
+
867
+ ## License
868
+
869
+ MIT License