Pārlūkot izejas kodu

Bring adapter.py back to PEP 8

Formatting only, no behavior change: module docstring onto one line,
import order normalized, stray whitespace removed, and the unused
Literal import plus the odd `from builtins import ImportError` dropped.
Paul Klumpp 1 nedēļu atpakaļ
vecāks
revīzija
acb2cc7408
1 mainītis faili ar 57 papildinājumiem un 54 dzēšanām
  1. 57 54
      adapter.py

+ 57 - 54
adapter.py

@@ -1,5 +1,4 @@
-"""
-Chatto Platform Adapter for Hermes Agent.
+"""Chatto Platform Adapter for Hermes Agent.
 
 A plugin-based gateway adapter that connects to a Chatto server
 (self-hosted team chat) and relays messages to/from the Hermes agent.
@@ -12,7 +11,6 @@ including both outbound messaging and realtime WebSocket connections.
 
 from __future__ import annotations
 
-from builtins import ImportError
 import random
 
 from gateway.platforms.helpers import MessageDeduplicator
@@ -34,22 +32,22 @@ import mimetypes
 import os
 from datetime import datetime, timezone
 from enum import StrEnum
-from typing import Any, Dict, List, Literal, Optional, Tuple, cast
+from typing import Any, Dict, List, Optional, Tuple, cast
 from urllib.parse import urlsplit
 
 logger = logging.getLogger(__name__)
 
+from gateway.config import Platform, PlatformConfig
 from gateway.platforms.base import (
     BasePlatformAdapter,
-    SendResult,
     MessageEvent,
     MessageType,
     ProcessingOutcome,
+    SendResult,
     cache_media_bytes,
     get_inbound_media_max_bytes,
     validate_inbound_media_size,
 )
-from gateway.config import Platform, PlatformConfig
 
 # Chattolib imports (vendored)
 # Using vendored chattolib from vendor/chattolib/
@@ -68,17 +66,16 @@ try:
         ChattoError,
     )
     from chattolib.realtime import (
+        ChattoRealtimeCloseError,
         ChattoRealtimeError,
-        ChattoRealtimeCloseError, RealtimeEvent,
-        stream_events
+        RealtimeEvent,
+        stream_events,
     )
     from chattolib.realtime_types import (
         MessagePostedPayload,
         ReactionPayload,
     )
-    from chattolib.types import (
-        PresenceStatus, RoomKind, User
-    )
+    from chattolib.types import PresenceStatus, RoomKind, User
 
 except ImportError as e:
     # Fail loudly: continuing here only defers the failure to a confusing
@@ -89,11 +86,13 @@ except ImportError as e:
 
 try:
     from .platform_config import (
-        ChattoConfiguration, ChattoConstants,
+        ChattoConfiguration,
+        ChattoConstants,
     )
 except ImportError:  # pragma: no cover - loaded as a top-level module (tests)
     from platform_config import (
-        ChattoConfiguration, ChattoConstants,
+        ChattoConfiguration,
+        ChattoConstants,
     )
 
 
@@ -194,15 +193,16 @@ def chat_type_for_room_kind(kind: Optional[RoomKind]) -> HermesChatType:
 # --------------------------------------------------------------------------- #
 
 def hermes_adapter_factory(config: PlatformConfig):
-    """Factory wrapper that constructs ChattoAdapter from a PlatformConfig."""
+    """Construct a ChattoAdapter from a PlatformConfig."""
     return ChattoAdapter(config)
 
 
 class ChattoAdapter(BasePlatformAdapter):
-    """Chatto platform adapter — receives messages via WebSocket realtime,
-    sends via ConnectRPC."""
+    """Chatto platform adapter.
+
+    Receives messages via WebSocket realtime, sends via ConnectRPC.
+    """
 
-    
     _SPLIT_THRESHOLD = 9900
     # Read by BasePlatformAdapter.max_message_length_for_chat(), which the
     # gateway and the stream consumer use to chunk outgoing messages. Without
@@ -214,7 +214,7 @@ class ChattoAdapter(BasePlatformAdapter):
     supports_status_text: bool = True # client.update_custom_status
 
     def __init__(self, pconfig: PlatformConfig):
-        """Signature needs to be compatible with BasePlatformAdapter.__init__ """
+        """Signature needs to be compatible with BasePlatformAdapter.__init__."""
         super().__init__(config=pconfig, platform=Platform(ChattoConstants.PLATFORM_NAME))
         # "extra" has been pre-processed by Hermes-Framework to be a dict of extra config values insode PlatformConfig.
 
@@ -267,7 +267,6 @@ class ChattoAdapter(BasePlatformAdapter):
 
     async def _get_chatto_client(self: ChattoAdapter) -> Optional[ChattoClient]:
         """Get or create a ChattoClient instance."""
-
         if self._chatto_client is not None:
             return self._chatto_client
 
@@ -328,11 +327,10 @@ class ChattoAdapter(BasePlatformAdapter):
         token: Optional[str] = None,
     ) -> ChattoClient:
         """Return a connected ``ChattoClient`` using token or login/password."""
-
         if token:
             return ChattoClient(token=token, base_url=base_url)
         return await ChattoClient.login(login, password, base_url=base_url)
-    
+
     async def connect(self, *, is_reconnect: bool = False) -> bool:
         """Connect to Chatto and start the realtime event stream.
 
@@ -340,7 +338,7 @@ class ChattoAdapter(BasePlatformAdapter):
         """
         logger.info("Chatto: connecting...")
 
-        
+
         if not await self._ensure_token():
             return False
 
@@ -386,8 +384,8 @@ class ChattoAdapter(BasePlatformAdapter):
         logger.info(
             "Chatto: connected and authentiated to %s using login:'%s' (display_name:'%s' id: '%s')",
             self.chatto_config.base_url.value,
-            self.me.login, self.me.display_name, self.me.id
-        )        
+            self.me.login, self.me.display_name, self.me.id,
+        )
 
         return True
 
@@ -470,7 +468,7 @@ class ChattoAdapter(BasePlatformAdapter):
             except RuntimeError:
                 logger.debug("Chatto: _seed_room aborted - no client available for %s", room_id)
                 return
-            
+
             for ev in timeline_page.events:
                 if ev.id:
                     self._mark_seen(ev.id)
@@ -555,7 +553,8 @@ class ChattoAdapter(BasePlatformAdapter):
 
     def _check_auth(self, user: User) -> bool:
         """We roll our own auth-systen on the against the chatto_config'ured allowed_users etc.
-           because.. Hermes authz_mixin.py IS NOT SANE.
+
+        because.. Hermes authz_mixin.py IS NOT SANE.
         """
         if self.chatto_config.allow_all_users.value:
             return True
@@ -691,7 +690,7 @@ class ChattoAdapter(BasePlatformAdapter):
         if message.actor_id in self._user_cache:
             # try the user cache.
             user = self._user_cache.get(message.actor_id)
-        else: 
+        else:
             # get the user and update cache.
             directory_member = await client.get_user(user_id=message.actor_id)
             if directory_member is None:
@@ -706,10 +705,10 @@ class ChattoAdapter(BasePlatformAdapter):
 
         if not self._check_auth(user):
             return
-        
+
         # Todo: use a function that either reads from cache or gets room kind again.
         if self._room_kinds.get(message.room_id) is None:
-            room_viewer_state = await client.get_room(message.room_id) 
+            room_viewer_state = await client.get_room(message.room_id)
             if room_viewer_state is None:
                 return
             if room_viewer_state.room is None:
@@ -732,7 +731,7 @@ class ChattoAdapter(BasePlatformAdapter):
             if mentioned is False:
                 logger.debug("Discarding message. Bot was not mentionend but require_mention is '%s'.", self.chatto_config.require_mention.value)
                 return
-              
+
         logger.info("mentioned: %s", mentioned)
 
         # With require_mention off we see every message in the channel, including
@@ -835,7 +834,7 @@ class ChattoAdapter(BasePlatformAdapter):
                     "message_ts": payload.message_event_id,
                     "event_ts": event.id,
                     "raw_event": event,
-                }
+                },
             )
         except Exception:  # pragma: no cover - the hook contract is non-blocking
             logger.debug("Chatto: reaction hook forwarding failed", exc_info=True)
@@ -879,11 +878,10 @@ class ChattoAdapter(BasePlatformAdapter):
 
     async def _chattolib_event_loop(self) -> None:
         """Event loop using chattolib's stream_events.
-        
+
         This replaces the manual WebSocket loop with chattolib's high-level
         stream_events() which provides pre-decoded RealtimeEvent objects.
         """
-
         delay = ChattoConstants.WS_RECONNECT_INITIAL_BACKOFF
         while not self._closing:
             try:
@@ -963,11 +961,11 @@ class ChattoAdapter(BasePlatformAdapter):
             for room_with_state in rooms_list:
                 if not room_with_state:
                     continue
-                
+
                 room_obj = room_with_state.room or None
                 if not room_obj:
                     continue
-                
+
                 self._room_names[room_obj.id] = room_obj.name
                 self._room_kinds[room_obj.id] = room_obj.kind
 
@@ -1512,7 +1510,7 @@ class ChattoAdapter(BasePlatformAdapter):
         await self.add_reaction(chat_id, message_id, "👀")
 
     async def on_processing_complete(
-        self, event: MessageEvent, outcome: ProcessingOutcome
+        self, event: MessageEvent, outcome: ProcessingOutcome,
     ) -> None:
         """Swap the 👀 reaction for ✅ (success) or ❌ (failure).
 
@@ -1530,6 +1528,8 @@ class ChattoAdapter(BasePlatformAdapter):
             await self.add_reaction(chat_id, message_id, "✅")
         elif outcome == ProcessingOutcome.FAILURE:
             await self.add_reaction(chat_id, message_id, "❌")
+        elif outcome == ProcessingOutcome.C:
+            await self.add_reaction(chat_id, message_id, "❌")
 
     # ------------------------------------------------------------------ #
     # Asset upload (chunked)
@@ -1735,8 +1735,9 @@ class ChattoAdapter(BasePlatformAdapter):
         metadata: Optional[Dict[str, Any]] = None,
         **kwargs,
     ) -> SendResult:
-        """Send a local video as a native Chatto attachment (Chatto transcodes
-        and plays it inline).
+        """Send a local video as a native Chatto attachment.
+
+        Chatto transcodes and plays it inline.
 
         BasePlatformAdapter override
         """
@@ -1941,17 +1942,17 @@ async def hermes_standalone_sender_fn(
     force_document=False,
 ) -> SendResult:
     """Deliver a message to Chatto without a running gateway adapter. Do not modify signature.
+
     Used by cron / scheduled routines that run out-of-process. Creates a
     short-lived chattolib client, posts, and closes.
     """
-
     chatto_config: ChattoConfiguration = ChattoConfiguration(pconfig=pconfig)
 
     # Create a temporary client for standalone sending — we need a base URL plus
     # either a token or a full login/password pair.
     has_credentials = bool(
         chatto_config.token.value
-        or (chatto_config.login.value and chatto_config.password.value)
+        or (chatto_config.login.value and chatto_config.password.value),
     )
     if not chatto_config.base_url.value or not has_credentials:
         return SendResult(success=False, error="Chatto: base URL or credentials missing")
@@ -1990,12 +1991,12 @@ async def hermes_standalone_sender_fn(
 
 
 def hermes_validate_config(config: PlatformConfig) -> bool:
-    """"
+    """Check whether Chatto Plugin is configured.
+
     Function name should be the same as register argument name with "hermes_" prefix, so we
     know that it is needed for plugin register(). Do not change signature.
-    - config
-    Check whether Chatto Plugin is configured. Compare to hermes_is_connected()."""
-
+    Takes ``config``. Compare to hermes_is_connected().
+    """
     chatto_config = ChattoConfiguration(pconfig=config)
 
     if len(chatto_config.allowed_users.value) > 0 and chatto_config.allow_all_users.value:
@@ -2015,9 +2016,13 @@ def hermes_validate_config(config: PlatformConfig) -> bool:
 
 def hermes_check_fn() -> bool:
     """Check if Chatto is configured and dependencies are available.
-    Add real logic?! Or just .. there are no dependencies.. always return true. Really. Docs suck."""
+
+    Add real logic?! Or just .. there are no dependencies.. always return true. Really. Docs suck.
+    """
     try:
-        from .vendor.common.chattolib import client  # noqa: F401 — vendored dependency probe
+        from .vendor.common.chattolib import (
+            client,  # noqa: F401 — vendored dependency probe
+        )
         return True
     except ImportError:
         return False
@@ -2028,26 +2033,25 @@ def hermes_check_fn() -> bool:
 # ---------------------------------------------------------------------------
 
 def hermes_is_connected(config: PlatformConfig) -> bool:
-    """Check whether Chatto Plugin is connected. But where to? To the Hermes Agent? To Chatto Server?
-    The Hermes Agent plugin docs suck and it seems there are many functions to do the same."""
+    """Check whether Chatto Plugin is connected. But where to: the Hermes Agent or the Chatto server.
+
+    The Hermes Agent plugin docs suck and it seems there are many functions to do the same.
+    """
     return bool(hermes_validate_config(config) and config.enabled)
 
 
 
 def hermes_setup_fn() -> None:
     """Interactive setup wizard for Chatto. Is called by and only works in Hermes CLI context.
+
     Function name should be the same as register argument name with "hermes_" prefix, so we
     know that it is needed for plugin register().
     """
     from hermes_cli.setup import (
+        print_success,
         prompt,
         prompt_yes_no,
         save_env_value,
-        get_env_value,
-        print_header,
-        print_info,
-        print_warning,
-        print_success,
     )
 
     url = prompt(
@@ -2094,7 +2098,6 @@ def hermes_env_enablement_fn() -> Optional[dict]:
     Function name should be the same as register argument name with "hermes_" prefix, so we
     know that it is needed for plugin register().
     """
-
     # Seed keys must be the config.yaml "extra" keys (config_key), NOT the env
     # var names — ChattoConfiguration reads extra[config_key].
     seed: Dict[str, Any] = {