From 9b93cea12b1cdaca1f939ef1ec18a4fd051703b5 Mon Sep 17 00:00:00 2001 From: MuXinCG <202322130196@mail.sdu.edu.cn> Date: Sun, 15 Feb 2026 21:07:47 +0800 Subject: [PATCH] fix linter bug --- EvoScientist/EvoScientist.py | 2 +- EvoScientist/channels/__init__.py | 15 +++++------ EvoScientist/channels/capabilities.py | 2 +- EvoScientist/channels/channel_manager.py | 9 ++----- EvoScientist/channels/config.py | 2 +- EvoScientist/channels/consumer.py | 2 +- EvoScientist/channels/dingtalk/channel.py | 2 -- EvoScientist/channels/discord/channel.py | 1 - EvoScientist/channels/email/channel.py | 27 ++++++++++++++----- EvoScientist/channels/feishu/channel.py | 9 ++++--- EvoScientist/channels/middleware.py | 7 +++-- EvoScientist/channels/mixins.py | 3 +-- EvoScientist/channels/qq/channel.py | 1 - EvoScientist/channels/signal/channel.py | 3 +-- EvoScientist/channels/signal/probe.py | 3 ++- EvoScientist/channels/slack/channel.py | 1 - EvoScientist/channels/wechat/channel.py | 12 ++++++--- EvoScientist/channels/wechat/crypto.py | 2 -- EvoScientist/channels/wechat/verify_server.py | 10 +++++-- EvoScientist/cli/channel.py | 2 +- EvoScientist/cli/interactive.py | 4 --- tests/test_bus_integration.py | 5 ++-- tests/test_channel_comprehensive.py | 17 +++++------- tests/test_channel_manager.py | 3 +-- tests/test_mention_gating.py | 1 - tests/test_message_bus.py | 1 - 26 files changed, 72 insertions(+), 74 deletions(-) diff --git a/EvoScientist/EvoScientist.py b/EvoScientist/EvoScientist.py index 6c8b500..c3700df 100644 --- a/EvoScientist/EvoScientist.py +++ b/EvoScientist/EvoScientist.py @@ -24,7 +24,7 @@ from .backends import CustomSandboxBackend, MergedReadOnlyBackend from .config import get_effective_config, apply_config_to_env from .llm import get_chat_model from .mcp import load_mcp_tools -from .middleware import create_memory_middleware, create_skills_middleware +from .middleware import create_memory_middleware from .prompts import RESEARCHER_INSTRUCTIONS, get_system_prompt from .utils import load_subagents from .tools import tavily_search, think_tool, skill_manager, view_image diff --git a/EvoScientist/channels/__init__.py b/EvoScientist/channels/__init__.py index f7611a1..7085a47 100644 --- a/EvoScientist/channels/__init__.py +++ b/EvoScientist/channels/__init__.py @@ -4,10 +4,14 @@ This module provides an extensible interface for different messaging channels (iMessage, Telegram, Discord) to communicate with the EvoScientist agent. """ -from .base import Channel, RawIncoming, IncomingMessage, OutgoingMessage +from .base import Channel, RawIncoming, IncomingMessage, OutgoingMessage, chunk_text from .bus import MessageBus, InboundMessage, OutboundMessage +from .capabilities import ChannelCapabilities from .channel_manager import ChannelManager, register_channel, create_channel, available_channels from .consumer import InboundConsumer +from .formatter import UnifiedFormatter +from .middleware import TypingManager +from .plugin import ChannelPlugin, ChannelMeta, ReloadPolicy from .standalone import run_standalone # Backward compat: ChannelServer is now Channel itself @@ -27,6 +31,7 @@ __all__ = [ "run_standalone", "register_channel", "create_channel", + "available_channels", # New modules "ChannelCapabilities", "UnifiedFormatter", @@ -37,11 +42,3 @@ __all__ = [ "ChannelMeta", "ReloadPolicy", ] - -from .capabilities import ChannelCapabilities -from .formatter import UnifiedFormatter -from .middleware import TypingManager -from .base import chunk_text - -# Plugin architecture -from .plugin import ChannelPlugin, ChannelMeta, ReloadPolicy diff --git a/EvoScientist/channels/capabilities.py b/EvoScientist/channels/capabilities.py index b125a22..5060dd9 100644 --- a/EvoScientist/channels/capabilities.py +++ b/EvoScientist/channels/capabilities.py @@ -7,7 +7,7 @@ streaming, threading, etc.) without per-channel branching in core logic. from __future__ import annotations -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Literal FormatType = Literal["html", "markdown", "slack_mrkdwn", "discord", "plain"] diff --git a/EvoScientist/channels/channel_manager.py b/EvoScientist/channels/channel_manager.py index 30d3449..989cc64 100644 --- a/EvoScientist/channels/channel_manager.py +++ b/EvoScientist/channels/channel_manager.py @@ -11,7 +11,6 @@ account management (formerly ``account.py``), and pipeline assembly from __future__ import annotations import asyncio -import dataclasses import importlib import json import logging @@ -22,9 +21,9 @@ from datetime import datetime from pathlib import Path from typing import Any, Callable -from .base import Channel, RawIncoming, OutboundMessage +from .base import Channel, OutboundMessage from .bus import MessageBus -from .bus.events import InboundMessage +from .middleware import OutboundMiddlewareBase from .plugin import ChannelPlugin logger = logging.getLogger(__name__) @@ -245,10 +244,6 @@ class AccountManager: # Inbound / outbound pipelines (formerly pipeline.py) # ═════════════════════════════════════════════════════════════════════ -from .middleware import ( - OutboundMiddlewareBase, -) - class OutboundPipeline: """Processes outgoing messages through a middleware chain.""" diff --git a/EvoScientist/channels/config.py b/EvoScientist/channels/config.py index f27ad3e..c6afb77 100644 --- a/EvoScientist/channels/config.py +++ b/EvoScientist/channels/config.py @@ -12,7 +12,7 @@ common account patterns: from __future__ import annotations -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any diff --git a/EvoScientist/channels/consumer.py b/EvoScientist/channels/consumer.py index 5fdfd28..62463c9 100644 --- a/EvoScientist/channels/consumer.py +++ b/EvoScientist/channels/consumer.py @@ -12,7 +12,7 @@ from __future__ import annotations import asyncio import logging import uuid -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncIterator, Callable, TypeVar from .base import Channel diff --git a/EvoScientist/channels/dingtalk/channel.py b/EvoScientist/channels/dingtalk/channel.py index cbbb750..1b1bffb 100644 --- a/EvoScientist/channels/dingtalk/channel.py +++ b/EvoScientist/channels/dingtalk/channel.py @@ -4,7 +4,6 @@ import asyncio import json import logging from urllib.parse import quote_plus -import time from dataclasses import dataclass from datetime import datetime from pathlib import Path @@ -212,7 +211,6 @@ class DingTalkChannel(Channel, WebSocketMixin, TokenMixin): return sender_id = payload.get("senderStaffId") or payload.get("senderId", "") - conv_id = payload.get("conversationId", "") is_group = payload.get("conversationType") == "2" # For send API (oToMessages/batchSend), userIds needs staffId, not conversationId chat_id = sender_id diff --git a/EvoScientist/channels/discord/channel.py b/EvoScientist/channels/discord/channel.py index 2fe5dd3..3ef69c9 100644 --- a/EvoScientist/channels/discord/channel.py +++ b/EvoScientist/channels/discord/channel.py @@ -3,7 +3,6 @@ import asyncio import logging import os -import re from dataclasses import dataclass from datetime import datetime diff --git a/EvoScientist/channels/email/channel.py b/EvoScientist/channels/email/channel.py index 71a4dfa..2c2a2da 100644 --- a/EvoScientist/channels/email/channel.py +++ b/EvoScientist/channels/email/channel.py @@ -50,12 +50,24 @@ def _strip_html(text: str) -> str: @dataclass class EmailConfig(BaseChannelConfig): - imap_host: str = ""; imap_port: int = 993; imap_username: str = ""; imap_password: str = "" - imap_mailbox: str = "INBOX"; imap_use_ssl: bool = True - smtp_host: str = ""; smtp_port: int = 587; smtp_username: str = ""; smtp_password: str = "" - smtp_use_tls: bool = True; from_address: str = "" - poll_interval: int = 30; mark_seen: bool = True; max_body_chars: int = 12000 - subject_prefix: str = "Re: "; allowed_senders: set[str] | None = None; text_chunk_limit: int = 4096 + imap_host: str = "" + imap_port: int = 993 + imap_username: str = "" + imap_password: str = "" + imap_mailbox: str = "INBOX" + imap_use_ssl: bool = True + smtp_host: str = "" + smtp_port: int = 587 + smtp_username: str = "" + smtp_password: str = "" + smtp_use_tls: bool = True + from_address: str = "" + poll_interval: int = 30 + mark_seen: bool = True + max_body_chars: int = 12000 + subject_prefix: str = "Re: " + allowed_senders: set[str] | None = None + text_chunk_limit: int = 4096 class EmailChannel(Channel, PollingMixin): @@ -352,7 +364,8 @@ class EmailChannel(Channel, PollingMixin): await self._stop_polling() if self._imap: try: - self._imap.close(); self._imap.logout() + self._imap.close() + self._imap.logout() except Exception: pass self._imap = None diff --git a/EvoScientist/channels/feishu/channel.py b/EvoScientist/channels/feishu/channel.py index 8ba399d..e444be9 100644 --- a/EvoScientist/channels/feishu/channel.py +++ b/EvoScientist/channels/feishu/channel.py @@ -16,16 +16,19 @@ Send API: - ``POST /open-apis/im/v1/messages?receive_id_type=chat_id`` """ -import asyncio +from __future__ import annotations + import json import logging import re -import time -from typing import Any +from typing import Any, TYPE_CHECKING from dataclasses import dataclass from datetime import datetime from pathlib import Path +if TYPE_CHECKING: + from aiohttp import web + from ..base import Channel, RawIncoming, ChannelError from ..capabilities import FEISHU as FEISHU_CAPS from ..mixins import WebhookMixin, TokenMixin diff --git a/EvoScientist/channels/middleware.py b/EvoScientist/channels/middleware.py index 9ab67bc..c205fbd 100644 --- a/EvoScientist/channels/middleware.py +++ b/EvoScientist/channels/middleware.py @@ -14,11 +14,10 @@ import asyncio import dataclasses import logging import random -import re import time -from collections import OrderedDict, defaultdict, deque +from collections import OrderedDict, deque from collections.abc import Awaitable -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, Callable from .bus.events import InboundMessage, OutboundMessage @@ -527,7 +526,7 @@ class RetryMiddleware: """ def __init__(self, channel_name: str = "unknown") -> None: - from .retry import RetryConfig, DEFAULT_RETRY, RETRY_PRESETS + from .retry import DEFAULT_RETRY, RETRY_PRESETS self._config = RETRY_PRESETS.get(channel_name, DEFAULT_RETRY) self._channel_name = channel_name diff --git a/EvoScientist/channels/mixins.py b/EvoScientist/channels/mixins.py index fcfe58c..559bffd 100644 --- a/EvoScientist/channels/mixins.py +++ b/EvoScientist/channels/mixins.py @@ -16,9 +16,8 @@ import asyncio import json import logging import time -from typing import Any, Callable +from typing import Any -from .base import Channel, ChannelError logger = logging.getLogger(__name__) diff --git a/EvoScientist/channels/qq/channel.py b/EvoScientist/channels/qq/channel.py index c3352bb..0f0e83a 100644 --- a/EvoScientist/channels/qq/channel.py +++ b/EvoScientist/channels/qq/channel.py @@ -209,7 +209,6 @@ class QQChannel(Channel): from pathlib import Path chat_id = self._resolve_media_chat_id(recipient, metadata) msg_type = (metadata or {}).get("msg_type", "c2c") - msg_id = (metadata or {}).get("event_id", "") ext = Path(file_path).suffix.lower() file_type = self._FILE_TYPE_MAP.get(ext, 1) # default to image diff --git a/EvoScientist/channels/signal/channel.py b/EvoScientist/channels/signal/channel.py index 53affd4..2a577f1 100644 --- a/EvoScientist/channels/signal/channel.py +++ b/EvoScientist/channels/signal/channel.py @@ -15,9 +15,8 @@ import json import logging import re import subprocess -import time from collections import deque -from dataclasses import dataclass, field +from dataclasses import dataclass from datetime import datetime from typing import Any diff --git a/EvoScientist/channels/signal/probe.py b/EvoScientist/channels/signal/probe.py index c51feb5..8220008 100644 --- a/EvoScientist/channels/signal/probe.py +++ b/EvoScientist/channels/signal/probe.py @@ -9,7 +9,8 @@ async def validate_signal( rpc_port: int = 7583, ) -> tuple[bool, str]: """Validate Signal setup by checking signal-cli availability.""" - import asyncio, subprocess + import asyncio + import subprocess if not phone_number: return False, "phone_number is required" diff --git a/EvoScientist/channels/slack/channel.py b/EvoScientist/channels/slack/channel.py index 65dc897..21237f7 100644 --- a/EvoScientist/channels/slack/channel.py +++ b/EvoScientist/channels/slack/channel.py @@ -2,7 +2,6 @@ import asyncio import logging -import re from dataclasses import dataclass from datetime import datetime diff --git a/EvoScientist/channels/wechat/channel.py b/EvoScientist/channels/wechat/channel.py index 4c2fbb6..291131e 100644 --- a/EvoScientist/channels/wechat/channel.py +++ b/EvoScientist/channels/wechat/channel.py @@ -17,16 +17,20 @@ Both backends use httpx (already a core dependency) and aiohttp for webhook server — matching the Feishu channel pattern. """ +from __future__ import annotations + import asyncio import hashlib -import json import logging import re import time -from dataclasses import dataclass, field +from dataclasses import dataclass from datetime import datetime from pathlib import Path -from typing import Any +from typing import Any, TYPE_CHECKING + +if TYPE_CHECKING: + from aiohttp import web from ..mixins import WebhookMixin, TokenMixin from ..base import Channel, RawIncoming, ChannelError @@ -412,7 +416,7 @@ class WeChatChannel(Channel, WebhookMixin, TokenMixin): if ann: annotations.append(ann) else: - annotations.append(f"[image: no download source]") + annotations.append("[image: no download source]") elif msg_type == "voice": recognition = xml_data.get("Recognition", "") media_id = xml_data.get("MediaId", "") diff --git a/EvoScientist/channels/wechat/crypto.py b/EvoScientist/channels/wechat/crypto.py index dd27e7c..3652a34 100644 --- a/EvoScientist/channels/wechat/crypto.py +++ b/EvoScientist/channels/wechat/crypto.py @@ -13,11 +13,9 @@ References: import base64 import hashlib -import socket import struct import time import xml.etree.ElementTree as ET -from typing import Optional # Crypto imports — all from the Python standard library + pycryptodome # (but we'll use a pure-Python fallback if not available) diff --git a/EvoScientist/channels/wechat/verify_server.py b/EvoScientist/channels/wechat/verify_server.py index 4a8ec7b..bf00c66 100644 --- a/EvoScientist/channels/wechat/verify_server.py +++ b/EvoScientist/channels/wechat/verify_server.py @@ -14,9 +14,15 @@ Usage: await server.stop() """ +from __future__ import annotations + import asyncio import hashlib import logging +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from aiohttp import web logger = logging.getLogger(__name__) @@ -89,7 +95,7 @@ class VerifyServer: def is_verified(self) -> bool: return self._verified.is_set() - async def _handle(self, request) -> "web.Response": + async def _handle(self, request) -> web.Response: """Handle GET verification request. During onboarding we use a lenient approach: @@ -163,7 +169,7 @@ class VerifyServer: self._verified.set() return web.Response(text=echostr) - async def _handle_post(self, request) -> "web.Response": + async def _handle_post(self, request) -> web.Response: """Handle POST — just acknowledge during verification phase.""" from aiohttp import web return web.Response(text="success") diff --git a/EvoScientist/cli/channel.py b/EvoScientist/cli/channel.py index 363d974..78383a9 100644 --- a/EvoScientist/cli/channel.py +++ b/EvoScientist/cli/channel.py @@ -162,7 +162,7 @@ async def _bus_inbound_consumer( """ from ..stream import events as _stream_events_mod from ..stream.display import ( - console, display_final_results, create_streaming_display, + console, create_streaming_display, ) from ..stream.state import StreamState from ..channels.consumer import _format_todo_list diff --git a/EvoScientist/cli/interactive.py b/EvoScientist/cli/interactive.py index a6c9adf..ecaf323 100644 --- a/EvoScientist/cli/interactive.py +++ b/EvoScientist/cli/interactive.py @@ -483,10 +483,6 @@ def cmd_interactive( state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer) state["thread_id"] = generate_thread_id() state["resumed"] = False - # Sync shared refs if channel is running - if _ChannelState.is_running(): - _ChannelState.agent = state["agent"] - _ChannelState.thread_id = state["thread_id"] console.print(f"[green]New session:[/green] [yellow]{state['thread_id']}[/yellow]") if state["workspace_dir"]: console.print(f"[dim]Workspace:[/dim] [cyan]{_shorten_path(state['workspace_dir'])}[/cyan]\n") diff --git a/tests/test_bus_integration.py b/tests/test_bus_integration.py index 7484924..8d73ff4 100644 --- a/tests/test_bus_integration.py +++ b/tests/test_bus_integration.py @@ -2,12 +2,11 @@ import asyncio -import pytest -from EvoScientist.channels.bus.events import InboundMessage, OutboundMessage +from EvoScientist.channels.bus.events import InboundMessage from EvoScientist.channels.bus.message_bus import MessageBus from EvoScientist.channels.channel_manager import ChannelManager -from EvoScientist.channels.base import Channel, IncomingMessage, OutgoingMessage +from EvoScientist.channels.base import Channel, OutgoingMessage def _run(coro): diff --git a/tests/test_channel_comprehensive.py b/tests/test_channel_comprehensive.py index 9bab9f9..6a15416 100644 --- a/tests/test_channel_comprehensive.py +++ b/tests/test_channel_comprehensive.py @@ -15,13 +15,10 @@ Test groups: from __future__ import annotations import asyncio -import re import time -from collections import OrderedDict from dataclasses import dataclass from datetime import datetime -from typing import Any -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, MagicMock import pytest @@ -38,7 +35,7 @@ from EvoScientist.channels.bus.events import ( OutboundMessage as BusOutbound, ) from EvoScientist.channels.bus.message_bus import MessageBus -from EvoScientist.channels.channel_manager import ChannelManager, ChannelHealth +from EvoScientist.channels.channel_manager import ChannelManager from EvoScientist.channels.consumer import InboundConsumer from EvoScientist.channels.middleware import DedupCache from EvoScientist.channels.retry import RetryConfig, RetryInfo, retry_async @@ -363,7 +360,7 @@ class TestMarkdownUtils: result = convert_markdown( text, - code_block_formatter=lambda l, c: f"[CODE]{c}[/CODE]", + code_block_formatter=lambda lang, c: f"[CODE]{c}[/CODE]", inline_code_formatter=lambda c: f"[IC]{c}[/IC]", inline_rules=[], escape_fn=bad_escape, @@ -382,7 +379,7 @@ class TestMarkdownUtils: text = "Normal text with \x00BLOCK0\x00 in it" result = convert_markdown( text, - code_block_formatter=lambda l, c: f"
{c}
", + code_block_formatter=lambda lang, c: f"
{c}
", inline_code_formatter=lambda c: f"{c}", inline_rules=[], ) @@ -393,7 +390,7 @@ class TestMarkdownUtils: text = "before `` after" result = convert_markdown( text, - code_block_formatter=lambda l, c: c, + code_block_formatter=lambda lang, c: c, inline_code_formatter=lambda c: f"[{c}]", inline_rules=[], ) @@ -1213,7 +1210,7 @@ class TestInboundConsumer: async def _test(): consumer = self._make_consumer() # Start and immediately stop - task = asyncio.create_task(consumer.run()) + asyncio.create_task(consumer.run()) await asyncio.sleep(0.1) await consumer.stop() await asyncio.sleep(0.1) @@ -1232,7 +1229,7 @@ class TestInboundConsumerErrorHandling: ch = StubChannel() mgr.register(ch) - consumer = InboundConsumer( + _consumer = InboundConsumer( bus=bus, manager=mgr, agent=MagicMock(), thread_id="", ) diff --git a/tests/test_channel_manager.py b/tests/test_channel_manager.py index bb45c93..9cd8656 100644 --- a/tests/test_channel_manager.py +++ b/tests/test_channel_manager.py @@ -5,9 +5,8 @@ import asyncio import pytest from EvoScientist.channels.bus.message_bus import MessageBus -from EvoScientist.channels.bus.events import InboundMessage, OutboundMessage from EvoScientist.channels.channel_manager import ChannelManager -from EvoScientist.channels.base import Channel, InboundMessage, OutboundMessage +from EvoScientist.channels.base import Channel, OutboundMessage def _run(coro): diff --git a/tests/test_mention_gating.py b/tests/test_mention_gating.py index 57edf84..842efc8 100644 --- a/tests/test_mention_gating.py +++ b/tests/test_mention_gating.py @@ -3,7 +3,6 @@ import asyncio from dataclasses import dataclass -import pytest from EvoScientist.channels.base import Channel, RawIncoming from EvoScientist.channels.capabilities import ChannelCapabilities diff --git a/tests/test_message_bus.py b/tests/test_message_bus.py index 7e70eb8..700423d 100644 --- a/tests/test_message_bus.py +++ b/tests/test_message_bus.py @@ -2,7 +2,6 @@ import asyncio -import pytest from EvoScientist.channels.bus.events import InboundMessage, OutboundMessage from EvoScientist.channels.bus.message_bus import MessageBus