from abc import ABCMeta, abstractmethod from collections.abc import Generator, Iterable from typing import Literal, Never, Self, Unpack, override from mido.messages.specs import MsgDict, MsgDictOverride class BaseMessage(metaclass=ABCMeta): """Abstract base class for messages.""" @property @abstractmethod def is_meta(self) -> bool: ... # a normal attribute in runtime @abstractmethod def copy(self) -> Self: ... @abstractmethod def bytes(self) -> list[int]: ... def bin(self) -> bytearray: """Encode message and return as a bytearray. This can be used to write the message to a file. """ def hex(self, sep: str = " ") -> str: """Encode message and return as a string of hex numbers, Each number is separated by the string sep. """ def dict(self) -> MsgDict: """Returns a dictionary containing the attributes of the message. Example: `{'type': 'sysex', 'data': [1, 2], 'time': 0}` Sysex data will be returned as a list. """ @classmethod def from_dict(cls, data: MsgDict) -> Self: """Create a message from a dictionary. Only "type" is required. The other will be set to default values. """ @property def is_realtime(self) -> bool: """True if the message is a system realtime message.""" def is_cc(self, control: int | None = ...) -> bool: """Return True if the message is of type 'control_change'. The optional control argument can be used to test for a specific control number, for example: >>> if msg.is_cc(7): ... # Message is control change 7 (channel volume). """ @override def __delattr__(self, name: str) -> Never: ... @override def __setattr__(self, name: str, value: object) -> None: ... @override def __eq__(self, other: object) -> bool: ... class SysexData(tuple[int, ...]): """Special kind of tuple accepts and converts any sequence in `+=`.""" def __iadd__(self, other: SysexData) -> Self: ... class Message(BaseMessage): type: str time: int @property @override def is_meta(self) -> Literal[False]: ... # a normal attribute in runtime def __init__(self, type: str, skip_checks: bool = False, **args: Unpack[MsgDictOverride]) -> None: ... @override def copy(self, skip_checks: bool = False, **overrides: Unpack[MsgDictOverride]) -> Self: """Return a copy of the message. Attributes will be overridden by the passed keyword arguments. Only message specific attributes can be overridden. The message type can not be changed. The `skip_checks` arg can be used to bypass validation of message attributes and should be used cautiously. """ @classmethod def from_bytes(cls, data: Iterable[int], time: int = 0) -> Self: """Parse a byte encoded message. Accepts a byte string or any iterable of integers. This is the reverse of `msg.bytes()` or `msg.bin()`. """ @classmethod def from_hex(cls, text: str, time: int = 0, sep: str | None = ...) -> Self: """Parse a hex encoded message. This is the reverse of `msg.hex()`. """ @classmethod def from_str(cls, text: str) -> Self: """Parse a string encoded message. This is the reverse of `str(msg)`. """ def __len__(self) -> int: ... @override def __setattr__(self, name: str, value: object) -> None: ... @override def bytes(self) -> list[int]: """Encode message and return as a list of integers.""" def parse_string(text: str) -> Message: """Parse a string of text and return a message. The string can span multiple lines, but must contain one full message. Raises ValueError if the string could not be parsed. """ def parse_string_stream(stream: Iterable[str]) -> Generator[tuple[Message, None] | tuple[None, str], Never]: """Parse a stream of messages and yield `(message, error_message)` stream can be any iterable that generates text strings, where each string is a string encoded message. If a string can be parsed, `(message, None)` is returned. If it can't be parsed, `(None, error_message)` is returned. The error message contains the line number where the error occurred. """ def format_as_string(msg: Message, include_time: bool = True) -> str: """Format a message and return as a string. This is equivalent to `str(message)`. To leave out the time attribute, pass `include_time=False`. """