专题图修改虚拟环境
This commit is contained in:
@@ -379,7 +379,7 @@ def _generate_batch_maps(models: list, config: dict, disaster_time: str) -> None
|
|||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from app.services.qgis.qgis_env import build_qgis_command
|
from app.services.qgis.qgis_env import build_qgis_command, build_clean_subprocess_env
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(f"[批量产图] 开始: {len(models)} 张专题图, batch={disaster_time}")
|
logger.info(f"[批量产图] 开始: {len(models)} 张专题图, batch={disaster_time}")
|
||||||
@@ -409,10 +409,10 @@ def _generate_batch_maps(models: list, config: dict, disaster_time: str) -> None
|
|||||||
cmd,
|
cmd,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
timeout=600, # 10 分钟超时(15 张模板 × ~40s/张 ≈ 600s)
|
timeout=600, # 10 分钟超时(15 张模板 × ~40s/张 ≈ 600s)
|
||||||
# 不传 env —— 让子进程继承父进程环境,
|
env=build_clean_subprocess_env(),
|
||||||
# runner 内部 _setup_environment() 会设置 QGIS 所需变量。
|
# 使用干净的环境变量:移除 venv 的 PYTHONPATH/VIRTUAL_ENV/PATH 污染,
|
||||||
# build_qgis_env() 设置的 PYTHONPATH/PATH/QGIS_PREFIX_PATH
|
# 避免 QGIS Python 3.12 的 DLL 加载被干扰导致 0xC0000005 崩溃。
|
||||||
# 与 QGIS DLL 加载冲突,导致 0xC0000005 崩溃。
|
# QGIS Python 3.12 仅通过 sys.path 即可正确加载所有模块和 DLL。
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -160,6 +160,67 @@ def build_qgis_env(qgis_root: str = None) -> dict:
|
|||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def build_clean_subprocess_env() -> dict:
|
||||||
|
"""
|
||||||
|
为 QGIS Python 3.12 子进程构建干净的环境变量。
|
||||||
|
|
||||||
|
问题背景:
|
||||||
|
主进程运行在 venv Python 3.10 中,继承了 venv 的环境变量
|
||||||
|
(PYTHONPATH 指向 venv site-packages、VIRTUAL_ENV、PATH 含 venv Scripts 等)。
|
||||||
|
QGIS Python 3.12 子进程如果继承这些变量,DLL 加载会被干扰,
|
||||||
|
导致 0xC0000005 (ACCESS_VIOLATION) 崩溃。
|
||||||
|
|
||||||
|
同时,QGIS_PREFIX_PATH、QT_PLUGIN_PATH 等变量也会与
|
||||||
|
QGIS 内置 DLL 加载机制冲突,同样导致崩溃。
|
||||||
|
|
||||||
|
策略:
|
||||||
|
从 os.environ 中移除所有 Python/venv 相关的污染变量,
|
||||||
|
只保留操作系统正常运行所需的基础变量(SystemRoot、TEMP 等)。
|
||||||
|
QGIS Python 3.12 仅通过 sys.path 即可正确加载所有模块和 DLL。
|
||||||
|
"""
|
||||||
|
env = dict(os.environ)
|
||||||
|
|
||||||
|
# 先记录 venv 路径(后续清理 PATH 时需要用)
|
||||||
|
venv_root = env.get("VIRTUAL_ENV", "").lower()
|
||||||
|
|
||||||
|
# 移除 Python/venv 相关变量 —— 这些会污染 QGIS Python 3.12 的 DLL 加载
|
||||||
|
for key in [
|
||||||
|
"PYTHONPATH", # venv 设置,指向 site-packages → DLL 冲突
|
||||||
|
"PYTHONHOME", # 如果存在,改变 Python 查找路径
|
||||||
|
"VIRTUAL_ENV", # venv 标识,不必要
|
||||||
|
"PYTHONDONTWRITEBYTECODE",
|
||||||
|
"QGIS_PREFIX_PATH", # 与 QGIS 内置 DLL 加载冲突
|
||||||
|
"QT_PLUGIN_PATH", # 与 Qt DLL 加载冲突
|
||||||
|
"GDAL_DATA", # build_qgis_env 设置,可能导致路径冲突
|
||||||
|
"PROJ_DATA", # build_qgis_env 设置,可能导致路径冲突
|
||||||
|
]:
|
||||||
|
env.pop(key, None)
|
||||||
|
|
||||||
|
# 清理 PATH:仅移除 venv 相关路径(避免 DLL 搜索顺序冲突)
|
||||||
|
# 保留 QGIS/系统路径(测试证明这些是安全的)
|
||||||
|
if venv_root:
|
||||||
|
path_parts = env.get("PATH", "").split(";")
|
||||||
|
clean_parts = []
|
||||||
|
for p in path_parts:
|
||||||
|
pl = p.lower().strip()
|
||||||
|
if not pl:
|
||||||
|
continue
|
||||||
|
# 跳过 venv 相关路径(.venv/Scripts, .venv/Lib 等)
|
||||||
|
if venv_root in pl:
|
||||||
|
continue
|
||||||
|
clean_parts.append(p)
|
||||||
|
env["PATH"] = ";".join(clean_parts)
|
||||||
|
|
||||||
|
# 移除 VIRTUAL_ENV 本身(已从 PATH 清理中使用过)
|
||||||
|
env.pop("VIRTUAL_ENV", None)
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
f"Clean env built: removed PYTHONPATH/VIRTUAL_ENV/venv-PATH, "
|
||||||
|
f"kept {len(env)} vars"
|
||||||
|
)
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
def is_qgis_available(qgis_root: str = None) -> bool:
|
def is_qgis_available(qgis_root: str = None) -> bool:
|
||||||
"""检查 QGIS 环境是否可用"""
|
"""检查 QGIS 环境是否可用"""
|
||||||
return get_qgis_python_path(qgis_root) is not None
|
return get_qgis_python_path(qgis_root) is not None
|
||||||
|
|||||||
Reference in New Issue
Block a user