mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-08 17:08:35 +08:00
fix: handle Telegram urllib3 header formatter compatibility (#6074)
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
def ensure_urllib3_header_param_compat() -> None:
|
||||||
|
"""
|
||||||
|
pyTelegramBotAPI imports urllib3.fields.format_header_param at import time.
|
||||||
|
Some urllib3-future builds only expose newer formatter names.
|
||||||
|
RFC 2231 formatting is kept as the last fallback because it encodes
|
||||||
|
non-ASCII values differently from urllib3's old default.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from urllib3 import fields
|
||||||
|
except ImportError:
|
||||||
|
return
|
||||||
|
|
||||||
|
if hasattr(fields, "format_header_param"):
|
||||||
|
return
|
||||||
|
|
||||||
|
for fallback_name in (
|
||||||
|
"format_header_param_html5",
|
||||||
|
"format_multipart_header_param",
|
||||||
|
"format_header_param_rfc2231",
|
||||||
|
):
|
||||||
|
fallback = getattr(fields, fallback_name, None)
|
||||||
|
if fallback is not None:
|
||||||
|
fields.format_header_param = fallback
|
||||||
|
return
|
||||||
@@ -8,36 +8,41 @@ from pathlib import Path
|
|||||||
from typing import Any, Callable, Dict, List, Optional, Union
|
from typing import Any, Callable, Dict, List, Optional, Union
|
||||||
from urllib.parse import urljoin, quote
|
from urllib.parse import urljoin, quote
|
||||||
|
|
||||||
from telebot import TeleBot, apihelper
|
from app.modules.telegram.compat import ensure_urllib3_header_param_compat
|
||||||
from telebot.types import (
|
|
||||||
|
# Must run before importing pyTelegramBotAPI.
|
||||||
|
ensure_urllib3_header_param_compat()
|
||||||
|
|
||||||
|
from telebot import TeleBot, apihelper # noqa: E402
|
||||||
|
from telebot.types import ( # noqa: E402
|
||||||
BotCommand,
|
BotCommand,
|
||||||
InlineKeyboardMarkup,
|
InlineKeyboardMarkup,
|
||||||
InlineKeyboardButton,
|
InlineKeyboardButton,
|
||||||
InputMediaPhoto,
|
InputMediaPhoto,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
from telebot.types import ForceReply
|
from telebot.types import ForceReply # noqa: E402
|
||||||
except ImportError:
|
except ImportError:
|
||||||
ForceReply = None
|
ForceReply = None
|
||||||
from telegramify_markdown import standardize, telegramify # noqa
|
from telegramify_markdown import standardize, telegramify # noqa: E402
|
||||||
try:
|
try:
|
||||||
from telegramify_markdown import entities_to_markdownv2 # noqa
|
from telegramify_markdown import entities_to_markdownv2 # noqa: E402
|
||||||
except ImportError:
|
except ImportError:
|
||||||
entities_to_markdownv2 = None
|
entities_to_markdownv2 = None
|
||||||
try:
|
try:
|
||||||
from telegramify_markdown.content import ContentTypes, File, Photo, Text
|
from telegramify_markdown.content import ContentTypes, File, Photo, Text # noqa: E402
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from telegramify_markdown.type import ContentTypes, File, Photo, Text
|
from telegramify_markdown.type import ContentTypes, File, Photo, Text # noqa: E402
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings # noqa: E402
|
||||||
from app.core.context import MediaInfo, Context
|
from app.core.context import MediaInfo, Context # noqa: E402
|
||||||
from app.core.metainfo import MetaInfo
|
from app.core.metainfo import MetaInfo # noqa: E402
|
||||||
from app.helper.image import ImageHelper
|
from app.helper.image import ImageHelper # noqa: E402
|
||||||
from app.helper.thread import ThreadHelper
|
from app.helper.thread import ThreadHelper # noqa: E402
|
||||||
from app.log import logger
|
from app.log import logger # noqa: E402
|
||||||
from app.utils.common import retry
|
from app.utils.common import retry # noqa: E402
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils # noqa: E402
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
TELEGRAM_PARSE_MODE_MARKDOWN = "MarkdownV2"
|
TELEGRAM_PARSE_MODE_MARKDOWN = "MarkdownV2"
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_urllib3_header_param_compat_adds_best_available_alias(monkeypatch):
|
||||||
|
"""urllib3 future 缺少旧别名时,应补齐最接近的新入口。"""
|
||||||
|
from app.modules.telegram.compat import ensure_urllib3_header_param_compat
|
||||||
|
|
||||||
|
def multipart_formatter(name, value):
|
||||||
|
return f"multipart:{name}={value}"
|
||||||
|
|
||||||
|
def rfc2231_formatter(name, value):
|
||||||
|
return f"rfc2231:{name}={value}"
|
||||||
|
|
||||||
|
fake_fields = SimpleNamespace(
|
||||||
|
format_multipart_header_param=multipart_formatter,
|
||||||
|
format_header_param_rfc2231=rfc2231_formatter,
|
||||||
|
)
|
||||||
|
fake_urllib3 = SimpleNamespace(fields=fake_fields)
|
||||||
|
monkeypatch.setitem(sys.modules, "urllib3", fake_urllib3)
|
||||||
|
|
||||||
|
ensure_urllib3_header_param_compat()
|
||||||
|
|
||||||
|
assert fake_fields.format_header_param is multipart_formatter
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_urllib3_header_param_compat_prefers_html5_formatter(monkeypatch):
|
||||||
|
"""旧版本 urllib3 的 html5 formatter 存在时,应优先保持原别名语义。"""
|
||||||
|
from app.modules.telegram.compat import ensure_urllib3_header_param_compat
|
||||||
|
|
||||||
|
def html5_formatter(name, value):
|
||||||
|
return f"html5:{name}={value}"
|
||||||
|
|
||||||
|
def multipart_formatter(name, value):
|
||||||
|
return f"multipart:{name}={value}"
|
||||||
|
|
||||||
|
fake_fields = SimpleNamespace(
|
||||||
|
format_header_param_html5=html5_formatter,
|
||||||
|
format_multipart_header_param=multipart_formatter,
|
||||||
|
)
|
||||||
|
fake_urllib3 = SimpleNamespace(fields=fake_fields)
|
||||||
|
monkeypatch.setitem(sys.modules, "urllib3", fake_urllib3)
|
||||||
|
|
||||||
|
ensure_urllib3_header_param_compat()
|
||||||
|
|
||||||
|
assert fake_fields.format_header_param is html5_formatter
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_urllib3_header_param_compat_keeps_existing_formatter(monkeypatch):
|
||||||
|
"""已有 format_header_param 时不应覆盖,避免改变 urllib3 正常行为。"""
|
||||||
|
from app.modules.telegram.compat import ensure_urllib3_header_param_compat
|
||||||
|
|
||||||
|
def existing_formatter(name, value):
|
||||||
|
return f"existing:{name}={value}"
|
||||||
|
|
||||||
|
def rfc2231_formatter(name, value):
|
||||||
|
return f"fallback:{name}={value}"
|
||||||
|
|
||||||
|
fake_fields = SimpleNamespace(
|
||||||
|
format_header_param=existing_formatter,
|
||||||
|
format_header_param_rfc2231=rfc2231_formatter,
|
||||||
|
)
|
||||||
|
fake_urllib3 = SimpleNamespace(fields=fake_fields)
|
||||||
|
monkeypatch.setitem(sys.modules, "urllib3", fake_urllib3)
|
||||||
|
|
||||||
|
ensure_urllib3_header_param_compat()
|
||||||
|
|
||||||
|
assert fake_fields.format_header_param is existing_formatter
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_urllib3_header_param_compat_noops_without_fallback(monkeypatch):
|
||||||
|
"""没有任何可用 fallback 时保持 no-op,让原始导入错误暴露。"""
|
||||||
|
from app.modules.telegram.compat import ensure_urllib3_header_param_compat
|
||||||
|
|
||||||
|
fake_fields = SimpleNamespace()
|
||||||
|
fake_urllib3 = SimpleNamespace(fields=fake_fields)
|
||||||
|
monkeypatch.setitem(sys.modules, "urllib3", fake_urllib3)
|
||||||
|
|
||||||
|
ensure_urllib3_header_param_compat()
|
||||||
|
|
||||||
|
assert not hasattr(fake_fields, "format_header_param")
|
||||||
|
|
||||||
|
|
||||||
|
def test_telegram_module_imports_when_urllib3_header_alias_missing(monkeypatch):
|
||||||
|
"""导入 Telegram 模块前旧别名缺失时,应先补齐再导入 telebot。"""
|
||||||
|
from urllib3 import fields
|
||||||
|
|
||||||
|
if not any(
|
||||||
|
hasattr(fields, name)
|
||||||
|
for name in (
|
||||||
|
"format_header_param_html5",
|
||||||
|
"format_multipart_header_param",
|
||||||
|
"format_header_param_rfc2231",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
pytest.skip("urllib3 has no compatible header formatter fallback")
|
||||||
|
|
||||||
|
monkeypatch.delattr(fields, "format_header_param", raising=False)
|
||||||
|
for module_name in list(sys.modules):
|
||||||
|
if (
|
||||||
|
module_name == "app.modules.telegram.telegram"
|
||||||
|
or module_name.startswith("telebot")
|
||||||
|
):
|
||||||
|
monkeypatch.delitem(sys.modules, module_name, raising=False)
|
||||||
|
|
||||||
|
telegram_module = importlib.import_module("app.modules.telegram.telegram")
|
||||||
|
|
||||||
|
assert telegram_module.Telegram
|
||||||
|
assert hasattr(fields, "format_header_param")
|
||||||
Reference in New Issue
Block a user