diff --git a/ahtcg_bot.py b/ahtcg_bot.py index 03dbff1..cb951b2 100755 --- a/ahtcg_bot.py +++ b/ahtcg_bot.py @@ -19,7 +19,7 @@ class ArkhamDBUpdater(commands.Bot): super().__init__(*args, **kwargs) # TODO: should really be a database - with open('channel_list.json') as f: + with open("channel_list.json") as f: self.channel_list = set(json.load(f)) self.arkhamdb_client = ArkhamDBClient() @@ -30,35 +30,42 @@ class ArkhamDBUpdater(commands.Bot): await super().close() def setup_commands(self) -> None: - @self.command(name='monitor') + @self.command(name="monitor") async def monitor(ctx: commands.Context) -> None: """Watch this channel for deck links and link to latest versions.""" - await ctx.message.reply('Now monitoring this channel for deck IDs', mention_author=True) + await ctx.message.reply( + "Now monitoring this channel for deck IDs", mention_author=True + ) self.channel_list.add(ctx.message.channel.id) - with open('channel_list.json', 'w') as f: + with open("channel_list.json", "w") as f: json.dump(list(self.channel_list), f) - @self.command(name='forget') + @self.command(name="forget") async def forget(ctx: commands.Context) -> None: """Remove this channel from the monitor list""" - await ctx.message.reply('No longer monitoring this channel for deck IDs', mention_author=True) + await ctx.message.reply( + "No longer monitoring this channel for deck IDs", mention_author=True + ) self.channel_list.discard(ctx.message.channel.id) - with open('channel_list.json', 'w') as f: + with open("channel_list.json", "w") as f: json.dump(list(self.channel_list), f) async def on_ready(self) -> None: - print(f'Logged in as {self.user} (ID: {self.user.id})') - print('Enabled on servers:') + print(f"Logged in as {self.user} (ID: {self.user.id})") + print("Enabled on servers:") async for guild in self.fetch_guilds(limit=150): - print(' -', guild.name) - print('------') + print(" -", guild.name) + print("------") self.arkhamdb_monitor.start() async def gather_deck_ids(self, channel: discord.TextChannel) -> dict[int, str]: deck_ids: dict[int, str] = {} url_regex = re.compile( - r'(?P.*)' + self.arkhamdb_client.origin + r'/deck/view/(?P\d+)') + r"(?P.*)" + + self.arkhamdb_client.origin + + r"/deck/view/(?P\d+)" + ) async for message in channel.history(limit=200, oldest_first=True): # ignore the bot's messages if message.author.id == self.user.id: @@ -66,19 +73,21 @@ class ArkhamDBUpdater(commands.Bot): matches = url_regex.finditer(message.content) for match in matches: - deck_ids[int(match.group('deck_id'))] = match.group('prefix') + deck_ids[int(match.group("deck_id"))] = match.group("prefix") return deck_ids async def clear_old_messages(self, channel: discord.TextChannel) -> None: async for message in channel.history(limit=200): - if message.author.id == self.user.id \ - and message.id != channel.last_message_id \ - and len(message.embeds) == 1: + if ( + message.author.id == self.user.id + and message.id != channel.last_message_id + and len(message.embeds) == 1 + ): await message.delete() def status_for_deck(self, prefix: str, deck: ArkhamDBDeck) -> str: - unspent_xp = deck['xp'] - deck['xp_spent'] + unspent_xp = deck["xp"] - deck["xp_spent"] status = f"{prefix}[{deck['name']}]({self.arkhamdb_client.origin}/deck/view/{deck['id']}) [{deck['id']}]" if unspent_xp > 0: status += f" {{{unspent_xp} unspent XP}}" @@ -86,7 +95,7 @@ class ArkhamDBUpdater(commands.Bot): return status async def update_channel_latest_decks(self, channel: discord.TextChannel) -> None: - print(f'Running update in channel {channel.guild} - {channel.name}') + print(f"Running update in channel {channel.guild} - {channel.name}") async with channel.typing(): deck_ids = await self.gather_deck_ids(channel) latest_decks = await self.arkhamdb_client.get_latest_decks(deck_ids) @@ -98,15 +107,19 @@ class ArkhamDBUpdater(commands.Bot): except discord.NotFound: last_message = None - message_text = '\n'.join(self.status_for_deck(prefix, deck) - for prefix, deck in latest_decks.values()) + message_text = "\n".join( + self.status_for_deck(prefix, deck) + for prefix, deck in latest_decks.values() + ) message_embed = discord.Embed( - title=f'Updated as of {datetime.now()}', - description=message_text) + title=f"Updated as of {datetime.now()}", description=message_text + ) - if last_message is not None \ - and last_message.author.id == self.user.id \ - and len(last_message.embeds) == 1: + if ( + last_message is not None + and last_message.author.id == self.user.id + and len(last_message.embeds) == 1 + ): if message_text != last_message.embeds[0].description: await last_message.edit(embed=message_embed) else: @@ -114,15 +127,19 @@ class ArkhamDBUpdater(commands.Bot): async def maybe_update_channel_for_message(self, message: discord.Message) -> None: # don't to react to the bot's changes, and only update registered channels - if message.author.id != self.user.id and \ - message.channel.id in self.channel_list: + if ( + message.author.id != self.user.id + and message.channel.id in self.channel_list + ): await self.update_channel_latest_decks(message.channel) async def on_message(self, message: discord.Message) -> None: await self.process_commands(message) await self.maybe_update_channel_for_message(message) - async def on_message_edit(self, before: discord.Message, after: discord.Message) -> None: + async def on_message_edit( + self, before: discord.Message, after: discord.Message + ) -> None: await self.maybe_update_channel_for_message(after) async def on_message_delete(self, message: discord.Message) -> None: @@ -135,5 +152,5 @@ class ArkhamDBUpdater(commands.Bot): await self.update_channel_latest_decks(channel) -bot = ArkhamDBUpdater(command_prefix='!arkhamdb ') +bot = ArkhamDBUpdater(command_prefix="!arkhamdb ") bot.run(TOKEN, reconnect=True) diff --git a/arkhamdb.py b/arkhamdb.py index 1f19a0f..b53b695 100644 --- a/arkhamdb.py +++ b/arkhamdb.py @@ -2,7 +2,7 @@ from typing import TypedDict, Optional, Union import aiohttp -ARKHAMDB_ORIGIN = 'https://arkhamdb.adamgoldsmith.name' +ARKHAMDB_ORIGIN = "https://arkhamdb.adamgoldsmith.name" class ArkhamDBDeck(TypedDict): @@ -29,6 +29,7 @@ class ArkhamDBDeck(TypedDict): next_deck: int problem: Optional[str] + class ArkhamDBClient: _session: aiohttp.ClientSession @@ -46,18 +47,21 @@ class ArkhamDBClient: deck = None while deck is None or deck["next_deck"] is not None: async with self._session.get( - self.origin + f"/api/public/deck/{next_deck_id}.json") as resp: + self.origin + f"/api/public/deck/{next_deck_id}.json" + ) as resp: deck = await resp.json() next_deck_id = deck["next_deck"] return deck - async def get_latest_decks(self, deck_ids: dict[int, str]) -> dict[int, tuple[str, ArkhamDBDeck]]: + async def get_latest_decks( + self, deck_ids: dict[int, str] + ) -> dict[int, tuple[str, ArkhamDBDeck]]: latest_decks: dict[int, tuple[str, ArkhamDBDeck]] = {} for deck_id, prefix in deck_ids.items(): try: deck = await self.get_latest_deck(deck_id) - latest_decks[deck['id']] = (prefix, deck) + latest_decks[deck["id"]] = (prefix, deck) except aiohttp.ContentTypeError: # TODO: json was invalid, should probably alert user pass diff --git a/pdm.lock b/pdm.lock index 5c449e3..257f606 100644 --- a/pdm.lock +++ b/pdm.lock @@ -24,12 +24,40 @@ version = "21.4.0" requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" summary = "Classes Without Boilerplate" +[[package]] +name = "black" +version = "22.1.0" +requires_python = ">=3.6.2" +summary = "The uncompromising code formatter." +dependencies = [ + "click>=8.0.0", + "mypy-extensions>=0.4.3", + "pathspec>=0.9.0", + "platformdirs>=2", + "tomli>=1.1.0", +] + [[package]] name = "chardet" version = "4.0.0" requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" summary = "Universal encoding detector for Python 2 and 3" +[[package]] +name = "click" +version = "8.0.4" +requires_python = ">=3.6" +summary = "Composable command line interface toolkit" +dependencies = [ + "colorama; platform_system == \"Windows\"", +] + +[[package]] +name = "colorama" +version = "0.4.4" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "Cross-platform colored terminal text." + [[package]] name = "discord.py" version = "1.7.3" @@ -51,6 +79,29 @@ version = "6.0.2" requires_python = ">=3.7" summary = "multidict implementation" +[[package]] +name = "mypy-extensions" +version = "0.4.3" +summary = "Experimental type system extensions for programs checked with the mypy typechecker." + +[[package]] +name = "pathspec" +version = "0.9.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +summary = "Utility library for gitignore style pattern matching of file paths." + +[[package]] +name = "platformdirs" +version = "2.5.1" +requires_python = ">=3.7" +summary = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." + +[[package]] +name = "tomli" +version = "2.0.1" +requires_python = ">=3.7" +summary = "A lil' TOML parser" + [[package]] name = "typing-extensions" version = "4.1.1" @@ -69,7 +120,7 @@ dependencies = [ [metadata] lock_version = "3.1" -content_hash = "sha256:606c5f38b9e3a2695bca366d583b87b1ff6289246353eff07a168e8ce54305df" +content_hash = "sha256:da292ccf4e3850e904927e30412026e99f5618b549b8de606742ccc0f6e03d64" [metadata.files] "aiohttp 3.7.4.post0" = [ @@ -119,10 +170,43 @@ content_hash = "sha256:606c5f38b9e3a2695bca366d583b87b1ff6289246353eff07a168e8ce {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] +"black 22.1.0" = [ + {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, + {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, + {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, + {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, + {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, + {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, + {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, + {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, + {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, + {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, + {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, + {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, + {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, + {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, + {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, + {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, + {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, + {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, + {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, + {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, + {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, + {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, + {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, +] "chardet 4.0.0" = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] +"click 8.0.4" = [ + {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, + {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, +] +"colorama 0.4.4" = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] "discord.py 1.7.3" = [ {file = "discord.py-1.7.3-py3-none-any.whl", hash = "sha256:c6f64db136de0e18e090f6752ea68bdd4ab0a61b82dfe7acecefa22d6477bb0c"}, {file = "discord.py-1.7.3.tar.gz", hash = "sha256:462cd0fe307aef8b29cbfa8dd613e548ae4b2cb581d46da9ac0d46fb6ea19408"}, @@ -192,6 +276,22 @@ content_hash = "sha256:606c5f38b9e3a2695bca366d583b87b1ff6289246353eff07a168e8ce {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, ] +"mypy-extensions 0.4.3" = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +"pathspec 0.9.0" = [ + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] +"platformdirs 2.5.1" = [ + {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, + {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, +] +"tomli 2.0.1" = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] "typing-extensions 4.1.1" = [ {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, diff --git a/pyproject.toml b/pyproject.toml index 9b3ce29..c512fbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,9 @@ verify_ssl = true name = "pypi" [tool.pdm.dev-dependencies] -dev = [] +format = [ + "black~=22.1", +] [project] # PEP 621 project metadata @@ -16,7 +18,10 @@ dependencies = [ "discord.py>=1.7.3", "aiohttp>=3.7.4.post0", ] +[project.optional-dependencies] [build-system] requires = ["pdm-pep517"] build-backend = "pdm.pep517.api" + +[tool.black]