diff --git a/my_project_name/bot_commands.py b/my_project_name/bot_commands.py index 576bd8b..1dfa608 100644 --- a/my_project_name/bot_commands.py +++ b/my_project_name/bot_commands.py @@ -43,8 +43,10 @@ class Command(object): async def _show_help(self): """Show the help text""" if not self.args: - text = ("Hello, I am a bot made with matrix-nio! Use `help commands` to view " - "available commands.") + text = ( + "Hello, I am a bot made with matrix-nio! Use `help commands` to view " + "available commands." + ) await send_text_to_room(self.client, self.room.room_id, text) return diff --git a/my_project_name/callbacks.py b/my_project_name/callbacks.py index fcc7a64..4d09bea 100644 --- a/my_project_name/callbacks.py +++ b/my_project_name/callbacks.py @@ -1,15 +1,14 @@ +import logging + +from nio import JoinError + from my_project_name.bot_commands import Command -from nio import ( - JoinError, -) from my_project_name.message_responses import Message -import logging logger = logging.getLogger(__name__) class Callbacks(object): - def __init__(self, client, store, config): """ Args: @@ -57,7 +56,7 @@ class Callbacks(object): # treat it as a command if has_command_prefix: # Remove the command prefix - msg = msg[len(self.command_prefix):] + msg = msg[len(self.command_prefix) :] command = Command(self.client, self.store, self.config, msg, room, event) await command.process() @@ -72,7 +71,8 @@ class Callbacks(object): if type(result) == JoinError: logger.error( f"Error joining room {room.room_id} (attempt %d): %s", - attempt, result.message, + attempt, + result.message, ) else: break diff --git a/my_project_name/chat_functions.py b/my_project_name/chat_functions.py index fd6ffc5..7e480a8 100644 --- a/my_project_name/chat_functions.py +++ b/my_project_name/chat_functions.py @@ -1,18 +1,13 @@ import logging -from nio import ( - SendRetryError -) + from markdown import markdown +from nio import SendRetryError logger = logging.getLogger(__name__) async def send_text_to_room( - client, - room_id, - message, - notice=True, - markdown_convert=True + client, room_id, message, notice=True, markdown_convert=True ): """Send text to a matrix room @@ -43,11 +38,7 @@ async def send_text_to_room( try: await client.room_send( - room_id, - "m.room.message", - content, - ignore_unverified_devices=True, + room_id, "m.room.message", content, ignore_unverified_devices=True, ) except SendRetryError: logger.exception(f"Unable to send message response to {room_id}") - diff --git a/my_project_name/config.py b/my_project_name/config.py index f55b7b0..292895f 100644 --- a/my_project_name/config.py +++ b/my_project_name/config.py @@ -1,9 +1,11 @@ import logging -import re import os -import yaml +import re import sys -from typing import List, Any +from typing import Any, List + +import yaml + from my_project_name.errors import ConfigError logger = logging.getLogger() @@ -23,34 +25,48 @@ class Config(object): self.config = yaml.safe_load(file_stream.read()) # Logging setup - formatter = logging.Formatter('%(asctime)s | %(name)s [%(levelname)s] %(message)s') + formatter = logging.Formatter( + "%(asctime)s | %(name)s [%(levelname)s] %(message)s" + ) log_level = self._get_cfg(["logging", "level"], default="INFO") logger.setLevel(log_level) - file_logging_enabled = self._get_cfg(["logging", "file_logging", "enabled"], default=False) - file_logging_filepath = self._get_cfg(["logging", "file_logging", "filepath"], default="bot.log") + file_logging_enabled = self._get_cfg( + ["logging", "file_logging", "enabled"], default=False + ) + file_logging_filepath = self._get_cfg( + ["logging", "file_logging", "filepath"], default="bot.log" + ) if file_logging_enabled: handler = logging.FileHandler(file_logging_filepath) handler.setFormatter(formatter) logger.addHandler(handler) - console_logging_enabled = self._get_cfg(["logging", "console_logging", "enabled"], default=True) + console_logging_enabled = self._get_cfg( + ["logging", "console_logging", "enabled"], default=True + ) if console_logging_enabled: handler = logging.StreamHandler(sys.stdout) handler.setFormatter(formatter) logger.addHandler(handler) # Storage setup - self.database_filepath = self._get_cfg(["storage", "database_filepath"], required=True) - self.store_filepath = self._get_cfg(["storage", "store_filepath"], required=True) + self.database_filepath = self._get_cfg( + ["storage", "database_filepath"], required=True + ) + self.store_filepath = self._get_cfg( + ["storage", "store_filepath"], required=True + ) # Create the store folder if it doesn't exist if not os.path.isdir(self.store_filepath): if not os.path.exists(self.store_filepath): os.mkdir(self.store_filepath) else: - raise ConfigError(f"storage.store_filepath '{self.store_filepath}' is not a directory") + raise ConfigError( + f"storage.store_filepath '{self.store_filepath}' is not a directory" + ) # Matrix bot account setup self.user_id = self._get_cfg(["matrix", "user_id"], required=True) @@ -59,16 +75,15 @@ class Config(object): self.user_password = self._get_cfg(["matrix", "user_password"], required=True) self.device_id = self._get_cfg(["matrix", "device_id"], required=True) - self.device_name = self._get_cfg(["matrix", "device_name"], default="nio-template") + self.device_name = self._get_cfg( + ["matrix", "device_name"], default="nio-template" + ) self.homeserver_url = self._get_cfg(["matrix", "homeserver_url"], required=True) self.command_prefix = self._get_cfg(["command_prefix"], default="!c") + " " def _get_cfg( - self, - path: List[str], - default: Any = None, - required: bool = True, + self, path: List[str], default: Any = None, required: bool = True, ) -> Any: """Get a config option from a path and option name, specifying whether it is required. diff --git a/my_project_name/errors.py b/my_project_name/errors.py index ec4284e..5b7887c 100644 --- a/my_project_name/errors.py +++ b/my_project_name/errors.py @@ -4,5 +4,6 @@ class ConfigError(RuntimeError): Args: msg (str): The message displayed to the user on error """ + def __init__(self, msg): - super(ConfigError, self).__init__("%s" % (msg,)) \ No newline at end of file + super(ConfigError, self).__init__("%s" % (msg,)) diff --git a/my_project_name/main.py b/my_project_name/main.py index c29ec97..1081f7a 100644 --- a/my_project_name/main.py +++ b/my_project_name/main.py @@ -1,21 +1,19 @@ #!/usr/bin/env python3 - -import logging import asyncio +import logging import sys from time import sleep + +from aiohttp import ClientConnectionError, ServerDisconnectedError from nio import ( AsyncClient, AsyncClientConfig, - RoomMessageText, InviteMemberEvent, - LoginError, LocalProtocolError, + LoginError, + RoomMessageText, ) -from aiohttp import ( - ServerDisconnectedError, - ClientConnectionError -) + from my_project_name.callbacks import Callbacks from my_project_name.config import Config from my_project_name.storage import Storage @@ -64,13 +62,12 @@ async def main(): # Try to login with the configured username/password try: login_response = await client.login( - password=config.user_password, - device_name=config.device_name, + password=config.user_password, device_name=config.device_name, ) # Check if login failed if type(login_response) == LoginError: - logger.error(f"Failed to login: %s", login_response.message) + logger.error("Failed to login: %s", login_response.message) return False except LocalProtocolError as e: # There's an edge case here where the user hasn't installed the correct C @@ -78,7 +75,8 @@ async def main(): logger.fatal( "Failed to login. Have you installed the correct dependencies? " "https://github.com/poljar/matrix-nio#installation " - "Error: %s", e + "Error: %s", + e, ) return False @@ -101,4 +99,5 @@ async def main(): # Make sure to close the client connection on disconnect await client.close() + asyncio.get_event_loop().run_until_complete(main()) diff --git a/my_project_name/message_responses.py b/my_project_name/message_responses.py index d4beab7..006888d 100644 --- a/my_project_name/message_responses.py +++ b/my_project_name/message_responses.py @@ -1,11 +1,11 @@ -from my_project_name.chat_functions import send_text_to_room import logging +from my_project_name.chat_functions import send_text_to_room + logger = logging.getLogger(__name__) class Message(object): - def __init__(self, client, store, config, message_content, room, event): """Initialize a new Message @@ -38,4 +38,3 @@ class Message(object): """Say hello""" text = "Hello, world!" await send_text_to_room(self.client, self.room.room_id, text) - diff --git a/my_project_name/storage.py b/my_project_name/storage.py index 65473df..eeb5e38 100644 --- a/my_project_name/storage.py +++ b/my_project_name/storage.py @@ -1,6 +1,6 @@ -import sqlite3 -import os.path import logging +import os.path +import sqlite3 latest_db_version = 0 @@ -34,10 +34,12 @@ class Storage(object): self.cursor = self.conn.cursor() # Sync token table - self.cursor.execute("CREATE TABLE sync_token (" - "dedupe_id INTEGER PRIMARY KEY, " - "token TEXT NOT NULL" - ")") + self.cursor.execute( + "CREATE TABLE sync_token (" + "dedupe_id INTEGER PRIMARY KEY, " + "token TEXT NOT NULL" + ")" + ) logger.info("Database setup complete") diff --git a/scripts-dev/lint.sh b/scripts-dev/lint.sh new file mode 100755 index 0000000..b5996aa --- /dev/null +++ b/scripts-dev/lint.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# +# Runs linting scripts over the local checkout +# isort - sorts import statements +# flake8 - lints and finds mistakes +# black - opinionated code formatter + +set -e + +if [ $# -ge 1 ] +then + files=$* + else + files="my_project_name my-project-name" +fi + +echo "Linting these locations: $files" +isort $files +flake8 $files +python3 -m black $files diff --git a/setup.cfg b/setup.cfg index 9a8e15b..60ce4af 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,7 @@ ignore=W503,W504,E203,E731,E501 [isort] line_length = 88 -sections=FUTURE,STDLIB,COMPAT,THIRDPARTY,FIRSTPARTY,TESTS,LOCALFOLDER +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,TESTS,LOCALFOLDER default_section=THIRDPARTY known_first_party=my_project_name known_tests=tests