Source code for efro.message._module

# Released under the MIT License. See LICENSE for details.
#
"""Functionality for sending and responding to messages.
Supports static typing for message types and possible return types.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from efro.message._protocol import MessageProtocol

if TYPE_CHECKING:
    pass


[docs] def create_sender_module( basename: str, protocol_create_code: str, enable_sync_sends: bool, enable_async_sends: bool, *, private: bool = False, protocol_module_level_import_code: str | None = None, build_time_protocol_create_code: str | None = None, ) -> str: """Create a Python module defining a MessageSender subclass. This class is primarily for type checking and will contain overrides for the varieties of send calls for message/response types defined in the protocol. Code passed for 'protocol_create_code' should import necessary modules and assign an instance of the Protocol to a 'protocol' variable. Class names are based on basename; a basename 'FooSender' will result in classes FooSender and BoundFooSender. If 'private' is True, class-names will be prefixed with an '_'. Note: output code may have long lines and should generally be run through a formatter. We should perhaps move this functionality to efrotools so we can include that functionality inline. """ protocol = _protocol_from_code( build_time_protocol_create_code if build_time_protocol_create_code is not None else protocol_create_code ) return protocol.do_create_sender_module( basename=basename, protocol_create_code=protocol_create_code, enable_sync_sends=enable_sync_sends, enable_async_sends=enable_async_sends, private=private, protocol_module_level_import_code=protocol_module_level_import_code, )
[docs] def create_receiver_module( basename: str, protocol_create_code: str, is_async: bool, *, private: bool = False, protocol_module_level_import_code: str | None = None, build_time_protocol_create_code: str | None = None, ) -> str: """ "Create a Python module defining a MessageReceiver subclass. This class is primarily for type checking and will contain overrides for the register method for message/response types defined in the protocol. Class names are based on basename; a basename 'FooReceiver' will result in FooReceiver and BoundFooReceiver. If 'is_async' is True, handle_raw_message() will be an async method and the @handler decorator will expect async methods. If 'private' is True, class-names will be prefixed with an '_'. Note that line lengths are not clipped, so output may need to be run through a formatter to prevent lint warnings about excessive line lengths. """ protocol = _protocol_from_code( build_time_protocol_create_code if build_time_protocol_create_code is not None else protocol_create_code ) return protocol.do_create_receiver_module( basename=basename, protocol_create_code=protocol_create_code, is_async=is_async, private=private, protocol_module_level_import_code=protocol_module_level_import_code, )
def _protocol_from_code(protocol_create_code: str) -> MessageProtocol: env: dict = {} exec(protocol_create_code, env) # pylint: disable=exec-used protocol = env.get('protocol') if not isinstance(protocol, MessageProtocol): raise RuntimeError( f'protocol_create_code yielded' f' a {type(protocol)}; expected a MessageProtocol instance.' ) return protocol # Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum