mirror of
https://github.com/ZhuLinsen/daily_stock_analysis
synced 2026-09-20 02:43:35 +08:00
fix: prevent mimetypes hang on Windows by skipping registry init (#2059)
Co-authored-by: E <e@local.com> Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
This commit is contained in:
11
api/app.py
11
api/app.py
@@ -19,6 +19,17 @@ import asyncio
|
||||
import json
|
||||
import logging
|
||||
import mimetypes
|
||||
|
||||
import sys
|
||||
|
||||
if sys.platform == "win32" and not mimetypes.inited:
|
||||
_orig_read_windows_registry = getattr(mimetypes.MimeTypes, 'read_windows_registry', None)
|
||||
if _orig_read_windows_registry is not None:
|
||||
mimetypes.MimeTypes.read_windows_registry = lambda self, strict=True: None
|
||||
try: mimetypes.init()
|
||||
finally: mimetypes.MimeTypes.read_windows_registry = _orig_read_windows_registry
|
||||
else:
|
||||
mimetypes.init()
|
||||
import os
|
||||
import re
|
||||
from contextlib import asynccontextmanager, suppress
|
||||
|
||||
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
||||
- [新功能] Tushare 数据源支持通过 `TUSHARE_HTTP_URL` 环境变量自定义接入地址,便于网络无法直达 `api.tushare.pro` 时切换自建网关或第三方兼容镜像;留空保持官方默认地址不变(fixes #1985)
|
||||
- [文档] `.env.example` 与 `.github/workflows/00-daily-analysis.yml` 同步映射 `TUSHARE_HTTP_URL`,避免出现"配置项有但 workflow 漏映射"的半修状态
|
||||
- [修复] #2051 PR Review 的特权 `pull_request_target` 流程不再检出 fork PR head:敏感文件、标签、报告与 AI 审查统一通过 GitHub API 将 PR 元数据和 diff 作为数据读取,只执行主分支可信脚本;Python 语法、Flake8、确定性检查和离线测试继续由无 secrets 的 `pull_request` CI / `backend-gate` 执行,兼容 `actions/checkout` 新增的 fork checkout 安全保护。
|
||||
- [修复] 修复 Windows 上 mimetypes 冷启动时读取注册表导致的进程卡死
|
||||
|
||||
## [3.27.0] - 2026-07-19
|
||||
|
||||
|
||||
89
tests/test_mimetypes_windows_init.py
Normal file
89
tests/test_mimetypes_windows_init.py
Normal file
@@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Tests for mimetypes cold-start behaviour on Windows."""
|
||||
|
||||
import importlib
|
||||
import mimetypes
|
||||
import sys
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
class MimetypesWindowsInitTestCase(unittest.TestCase):
|
||||
"""Cold-start: Windows skips registry; non-Windows keeps full MIME db."""
|
||||
|
||||
def setUp(self):
|
||||
self._types_map_backup = dict(mimetypes.types_map)
|
||||
|
||||
def tearDown(self):
|
||||
mimetypes.types_map.clear()
|
||||
mimetypes.types_map.update(self._types_map_backup)
|
||||
|
||||
@staticmethod
|
||||
def _simulate_cold_start():
|
||||
mimetypes.inited = False
|
||||
mimetypes._db = None
|
||||
|
||||
def test_windows_cold_import_skips_registry(self):
|
||||
"""Windows cold-start must not call read_windows_registry."""
|
||||
import api.app
|
||||
|
||||
self._simulate_cold_start()
|
||||
with patch("sys.platform", "win32"), \
|
||||
patch.object(mimetypes.MimeTypes, "read_windows_registry") as mock_registry:
|
||||
importlib.reload(api.app)
|
||||
|
||||
mock_registry.assert_not_called()
|
||||
|
||||
def test_non_windows_retains_full_mime_guessing(self):
|
||||
"""Non-Windows must NOT replace the system MIME database."""
|
||||
import api.app
|
||||
|
||||
self._simulate_cold_start()
|
||||
with patch("sys.platform", "linux"):
|
||||
importlib.reload(api.app)
|
||||
|
||||
self.assertEqual(
|
||||
mimetypes.guess_type("index.html")[0],
|
||||
"text/html",
|
||||
"HTML must still be detected on non-Windows",
|
||||
)
|
||||
self.assertEqual(
|
||||
mimetypes.guess_type("test.pdf")[0],
|
||||
"application/pdf",
|
||||
"PDF must still be detected on non-Windows",
|
||||
)
|
||||
|
||||
def test_types_map_consistent_with_db(self):
|
||||
"""types_map and _db.types_map[True] must be the same object."""
|
||||
import api.app
|
||||
|
||||
self._simulate_cold_start()
|
||||
with patch("sys.platform", "win32"):
|
||||
importlib.reload(api.app)
|
||||
|
||||
self.assertIs(
|
||||
mimetypes.types_map,
|
||||
mimetypes._db.types_map[True],
|
||||
"types_map must reference _db internals (no split-brain)",
|
||||
)
|
||||
|
||||
def test_frontend_mime_types_registered_after_init(self):
|
||||
"""_register_frontend_asset_mime_types must work after cold-start init."""
|
||||
import api.app
|
||||
|
||||
self._simulate_cold_start()
|
||||
with patch("sys.platform", "win32"):
|
||||
importlib.reload(api.app)
|
||||
|
||||
api.app._register_frontend_asset_mime_types()
|
||||
|
||||
self.assertEqual(
|
||||
mimetypes.guess_type("app.js")[0], "text/javascript"
|
||||
)
|
||||
self.assertEqual(
|
||||
mimetypes.guess_type("style.css")[0], "text/css"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user