ruff: 清理代码并规范导入顺序

对整个代码库进行了大规模的清理和重构,主要包括:
- 统一并修复了多个文件中的 `import` 语句顺序,使其符合 PEP 8 规范。
- 移除了大量未使用的导入和变量,减少了代码冗余。
- 修复了多处代码风格问题,例如多余的空行、不一致的引号使用等。
- 简化了异常处理逻辑,移除了不必要的 `noqa` 注释。
- 在多个文件中使用了更现代的类型注解语法(例如 `list[str]` 替代 `List[str]`)。
This commit is contained in:
minecraft1024a
2025-10-05 20:38:56 +08:00
parent 2908cfead1
commit 7a7f737f71
20 changed files with 163 additions and 171 deletions

152
bot.py
View File

@@ -1,22 +1,20 @@
# import asyncio
import asyncio
import os
import platform
import sys
import time
import platform
import traceback
from pathlib import Path
from contextlib import asynccontextmanager
import hashlib
from typing import Optional, Dict, Any
from pathlib import Path
# 初始化基础工具
from colorama import init, Fore
from colorama import Fore, init
from dotenv import load_dotenv
from rich.traceback import install
# 初始化日志系统
from src.common.logger import initialize_logging, get_logger, shutdown_logging
from src.common.logger import get_logger, initialize_logging, shutdown_logging
# 初始化日志和错误显示
initialize_logging()
@@ -24,7 +22,7 @@ logger = get_logger("main")
install(extra_lines=3)
# 常量定义
SUPPORTED_DATABASES = ['sqlite', 'mysql', 'postgresql']
SUPPORTED_DATABASES = ["sqlite", "mysql", "postgresql"]
SHUTDOWN_TIMEOUT = 10.0
EULA_CHECK_INTERVAL = 2
MAX_EULA_CHECK_ATTEMPTS = 30
@@ -37,18 +35,18 @@ logger.info("工作目录已设置")
class ConfigManager:
"""配置管理器"""
@staticmethod
def ensure_env_file():
"""确保.env文件存在如果不存在则从模板创建"""
env_file = Path(".env")
template_env = Path("template/template.env")
if not env_file.exists():
if template_env.exists():
logger.info("未找到.env文件正在从模板创建...")
try:
env_file.write_text(template_env.read_text(encoding='utf-8'), encoding='utf-8')
env_file.write_text(template_env.read_text(encoding="utf-8"), encoding="utf-8")
logger.info("已从template/template.env创建.env文件")
logger.warning("请编辑.env文件将EULA_CONFIRMED设置为true并配置其他必要参数")
except Exception as e:
@@ -64,23 +62,23 @@ class ConfigManager:
env_file = Path(".env")
if not env_file.exists():
return False
# 检查文件大小
file_size = env_file.stat().st_size
if file_size == 0 or file_size > MAX_ENV_FILE_SIZE:
logger.error(f".env文件大小异常: {file_size}字节")
return False
# 检查文件内容是否包含必要字段
try:
content = env_file.read_text(encoding='utf-8')
if 'EULA_CONFIRMED' not in content:
content = env_file.read_text(encoding="utf-8")
if "EULA_CONFIRMED" not in content:
logger.error(".env文件缺少EULA_CONFIRMED字段")
return False
except Exception as e:
logger.error(f"读取.env文件失败: {e}")
return False
return True
@staticmethod
@@ -90,7 +88,7 @@ class ConfigManager:
if not ConfigManager.verify_env_file_integrity():
logger.error(".env文件完整性验证失败")
return False
load_dotenv()
logger.info("环境变量加载成功")
return True
@@ -100,44 +98,44 @@ class ConfigManager:
class EULAManager:
"""EULA管理类"""
@staticmethod
async def check_eula():
"""检查EULA和隐私条款确认状态"""
confirm_logger = get_logger("confirm")
if not ConfigManager.safe_load_dotenv():
confirm_logger.error("无法加载环境变量EULA检查失败")
sys.exit(1)
eula_confirmed = os.getenv('EULA_CONFIRMED', '').lower()
if eula_confirmed == 'true':
eula_confirmed = os.getenv("EULA_CONFIRMED", "").lower()
if eula_confirmed == "true":
logger.info("EULA已通过环境变量确认")
return
# 提示用户确认EULA
confirm_logger.critical("您需要同意EULA和隐私条款才能使用MoFox_Bot")
confirm_logger.critical("请阅读以下文件:")
confirm_logger.critical(" - EULA.md (用户许可协议)")
confirm_logger.critical(" - PRIVACY.md (隐私条款)")
confirm_logger.critical("然后编辑 .env 文件,将 'EULA_CONFIRMED=false' 改为 'EULA_CONFIRMED=true'")
attempts = 0
while attempts < MAX_EULA_CHECK_ATTEMPTS:
try:
await asyncio.sleep(EULA_CHECK_INTERVAL)
attempts += 1
# 重新加载环境变量
ConfigManager.safe_load_dotenv()
eula_confirmed = os.getenv('EULA_CONFIRMED', '').lower()
if eula_confirmed == 'true':
eula_confirmed = os.getenv("EULA_CONFIRMED", "").lower()
if eula_confirmed == "true":
confirm_logger.info("EULA确认成功感谢您的同意")
return
if attempts % 5 == 0:
confirm_logger.critical(f"请修改 .env 文件中的 EULA_CONFIRMED=true (尝试 {attempts}/{MAX_EULA_CHECK_ATTEMPTS})")
except KeyboardInterrupt:
confirm_logger.info("用户取消,程序退出")
sys.exit(0)
@@ -146,43 +144,43 @@ class EULAManager:
if attempts >= MAX_EULA_CHECK_ATTEMPTS:
confirm_logger.error("达到最大检查次数,程序退出")
sys.exit(1)
confirm_logger.error("EULA确认超时程序退出")
sys.exit(1)
class TaskManager:
"""任务管理器"""
@staticmethod
async def cancel_pending_tasks(loop, timeout=SHUTDOWN_TIMEOUT):
"""取消所有待处理的任务"""
remaining_tasks = [
t for t in asyncio.all_tasks(loop)
t for t in asyncio.all_tasks(loop)
if t is not asyncio.current_task(loop) and not t.done()
]
if not remaining_tasks:
logger.info("没有待取消的任务")
return True
logger.info(f"正在取消 {len(remaining_tasks)} 个剩余任务...")
# 取消任务
for task in remaining_tasks:
task.cancel()
# 等待任务完成
try:
results = await asyncio.wait_for(
asyncio.gather(*remaining_tasks, return_exceptions=True),
asyncio.gather(*remaining_tasks, return_exceptions=True),
timeout=timeout
)
# 检查任务结果
for i, result in enumerate(results):
if isinstance(result, Exception):
logger.warning(f"任务 {i} 取消时发生异常: {result}")
logger.info("所有剩余任务已成功取消")
return True
except asyncio.TimeoutError:
@@ -208,30 +206,30 @@ class TaskManager:
class ShutdownManager:
"""关闭管理器"""
@staticmethod
async def graceful_shutdown(loop=None):
"""优雅关闭程序"""
try:
logger.info("正在优雅关闭麦麦...")
start_time = time.time()
# 停止异步任务
tasks_stopped = await TaskManager.stop_async_tasks()
# 取消待处理任务
tasks_cancelled = True
if loop and not loop.is_closed():
tasks_cancelled = await TaskManager.cancel_pending_tasks(loop)
shutdown_time = time.time() - start_time
success = tasks_stopped and tasks_cancelled
if success:
logger.info(f"麦麦优雅关闭完成,耗时: {shutdown_time:.2f}")
else:
logger.warning(f"麦麦关闭完成,但部分操作未成功,耗时: {shutdown_time:.2f}")
return success
except Exception as e:
@@ -264,29 +262,29 @@ async def create_event_loop_context():
class DatabaseManager:
"""数据库连接管理器"""
def __init__(self):
self._connection = None
async def __aenter__(self):
"""异步上下文管理器入口"""
try:
from src.common.database.database import initialize_sql_database
from src.config.config import global_config
logger.info("正在初始化数据库连接...")
start_time = time.time()
# 使用线程执行器运行潜在的阻塞操作
await asyncio.to_thread(initialize_sql_database, global_config.database)
elapsed_time = time.time() - start_time
logger.info(f"数据库连接初始化成功,使用 {global_config.database.database_type} 数据库,耗时: {elapsed_time:.2f}")
return self
except Exception as e:
logger.error(f"数据库连接初始化失败: {e}")
raise
async def __aexit__(self, exc_type, exc_val, exc_tb):
"""异步上下文管理器出口"""
if exc_type:
@@ -295,34 +293,34 @@ class DatabaseManager:
class ConfigurationValidator:
"""配置验证器"""
@staticmethod
def validate_configuration():
"""验证关键配置"""
try:
from src.config.config import global_config
# 检查必要的配置节
required_sections = ['database', 'bot']
required_sections = ["database", "bot"]
for section in required_sections:
if not hasattr(global_config, section):
logger.error(f"配置中缺少{section}配置节")
return False
# 验证数据库配置
db_config = global_config.database
if not hasattr(db_config, 'database_type') or not db_config.database_type:
if not hasattr(db_config, "database_type") or not db_config.database_type:
logger.error("数据库配置缺少database_type字段")
return False
if db_config.database_type not in SUPPORTED_DATABASES:
logger.error(f"不支持的数据库类型: {db_config.database_type}")
logger.info(f"支持的数据库类型: {', '.join(SUPPORTED_DATABASES)}")
return False
logger.info("配置验证通过")
return True
except ImportError:
logger.error("无法导入全局配置模块")
return False
@@ -332,16 +330,16 @@ class ConfigurationValidator:
class EasterEgg:
"""彩蛋功能"""
_initialized = False
@classmethod
def show(cls):
"""显示彩色文本"""
if not cls._initialized:
init()
cls._initialized = True
text = "多年以后面对AI行刑队张三将会回想起他2023年在会议上讨论人工智能的那个下午"
rainbow_colors = [Fore.RED, Fore.YELLOW, Fore.GREEN, Fore.CYAN, Fore.BLUE, Fore.MAGENTA]
rainbow_text = ""
@@ -394,27 +392,27 @@ class MaiBotMain:
"""执行同步初始化步骤"""
self.setup_timezone()
await EULAManager.check_eula()
if not ConfigurationValidator.validate_configuration():
raise RuntimeError("配置验证失败,请检查配置文件")
return self.create_main_system()
async def run_async_init(self, main_system):
"""执行异步初始化步骤"""
# 初始化数据库连接
await self.initialize_database()
# 初始化数据库表结构
await self.initialize_database_async()
# 初始化主系统
await main_system.initialize()
# 初始化知识库
from src.chat.knowledge.knowledge_lib import initialize_lpmm_knowledge
initialize_lpmm_knowledge()
# 显示彩蛋
EasterEgg.show()
@@ -422,7 +420,7 @@ async def wait_for_user_input():
"""等待用户输入(异步方式)"""
try:
# 在非生产环境下,使用异步方式等待输入
if os.getenv('ENVIRONMENT') != 'production':
if os.getenv("ENVIRONMENT") != "production":
logger.info("程序执行完成,按 Ctrl+C 退出...")
# 简单的异步等待,避免阻塞事件循环
while True:
@@ -438,30 +436,30 @@ async def main_async():
"""主异步函数"""
exit_code = 0
main_task = None
async with create_event_loop_context() as loop:
try:
# 确保环境文件存在
ConfigManager.ensure_env_file()
# 创建主程序实例并执行初始化
maibot = MaiBotMain()
main_system = await maibot.run_sync_init()
await maibot.run_async_init(main_system)
# 运行主任务
main_task = asyncio.create_task(main_system.schedule_tasks())
logger.info("麦麦机器人启动完成,开始运行主任务...")
# 同时运行主任务和用户输入等待
user_input_done = asyncio.create_task(wait_for_user_input())
# 使用wait等待任意一个任务完成
done, pending = await asyncio.wait(
[main_task, user_input_done],
return_when=asyncio.FIRST_COMPLETED
)
# 如果用户输入任务完成用户按了Ctrl+C取消主任务
if user_input_done in done and main_task not in done:
logger.info("用户请求退出,正在取消主任务...")
@@ -472,7 +470,7 @@ async def main_async():
logger.info("主任务已取消")
except Exception as e:
logger.error(f"主任务取消时发生错误: {e}")
except KeyboardInterrupt:
logger.warning("收到中断信号,正在优雅关闭...")
if main_task and not main_task.done():
@@ -481,7 +479,7 @@ async def main_async():
logger.error(f"主程序发生异常: {e}")
logger.debug(f"异常详情: {traceback.format_exc()}")
exit_code = 1
return exit_code
if __name__ == "__main__":
@@ -500,5 +498,5 @@ if __name__ == "__main__":
shutdown_logging()
except Exception as e:
print(f"关闭日志系统时出错: {e}")
sys.exit(exit_code)