fix(gateway): complete lazy-install rebind for slack/feishu/matrix + add ensure_and_bind helper (#25038)

Fixes #25028.

The lazy-install hooks added in #25014 installed packages correctly but
failed to rebind module-level globals after install:

- Slack: missing aiohttp rebind → NameError on file uploads
- Feishu: none of the ~25 lark_oapi symbols rebound → TypeError on
  adapter instantiation
- Matrix: mautrix.types enums stayed as stubs → mismatched values at
  runtime

Introduces tools.lazy_deps.ensure_and_bind() — a DRY helper that
combines ensure() + importer-callable + globals().update(). This
eliminates the error-prone pattern of manually listing every global
that needs updating after lazy-install. Each platform adapter now
defines a single _import() function returning all bindings.

Also fixes: pyproject.toml [slack] extra was missing aiohttp (needed
by slack-bolt's async path).
This commit is contained in:
Siddharth Balyan 2026-05-14 10:41:46 +05:30 committed by GitHub
parent 52521c937a
commit d898e0eb7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 149 additions and 39 deletions

View file

@ -76,27 +76,26 @@ def check_slack_requirements() -> bool:
"""Check if Slack dependencies are available.
Lazy-installs slack-bolt/slack-sdk via ``tools.lazy_deps.ensure("platform.slack")``
on first call if not present.
on first call if not present. Rebinds all module-level globals on success.
"""
global SLACK_AVAILABLE, AsyncApp, AsyncSocketModeHandler, AsyncWebClient
if SLACK_AVAILABLE:
return True
try:
from tools.lazy_deps import ensure as _lazy_ensure
_lazy_ensure("platform.slack", prompt=False)
except Exception:
return False
try:
from slack_bolt.async_app import AsyncApp as _App
from slack_bolt.adapter.socket_mode.async_handler import AsyncSocketModeHandler as _Handler
from slack_sdk.web.async_client import AsyncWebClient as _Client
except ImportError:
return False
AsyncApp = _App
AsyncSocketModeHandler = _Handler
AsyncWebClient = _Client
SLACK_AVAILABLE = True
return True
def _import():
from slack_bolt.async_app import AsyncApp
from slack_bolt.adapter.socket_mode.async_handler import AsyncSocketModeHandler
from slack_sdk.web.async_client import AsyncWebClient
import aiohttp
return {
"AsyncApp": AsyncApp,
"AsyncSocketModeHandler": AsyncSocketModeHandler,
"AsyncWebClient": AsyncWebClient,
"aiohttp": aiohttp,
"SLACK_AVAILABLE": True,
}
from tools.lazy_deps import ensure_and_bind
return ensure_and_bind("platform.slack", _import, globals(), prompt=False)
def _extract_text_from_slack_blocks(blocks: list) -> str: