From 01145ab926a0bbd099bbf79f39106a1d442f9d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erkki=20Sepp=C3=A4l=C3=A4?= Date: Wed, 8 Mar 2023 21:36:43 +0200 Subject: [PATCH] commands: remove content includign and after # to support commments Closes #17. --- README.md | 4 +++- teslabot/commands.py | 8 +++++--- teslabot/control.py | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7c5e4dc..5791373 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ You can use e.g. `screen`, `tmux` or `systemd` to arrange this process to run on Note that by default you need to prefix commands with ```!```. | command | description | -| --- | --- | +|---------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| | help | Show the list of commands supported. | | authorize | Start the authorization flow. Works only in admin room (though you could only have one and same for control and admin). | | authorize url | Last phase of the authorization flow. | @@ -168,3 +168,5 @@ Note that by default you need to prefix commands with ```!```. | charge schedule disable | Disable charging schedule. | | heater seat n off/low/medium/high | Adjust seat heaters. Works only if AC is on. | | heater steering off/high | Adjust steering wheel heater. Works only if AC is on. | +| command # comment | Run command; ignore # comment | +| # comment | Ignore message | diff --git a/teslabot/commands.py b/teslabot/commands.py index 31b8814..6da0303 100644 --- a/teslabot/commands.py +++ b/teslabot/commands.py @@ -4,6 +4,7 @@ from abc import ABC, abstractmethod from typing import List, Callable, Coroutine, Any, TypeVar, Generic, Optional, Tuple, Mapping, Union, Awaitable from .parser import Parser, ParseResult, ParseOK, ParseFail +from .utils import assert_some from . import log @@ -20,7 +21,7 @@ class CommandsException(Exception): class ParseError(CommandsException): pass -class InvocationParseError(ParseError): +class InvocationEmptyError(ParseError): pass @dataclass @@ -45,13 +46,14 @@ class Invocation: @staticmethod def parse(message: str) -> "Invocation": - fields = [field for field in re.split(r" *", message) if field != ""] + command = assert_some(re.match(r"^[^#]*", message), "This should always match")[0] # extract non-comment part + fields = [field for field in re.split(r" *", command) if field != ""] if len(fields): logger.debug(f"Command: {fields}") return Invocation(name=fields[0], args=fields[1:]) else: - raise InvocationParseError() + raise InvocationEmptyError() class Command(ABC, Generic[Context]): name: str diff --git a/teslabot/control.py b/teslabot/control.py index b4d54dd..a0d5347 100644 --- a/teslabot/control.py +++ b/teslabot/control.py @@ -84,6 +84,8 @@ async def process_message(self, command_context: CommandContext, message: str) - await self.local_commands.invoke(command_context, invocation) else: await self.callback.command_callback(command_context, invocation) + except commands.InvocationEmptyError as exn: + logger.debug("Ignoring empty message (or completely commented)") except commands.CommandParseError as exn: logger.error(f"{command_context.txn}: Failed to parse command: {message}") def format(word: str, highlight: bool) -> str: