import os from dotenv import load_dotenv from flask import Flask # 项目根目录 = 本文件父目录的父目录 BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) # 必须先于 applications.config 加载:config 在模块级就要读 PEAR_DATA_DIR # 等环境变量来拼 data 目录路径,晚一步就会沿用默认值。 load_dotenv(os.path.join(BASE_DIR, ".env"), override=False) from applications.common.script import init_script from applications.config import BaseConfig, get_config_by_name, ensure_data_dir from applications.extensions import init_plugs from applications.view import init_bps def create_app(): # 1) 再加载一次 .env(幂等;override=False 保证环境变量优先级更高) load_dotenv(os.path.join(BASE_DIR, ".env"), override=False) app = Flask(BASE_DIR) # 2) 根据 PEAR_ENV / FLASK_ENV 选择配置类,默认 dev env_name = os.environ.get("PEAR_ENV") or os.environ.get("FLASK_ENV") or "dev" config_cls = get_config_by_name(env_name) app.config.from_object(config_cls) # 3) 把 BaseConfig 默认值里没写、但 .env 可能写了的 SQLALCHEMY_DATABASE_URI 等再覆盖一次 if os.environ.get("SQLALCHEMY_DATABASE_URI"): app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["SQLALCHEMY_DATABASE_URI"] # 3.5) 让配置类有机会做运行时校验(例如 ProConfig 强制要求 SECRET_KEY) if hasattr(config_cls, "init_app"): config_cls.init_app(app) # 3.6) 数据目录兜底:确保 data/ 存在,并以运行时解析结果为准写回路径 # (.env 里配了 PEAR_DATA_DIR 时,这里保证它一定生效) data_dir = ensure_data_dir() app.config["DATA_DIR"] = data_dir if not os.environ.get("SQLALCHEMY_DATABASE_URI"): app.config["SQLALCHEMY_DATABASE_URI"] = ( "sqlite:///" + os.path.join(data_dir, "pear.db").replace("\\", "/") ) app.config["SESSION_FILE_DIR"] = os.path.join(data_dir, "flask_session") # 4) 注册 flask 组件 / 蓝图 / 命令 init_plugs(app) init_bps(app) init_script(app) # 5) 全站访问埋点已迁移到 plugins/siteStats(@app.before_request → record_visit) return app