一个为爬虫设计的强大Python工具集
Project description
MignonFramework 模块文档
本文档为 MignonFramework 中的每一个模块提供了独立的、详细的说明。(基于0.5.2.4版本)
# 下载并使用:
pip install mignonFramework
Logger 模块
简单介绍
Logger 是一个健壮的、高度自动化的日志框架,专为提升开发体验和项目健壮性而设计。它不仅能记录日志到文件,还能自动捕获所有标准输出 (print),并为函数提供开箱即用的异常捕获和日志记录能力。
原理
Logger 的核心原理是 AOP (面向切面编程) 和 流重定向。
- 自动
stdout拦截: 当Logger被启用时,它会用一个自定义的流对象(HOOK)替换掉 Python 内置的sys.stdout。这意味着任何地方调用print(),其输出内容都会被这个自定义对象拦截,然后被格式化成结构化的日志条目,并同时输出到控制台和日志文件。 - AOP 装饰器:
@log装饰器利用 Python 的装饰器特性,将异常捕获和日志记录这段“横切逻辑”动态地“织入”到业务函数中,而无需修改业务函数本身的源代码。 - 线程安全: 所有文件写入操作都使用了
threading.RLock来确保在多线程环境下的数据一致性。 - 日志轮转: 当日志文件达到预设的最大行数时,会自动创建新的日志文件(如
xxx_1.log,xxx_2.log),防止单个文件过大。
使用方法
1. 启用全局自动日志
这是最简单的用法。在你的项目入口处,实例化 Logger 并将 enabled 设置为 True。
from mignonFramework import Logger
# 启用自动日志,所有 print 语句都将被记录
log = Logger(True)
print("这是一条普通信息,它会被自动记录为 INFO 级别的日志。")
2. 使用 @log 装饰器进行异常捕获
对于关键函数,使用 @log 装饰器可以实现自动的异常捕获和详细的 traceback 日志记录。
from mignonFramework import Logger
log = Logger(True)
@log
def calculate(a, b):
print(f"正在计算 {a} / {b}")
result = a / b
return result
# 发生异常,@log 会自动捕获并记录详细错误,然后重新抛出
try:
calculate(10, 0)
except ZeroDivisionError:
print("捕获到预期的异常。")
参数
__init__(self, enabled=False, log_path='./resources/log', name_template='{date}.log')enabled(bool, 可选): 是否启用全局stdout自动拦截。默认为False。log_path(str, 可选): 日志文件存放的目录路径。默认为'./resources/log'。name_template(str, 可选): 日志文件的命名模板,{date}会被替换为当前日期。默认为'{date}.log'。
ConfigReader 模块
简单介绍
ConfigReader 是一个强大且优雅的配置管理引擎,它将 Java Spring 框架中依赖注入 (DI) 和控制反转 (IoC) 的思想带到了 Python 世界。它不仅能读写 .ini 配置文件,还能将配置类作为单例进行管理,并通过 @inject 装饰器实现配置的自动注入和生成。
原理
ConfigReader 的核心是 DI 容器、装饰器 和 Python 描述符。
- DI 容器:
ConfigManager实例扮演了 Spring 中ApplicationContext的角色。它负责创建、管理和提供配置类的单例实例 (getInstance)。 @inject装饰器: 这是一个装饰器工厂,它将一个ConfigManager实例与一个配置类进行绑定。- 自动生成
.ini: 当一个被@inject装饰的类的属性首次被访问时,框架会自动从.ini文件中读取值。如果文件或值不存在,它会根据你在类中定义的默认值,自动将配置项写入.ini文件,然后再返回值。
这个流程实现了“定义即配置”和“首次运行自动生成”的顺滑体验,完美避免了在代码中硬编码。
使用方法
1. 定义配置类并注入
创建一个 Python 类来定义你需要的配置项。你只需要定义,不需要实例化。
# a_config.py
from mignonFramework import ConfigManager, inject
# 1. 创建一个 ConfigManager 实例,指向你的配置文件和节名
db_config_manager = ConfigManager(filename='./resources/db.ini', section='database')
# 2. 定义你的配置类,并使用 @inject 装饰
@inject(db_config_manager)
class DatabaseConfig:
# 3. 定义配置字段,提供类型注解和默认值
# 这些默认值会在首次运行时自动写入 db.ini 文件
host: str = '127.0.0.1'
port: int = 3306
user: str = 'root'
password: str # 没有默认值的字段,会自动写入空值,等待用户填写
db_name: str = 'my_app_db'
# 4. 通过 getInstance 获取配置类的单例
# 首次运行时,如果 db.ini 不存在或不完整,它会被自动创建和填充
db_cfg = db_config_manager.getInstance(DatabaseConfig)
2. 在项目中使用配置
在项目的其他地方,直接导入配置实例即可使用。
# main.py
from a_config import db_cfg
# 访问属性时,会自动从 db.ini 文件读取值
print(f"正在连接到数据库: {db_cfg.host}:{db_cfg.port}")
# 修改配置并自动写回文件
db_cfg.port = 3307 # 赋值操作会自动更新 db.ini 文件
参数
ConfigManager(filename='./resources/config/config.ini', section='config')filename(str, 可选): 配置文件的路径。section(str, 可选): 配置文件中的节 (section) 名称。
inject(manager)manager(ConfigManager): 一个ConfigManager的实例。
MicroserviceByNodeJS 模块
简单介绍
MicroserviceByNodeJS 是 MignonFramework 的创新核心,它提供了一个高性能、持久化的微服务解决方案,专门用于解决 Python 调用复杂、特别是异步 JavaScript 的难题。它通过 C/S (客户端/服务器) 架构,将 JS 的执行放在了其原生的 Node.js 环境中,实现了极致的性能和稳定性。
原理
它的原理是将 JS 的执行环境与 Python 的调用逻辑彻底分离。
- 服务器端:
- 当你创建一个
MicroServiceByNodeJS实例(非client_only模式)时,它会使用 Python 的subprocess模块启动一个常驻的 Node.js 服务器进程 (invoker.js)。 - 这个
invoker.js是一个基于 Express.js 的 打包好的 HTTP 服务器。在启动时,它会自动扫描指定的 JS 目录 (scan_dir) 并一次性将所有 JS 文件作为模块加载到内存中。
- 当你创建一个
- 客户端:
- 它的
invoke方法或@evalJS装饰器会将函数调用转换成一个轻量级的 HTTP POST 请求,发送给 Node.js 服务器。 - Node.js 服务器接收到请求后,在内存中找到对应的、已经编译好的模块和函数,执行它(可以完美处理
async/await),然后将最终结果通过 HTTP 响应返回给 Python 客户端。
- 它的
这个模式通过“一次加载,多次服务”的思想,避免了 execJS 每次调用都需要的进程启动、文件I/O和代码编译的巨大开销。
使用方法
1. 启动 JS 微服务 (文件1)
创建一个独立的 Python 文件来启动并持久化运行 JS 微服务。
# run_js_service.py
from mignonFramework import MicroServiceByNodeJS
# 默认会扫描 ./resources/js 目录下的所有js文件
# 并将它们暴露成API
service_runner = MicroServiceByNodeJS()
print("JavaScript microservice is running...")
# 作为一个独立的服务持久化运行
service_runner.startAsMicro()
2. 在其他项目中调用 (文件2)
在你的主应用或爬虫脚本中,以 client_only 模式连接并调用服务。
# main_scraper.py
from mignonFramework import MicroServiceByNodeJS, ConfigManager, inject
# 使用 ConfigManager 来管理 JS 文件名,避免硬编码
config = ConfigManager()
@inject(config)
class MyConfig:
js_file_name: str = 'h5st_encrypt' # 对应 h5st_encrypt.js
data = config.getInstance(MyConfig)
# 1. 以 client_only=True 模式连接到正在运行的服务
service_client = MicroServiceByNodeJS(client_only=True)
# 2. 使用 @service.evalJS 装饰器,参数从配置中动态读取
@service_client.evalJS(data.js_file_name)
def get_h5st(params):
return ""
# 3. 像调用普通 Python 函数一样调用它
if __name__ == "__main__":
encrypted_data = get_h5st({"key": "value"})
print(f"从 JS 微服务获取到的加密结果: {encrypted_data}")
# 当然, 也可以合并启用
# main_scraper.py
from mignonFramework import MicroServiceByNodeJS, ConfigManager, inject
# 使用 ConfigManager 来管理 JS 文件名,避免硬编码
config = ConfigManager()
@inject(config)
class MyConfig:
js_file_name: str = 'h5st_encrypt' # 对应 h5st_encrypt.js
data = config.getInstance(MyConfig)
# 1. 以 client_only=True 模式连接到正在运行的服务
service_client = MicroServiceByNodeJS()
# 2. 使用 @service.evalJS 装饰器,参数从配置中动态读取
@service_client.evalJS(data.js_file_name)
def get_h5st(params):
return ""
# 3. 像调用普通 Python 函数一样调用它
if __name__ == "__main__":
encrypted_data = get_h5st({"key": "value"})
print(f"从 JS 微服务获取到的加密结果: {encrypted_data}")
参数
__init__(self, client_only=False, port=3000, url_base="127.0.0.1", scan_dir="./resources/js", ...)client_only(bool, 可选): 是否只作为客户端连接一个已存在的服务。默认为False。port(int, 可选): Node.js 服务监听的端口。url_base(str, 可选): Node.js 服务的 IP 地址或域名。scan_dir(str, 可选): (仅服务端模式) Node.js 服务启动时要扫描的 JS 模块目录。
Queues 模块(QueueIter)
简单介绍
QueueIter 是一个灵活、可重用、支持装饰器配置和随机种子的爬取队列生成器。它非常适合用于爬虫或任何需要分批处理任务的场景,并提供了强大的流程控制和任务编排能力。
原理
QueueIter 本质上是一个线程安全的、可动态配置的迭代器。
- 动态配置: 队列的核心属性(如
pages任务列表,current_index当前进度)都设计为 Pythonproperty,允许在运行时安全地修改。 - 任务终结与编排 (
@target):@target装饰器与ConfigManager联动。它允许你注册一个“终结任务”,当队列迭代完成时,会自动执行这个任务,例如修改某个配置类的属性。这是一种非常优雅的跨对象状态管理和任务编排方式。 - 同时QueueIter只要seed固定, 生成的顺序虽然打乱, 但每次生成的顺序一定相同, 因此, 在断点续爬的过程中需要通过current_index来控制
使用方法
1. 基本用法
from mignonFramework import QueueIter
# 创建一个从 1 到 100 的任务队列,并打乱顺序
task_queue = QueueIter(pages=range(1, 101), shuffle=True)
while task_queue.hasNext():
page_number = next(task_queue)
print(f"正在处理页面: {page_number}")
2. 使用 @target 进行任务编排
当一个队列跑完后,自动修改另一个配置。
from mignonFramework import QueueIter, target, ConfigManager, inject
config = ConfigManager(section='SpiderState')
user_queue = QueueIter(pages=range(1, 51), config_manager=config)
# 使用 @target 装饰器,定义一个终结任务
# 当 user_queue 跑完后,会自动将 SpiderState 的 current_task 属性值改为 'products'
@target(user_queue, 'current_task', 'products')
@inject(config)
class SpiderState:
current_task: str = 'users'
state = config.getInstance(SpiderState)
while user_queue.hasNext():
user_id = next(user_queue)
print(f"处理用户 {user_id}, 当前任务: {state.current_task}")
# 循环结束后
print(f"用户队列处理完毕, 下一个任务是: {state.current_task}") # 输出: products
参数
__init__(self, config_manager=None, shuffle=True, callback=None, pages=range(0, 1), ...)config_manager(ConfigManager, 可选): 一个ConfigManager实例,在使用@target功能时必需。shuffle(bool, 可选): 是否在初始化时打乱pages列表的顺序。pages(list或range, 可选): 包含所有任务的列表或range对象。seed(int, 可选): 用于随机数生成的种子,以确保每次打乱的顺序一致。
GenericProcessor 模块 (InsertQuick)
简单介绍
GenericFileProcessor (别名 InsertQuick) 是框架的ETL心脏。它是一个高度可定制的、通用的逐行JSON文件处理器,用于将文件内容批量写入指定目标(如数据库)。它支持零配置启动、交互式的Eazy Mode和强大的行级错误处理与恢复机制。
原理
GenericProcessor 的核心是一个可定制的数据处理流水线 (Pipeline)。
- 写入器抽象 (
BaseWriter): 它不关心数据最终写到哪里。它依赖于一个实现了BaseWriter接口的writer对象(如MysqlManager),这使得它的输出端是完全可插拔的。 - 强大的错误恢复: 当
upsert_batch批量写入失败时,它不会直接崩溃,而是自动降级为逐行恢复模式。在逐行模式下,它会精确定位到出错的行和数据,并提供交互式选项或全自动跳过。 - 零配置与自动生成INI: 如果在初始化时不提供
writer或table_name,它会自动查找generic.ini配置文件。如果文件或配置项不存在,它会自动生成一个带注释的模板文件,引导用户填写数据库连接信息和表名。
使用方法
1. 零配置启动 (推荐)
你不需要在代码里写任何数据库连接信息。
# main.py
from mignonFramework import InsertQuick
# 1. 直接实例化,不传入任何参数
# 它会自动寻找 ./resources/config/generic.ini
processor = InsertQuick()
# 2. 运行
# 首次运行时,如果 generic.ini 不存在,它会被自动创建
# 你只需要去文件里填写好数据库信息和表名,然后再次运行即可
processor.run()
2. 高级用法:自定义数据转换
from mignonFramework import InsertQuick, Rename
# 定义一个修改器函数
def modify_user_data(data_dict):
return {
'user_id': Rename('id'), # 将 'user_id' 重命名为 'id'
'fullName': (data_dict.get('firstName', '') + ' ' + data_dict.get('lastName', ''))
}
# 同样使用零配置方式初始化
processor = InsertQuick(
modifier_function=modify_user_data,
exclude_keys=['firstName', 'lastName']
)
processor.run()
3. EAZY_MODE(极为推荐)
# 使用方法
from mignonFramework import InsertQuick
InsertQuick(eazy=True).run("./文件路径")
# 即可启动内部Flask, 随机抽取行做解析, 粘贴DDL即可一键生成inclue_key等代码, 极为迅速
参数
__init__(self, writer=None, table_name=None, modifier_function=None, ...)writer(BaseWriter, 可选): 写入器实例。推荐不传,让框架自动从配置文件加载。table_name(str, 可选): 目标表名。推荐不传,让框架自动从配置文件加载。modifier_function(Callable, 可选): 一个接收原始数据字典、返回修改指令字典的函数。filter_function(Callable, 可选): 一个接收原始数据字典和行号、返回bool值的函数。返回False则跳过该行。exclude_keys(list, 可选): 需要排除的原始键名列表。include_keys(list, 可选): “白名单”,只有这些**目标键名(snake_case)**才会被保留。eazy(bool, 可选): 是否启动 。auto_skip_error(bool, 可选): 在逐行恢复模式中,是否自动跳过错误行。
MySQLManager 模块
简单介绍
MySQLManager 是一个线程安全、带自动重连和高效 UPSERT 功能的MySQL数据库管理器。它是 BaseWriter 接口的官方实现,专门设计用来与 GenericProcessor 无缝协作。
原理
- 线程安全: 使用
threading.local()为每个线程创建独立的数据库连接,避免了多线程操作同个连接导致的常见问题。 - 自动重连: 在执行操作前会检查连接是否断开,如果断开则会自动尝试重连,增加了长时间运行任务的稳定性。
- 高效的
UPSERT: 它能智能地构建INSERT ... ON DUPLICATE KEY UPDATE语句,实现了高效的数据写入和更新操作。
使用方法
MySQLManager 主要被设计为在 GenericProcessor 内部通过配置文件自动初始化,用户通常不需要手动实例化它。但如果需要独立使用,方法如下:
from mignonFramework import MysqlManager
# 不推荐在代码中硬编码,这里仅作演示
db_config = {
'host': 'localhost',
'user': 'root',
'password': 'password',
'database': 'my_db',
'port': 3306
}
db_manager = MysqlManager(**db_config)
if db_manager.is_connected():
users_to_insert = [
{'id': 1, 'name': 'Alice', 'age': 30},
{'id': 2, 'name': 'Bob', 'age': 25}
]
# 批量写入
db_manager.upsert_batch(users_to_insert, 'users')
# 单条写入
db_manager.upsert_single({'id': 3, 'name': 'Charlie', 'age': 35}, 'users')
db_manager.close()
参数
__init__(self, host, user, password, database, port=3306, **kwargs)host,user,password,database,port: 标准的MySQL连接参数。
ProcessFile 模块
简单介绍
ProcessFile 是一个开箱即用的文件批处理引擎,内置了基于SQLite或文件移动的状态管理,实现了可靠的**“断点续传”**功能。它的任务是持续不断地监控一个目录,将文件进行解析、转换,并追加写入到大型结果文件中。
原理
- 配置驱动: 整个流程完全由一个独立的
.ini配置文件驱动。 - 自动生成INI: 如果配置文件不存在,它会自动生成一个带详细注释的模板文件,引导用户填写输入/输出路径等信息。
- 双模式状态管理:
- config 模式: 使用
SQLiteStateTracker,通过数据库来记录每个文件的处理状态(成功、失败),适合需要持久化和可查询记录的场景, 缺点是如果自己想记录的话还需要查。 - move 模式: 使用
MoveStateTracker,通过物理移动文件到finish或exception目录来标记状态,简单直观, 缺点是慢,即时有异步的支持IO操作也很巨大。
- config 模式: 使用
- 异步核心: 文件的读写操作使用了
aiofiles和asyncio,在处理大量小文件时能提供更好的 I/O 性能。
使用方法
你几乎不需要写任何Python代码来使用它。
-
创建启动脚本:
# run_process.py from mignonFramework import processRun # 指定你的配置文件路径,然后运行 processRun(config_path='./resources/config/processFile.ini') -
运行与配置:
- 第一次运行
python run_process.py。 - 程序会提示配置缺失,并自动在
./resources/config/目录下创建一个processFile.ini文件。 - 打开
processFile.ini,根据里面的注释填写你的输入目录 (input_dir) 和输出目录 (output_dir)。 - 再次运行
python run_process.py,处理流程就会自动开始。
- 第一次运行
参数
run(config_path: str = './resources/config/processFile.ini')config_path(str, 可选): 指向该模块专属配置文件的路径。
execJSTo 模块
简单介绍
execJSTo 提供了一个极其优雅的装饰器 @execJS,通过智能的参数签名“翻译”,实现了Python函数到同步JS函数的无缝代理调用。它是处理同步、无I/O、纯计算型JS逻辑的最轻量、最便捷的方案。
原理
@execJS 装饰器在 PyExecJS 库的基础上,构建了一个智能的、声明式的调用层。本质还是AOP.
- 参数签名“翻译”: 它利用 Python 的
inspect模块去分析你装饰的 Python 函数的签名。这使得它可以正确处理位置参数和关键字参数,并自动按照 JS 函数期望的顺序来传递。 - 声明式编程: 它将一个命令式的调用(
ctx.call(...))转换成了一个声明式的注解(@execJS(...))。开发者只需要“声明”这个 Python 函数对应哪个 JS 文件,剩下的所有细节(文件读取、编译、参数绑定、执行)都由装饰器自动完成。
使用方法
from mignonFramework import execJS
# 假设有一个 crypto.js 文件:
# function encrypt(data, key) { ... return encrypted_data; }
# 1. 使用 @execJS 装饰一个函数,参数为JS文件路径
@execJS('./resources/js/crypto.js')
def encrypt(data, key):
# 2. Python 函数体不会被执行
# 它的签名 (参数) 会被用来调用 JS 函数
pass
# 3. 像调用普通Python函数一样调用它
# 关键字参数和位置参数都能被正确处理
encrypted_text = encrypt(data="hello", key="secret")
print(encrypted_text)
# 也可以指定JS函数名
@execJS('./resources/js/crypto.js', js_function_name='decrypt_data')
def decrypt(text):
pass
参数
execJS(js_file_path: str, js_function_name: str = None)js_file_path(str): 目标 JavaScript 文件的路径。js_function_name(str, 可选): 要调用的 JavaScript 函数名。如果为None,则默认使用被装饰的 Python 函数的名称。
getJSONequals 模块
简单介绍
getJSONequals (别名 jsonContrast) 是一个强大的JSON对比工具
原理
- 对于不标准的JSON也能够处理, 以及会将Object转为String做比较
使用方法
在Android逆向和Web逆向中, 难免会遇到很难识别出不同的JSON数据
from mignonFramework import jsonContrast
test1 = {
"a":"b",
"c":"d",
"e":"f"
}
test2 = {
"a":"b",
"c":"d",
"e":"f"
}
jsonContrast(test2,test1)
# 此时自动打印
参数
-
jsonContrast(json1, json2)-
json1(dict): 原始的JSON数据1。 -
*
json2(dict): 原始的JSON数据2。
-
辅助工具模块
mignonFramework_starter 模块
-
简单介绍: 框架的可视化Web UI启动器。它通过
start()函数启动一个本地 Flask Web 服务器,集成了代码生成、cURL转换 等多种高效开发工具,是 MignonFramework “开发者友好”理念的最终体现。 -
使用方法:
from mignonFramework import start # 启动 Web UI,默认监听 5001 端口 start()
Curl2Request 模块
-
简单介绍: 一个实用的开发者工具,能将从浏览器开发者工具复制的cURL命令字符串自动转换为等效的、格式化好的Python
requests代码。 -
使用方法:
from mignonFramework import Curl2Request curl_command = 'curl "http://example.com" -H "User-Agent: my-agent"' converter = Curl2Request(curl_command) python_code = converter.get_requests_code() print(python_code)
Deduplicate 模块
-
简单介绍: 提供了内存高效的大文件去重功能,以及复制、替换指定行的原子操作,是
GenericProcessor的完美数据调试搭档。 -
使用方法:
from mignonFramework import deduplicateFile, copyLineByNumber # 对大文件进行去重 deduplicateFile('./data/large_log.txt', mode='chunk') # 复制文件的第 123 行到新文件 copyLineByNumber('./data/source.txt', 123, './data/line_123.txt')
SqlDDL2List 模块
-
简单介绍: 一个精准的SQL DDL解析器,能从
CREATE TABLE语句中提取表结构信息(字段名、类型、约束等),是GenericProcessorEazy Mode 智能化的重要支撑。 -
使用方法:
from mignonFramework import extractDDL2List ddl_string = """ CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ); """ columns = extractDDL2List(ddl_string) # columns -> [('id', 'int(11)', 'NOT NULL', None), ('name', 'varchar(255)', '', 'NULL'), ...] print(columns)
PortForwarding 模块
-
简单介绍: 一个简洁可靠的TCP端口转发工具,用于网络抓包和流量分析。
-
使用方法:
from mignonFramework import portForwordRun # 将本地 8080 端口的流量转发到 example.com 的 80 端口 services = [ ('0.0.0.0', 8080, 'example.com', 80) ] portForwordRun(services)
CountLinesInFolder 模块
-
简单介绍: 提供了一系列高效的函数,用于统计单个文件、多个文件或整个目录(支持递归和正则匹配)的代码行数。
-
使用方法:
from mignonFramework import countSingleFileLines, countDirectoryFileLines # 统计单个文件行数 lines = countSingleFileLines('my_script.py') print(f"文件行数: {lines}") # 统计整个项目(.py文件)的总行数 total_lines = countDirectoryFileLines('.', file_regex=r'.*\.py$') print(f"项目总行数: {total_lines}")DatabaseTransfer 模块 简单介绍 DatabaseTransfer 是一个为解决复杂数据迁移需求而设计的高性能、可插拔的数据库迁移引擎。它内置了**“游标分页”和断点续传机制,能够高效、稳定地处理海量数据。其最大的亮点是集成了 Eazy Mode,通过可视化的 Web 界面,将繁琐的配置过程简化为几次点击,真正实现“一键迁移”**。
原理 DatabaseTransfer 的设计哲学是**“配置优于编码,抽象优于实现”**。
可插拔的迁移核心 (AOP): 框架通过 AbstractDatabaseTransfer 抽象基类定义了迁移的完整生命周期(连接、获取表、复制结构、传输数据)。所有具体的迁移任务(如 MySQLToMySQLTransfer)都是这个抽象的实现。这使得框架的核心逻辑与具体数据库解耦,未来可以轻松扩展支持 PostgreSQL、Oracle 等,实现了真正的“可插拔”。
配置驱动与状态持久化: 整个迁移过程由一个 dataBaseTransfer.json 文件精确控制。这个文件不仅定义了源和目标的连接信息,还实时记录了迁移进度(如 alreadyFinished, nowTitle, nowLastId)。这种设计使得迁移任务可以随时中断和恢复,保证了长时间任务的稳定性。
高效的游标分页: 针对大数据表,它摒弃了低效的 OFFSET 分页,采用 WHERE id > last_id ORDER BY id LIMIT batch_size 的方式进行批处理。这极大地提升了查询效率,并且是实现断点续传的关键。
健壮的错误恢复机制: 当批量写入 (upsert_batch) 遇到脏数据而失败时,系统不会直接崩溃。它会自动降级为逐行恢复模式,精确定位到出错的数据行,并提供交互式选项(跳过、中止)或根据配置自动跳过,最大程度地保障了迁移任务的顺利完成。
Eazy Mode (Web UI): 模块内置了一个轻量级的 Flask Web 应用。它为用户提供了一个直观的图形界面,用于测试数据库连接、获取和选择数据表、配置过滤规则,并最终自动生成格式正确的 dataBaseTransfer.json 配置文件。这极大地降低了使用门槛。
使用方法
- Eazy Mode (强烈推荐) 这是最简单、最快捷的方式。你只需要一个启动脚本。
# run_transfer_ui.py
from mignonFramework.utils.dataBaseTransfer import DatabaseTransferRunner
# 以 Eazy Mode 启动,这将开启一个本地 Web 服务器
# 它会自动寻找或创建 ./resources/config/dataBaseTransfer.json
runner = DatabaseTransferRunner(eazy=True)
runner.run()
# 运行后,访问 http://127.0.0.1:5001 即可开始可视化配置
- 标准模式 (配置完成后) 当你通过 Eazy Mode 生成了 dataBaseTransfer.json 文件后,就可以使用标准模式来执行迁移任务。
# run_migration.py
from mignonFramework.utils.dataBaseTransfer import DatabaseTransferRunner, MySQLToMySQLTransfer
# 以标准模式启动
runner = DatabaseTransferRunner(eazy=False)
# 加载配置并开始迁移
# 你也可以在这里替换成其他迁移实现类
runner.run(transfer_class=MySQLToMySQLTransfer)
参数 DatabaseTransferRunner(config_path: str = None, eazy: bool = False)
config_path (str, 可选): 迁移配置文件的路径。默认为 './resources/config/dataBaseTransfer.json'。
eazy (bool, 可选): 是否启动 Eazy Mode 可视化配置界面。默认为 False。
runner.run(transfer_class: Type[AbstractDatabaseTransfer] = MySQLToMySQLTransfer)
transfer_class (可选): 指定用于迁移的实现类。默认为 MySQLToMySQLTransfer。
JsonConfigManager 模块 简单介绍 JsonConfigManager 是一个将响应式编程和依赖注入思想融入JSON配置管理的强大工具。它通过一个巧妙的代理层,让你能够以操作普通 Python 对象属性的方式来读写 JSON 文件,并且任何修改都会自动、原子性地、线程安全地写回磁盘。它彻底告别了繁琐的 json.load() 和 json.dump()。
原理 JsonConfigManager 的核心是**“配置即对象,操作即保存”**。
动态代理 (_ConfigObject & _ConfigList): 当你调用 manager.getInstance() 时,得到的不是一个普通的字典,而是一个_ConfigObject代理对象。这个代理对象封装了真实的配置数据。
属性访问拦截: 代理对象通过重写 getattr 和 setattr Python魔法方法,拦截了所有的属性访问。
当你读取属性 (config.db.host),getattr 会在内部的字典中查找对应的值。如果值是字典或列表,它会递归地将其也包装成代理对象。
当你写入属性 (config.db.port = 3307),setattr 不仅会更新内部字典,还会立即调用一个回调函数,这个回调函数就是 manager._save 方法。
自动持久化: 正是因为 setattr 和列表修改方法(如 append)都绑定了保存回调,所以你对配置对象的任何改动都会被立刻、自动地持久化到 .json 文件中。
线程安全: 所有的文件读写操作都被 threading.RLock 保护,确保了在多线程环境下配置文件的完整性和一致性。
依赖注入 (@injectJson): 模块提供了一个装饰器工厂,可以像 Spring 框架一样,将一个 JsonConfigManager 实例“注入”到一个配置类定义中,使其在被“实例化”时自动返回配置代理对象,进一步简化了代码。
使用方法
- 定义配置模板并获取实例
# my_config.py
from mignonFramework.utils.config.JsonlConfigReader import JsonConfigManager
# (推荐) 定义一个与JSON结构对应的类,以获得更好的IDE提示和代码可读性
class AppConfig:
host: str
port: int
users: list
# 1. 创建一个 manager 实例,指向你的配置文件
config_manager = JsonConfigManager(filename='./resources/config/app_settings.json')
# 2. 获取配置的实时代理对象
# 如果文件不存在,会自动创建一个空的 "{}"
app_cfg = config_manager.getInstance(AppConfig)
- 在项目中使用配置 现在,你可以像操作普通对象一样操作 app_cfg,所有变更都会自动保存。
# main.py
from my_config import app_cfg
# 像访问对象属性一样读取配置
print(f"Server is running on {app_cfg.host}:{app_cfg.port}")
# 修改配置,这一步会自动将更改写入 app_settings.json 文件
app_cfg.port = 8080
print("Port has been updated.")
# 即使是列表操作,也会被自动保存
app_cfg.users.append("new_user")
print("New user added.")
参数 JsonConfigManager(filename: str = "./resources/config/config.json")
filename (str, 可选): JSON 配置文件的路径。如果路径或文件不存在,将会被自动创建。
injectJson(manager: JsonConfigManager)
manager (JsonConfigManager): 一个 JsonConfigManager 的实例,用于装饰器注入。
PrintDirectoryTree 模块 简单介绍 PrintDirectoryTree 是一个简洁而实用的开发辅助工具,用于在控制台中以美观的树状结构递归地打印出指定目录的内容。对于需要快速可视化项目结构、或为文档生成目录列表的场景,这是一个非常方便的小工具。
原理 它的实现优雅地利用了递归和迭代状态判断。
递归遍历: 核心函数 print_directory_tree 会检查路径下的每一个项目。如果项目是文件夹,它就会以更新后的缩进级别再次调用自身,从而实现深度遍历。
前缀智能判断: 为了生成 ├── 和 └── 这样清晰的树状连接线,函数在遍历一个目录之前,会先获取该目录下所有条目的列表。在循环内部,通过 enumerate 判断当前处理的条目是否是列表中的最后一项。
如果是最后一项,就使用 └── 作为前缀。
如果不是,就使用 ├── 作为前缀。 这个简单的“向前看”逻辑,是生成美观树状结构的关键。
使用方法 使用方法极其简单,只需导入并调用函数即可。
from mignonFramework.utils.utilClass.printDirectoryTree import print_directory_tree
# 定义你想要打印的目录路径
target_path = './MignonFramework'
# 调用函数
print(f"项目 '{target_path}' 的目录结构如下:")
print_directory_tree(target_path)
输出示例:
项目 './MignonFramework' 的目录结构如下:
├── resources
│ └── config
│ └── dataBaseTransfer.json
├── utils
│ ├── dataBaseTransfer.py
│ ├── JsonlConfigReader.py
│ └── printDirectoryTree.py
└── README.md
参数 print_directory_tree(path, indent=0)
path (str): 要遍历并打印的起始目录路径。
indent (int, 可选): 内部用于递归的缩进级别。通常用户无需手动设置此参数。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mignonframework-0.5.3.9.tar.gz.
File metadata
- Download URL: mignonframework-0.5.3.9.tar.gz
- Upload date:
- Size: 762.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d64047ffedb48a947a8da78122381dab9af8f98e639f3616c2bce8dcb0c7cd36
|
|
| MD5 |
4dfca3016856ece3365939e84f447548
|
|
| BLAKE2b-256 |
9ad5af963ed0941bba18e7e748319bf0842f57b594b54cc721703c8b9d0d0834
|
File details
Details for the file mignonframework-0.5.3.9-py3-none-any.whl.
File metadata
- Download URL: mignonframework-0.5.3.9-py3-none-any.whl
- Upload date:
- Size: 773.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed433165ab5fab2ffbff051e6c8b7c29a48609c73d61d961676c6ad02642a09d
|
|
| MD5 |
ee7e3d6953c5a0bc265ef0731c265340
|
|
| BLAKE2b-256 |
98931c5096c597e0966fc2afad1b4ee62d784de2f8b56f7295edae75d31c7208
|