From 6abb3b871b284ab678051258d2ee6db65ed13378 Mon Sep 17 00:00:00 2001 From: Luke Tainton Date: Fri, 6 Jun 2025 18:31:41 +0100 Subject: [PATCH 1/4] fix(lint): Fix linting issues --- app/close.py | 20 +++++++++++++++++--- app/img.py | 25 +++++++++++++++++++++++++ app/main.py | 3 +++ app/meme.py | 33 ++++++++++++++++++++++++++------- tests/test_config.py | 13 ++++++++----- 5 files changed, 79 insertions(+), 15 deletions(-) diff --git a/app/close.py b/app/close.py index 304369c..6565749 100644 --- a/app/close.py +++ b/app/close.py @@ -1,8 +1,13 @@ +"""Command module for handling the 'exit' command in the Webex meme bot.""" + from webex_bot.models.command import Command class ExitCommand(Command): + """Command to handle the 'exit' command in the Webex meme bot.""" + def __init__(self) -> None: + """Initialize the ExitCommand with command keyword and help message.""" super().__init__( command_keyword="exit", help_message="Exit", @@ -10,11 +15,20 @@ class ExitCommand(Command): ) self.sender: str = "" - def pre_execute(self, message, attachment_actions, activity) -> None: + def pre_execute( + self, message, attachment_actions, activity + ) -> None: # pylint: disable=unused-argument + """Pre-execution logic for the exit command.""" return - def execute(self, message, attachment_actions, activity) -> None: + def execute( + self, message, attachment_actions, activity + ) -> None: # pylint: disable=unused-argument + """Execute the exit command.""" return - def post_execute(self, message, attachment_actions, activity) -> None: + def post_execute( + self, message, attachment_actions, activity + ) -> None: # pylint: disable=unused-argument + """Post-execution logic for the exit command.""" return diff --git a/app/img.py b/app/img.py index 6a5e19f..ad4c1ea 100644 --- a/app/img.py +++ b/app/img.py @@ -1,3 +1,5 @@ +"""Generates meme images using the memegen.link API.""" + import requests CHAR_REPLACEMENTS: list = [ @@ -17,6 +19,11 @@ CHAR_REPLACEMENTS: list = [ def get_templates() -> list[dict]: + """Fetches available meme templates from the memegen.link API. + + Returns: + list[dict]: A list of dictionaries containing meme template information. + """ url: str = "https://api.memegen.link/templates" req: requests.Response = requests.get(url=url, timeout=10) req.raise_for_status() @@ -40,6 +47,14 @@ def get_templates() -> list[dict]: def format_meme_string(input_string: str) -> str: + """Formats a string for use in a meme image URL. + + Args: + input_string (str): The string to format. + + Returns: + str: The formatted string suitable for meme image URLs. + """ # https://memegen.link/#special-characters out_string: str = input_string for char_replacement in CHAR_REPLACEMENTS: @@ -48,6 +63,16 @@ def format_meme_string(input_string: str) -> str: def generate_api_url(template: str, top_str: str, btm_str: str) -> str: + """Generates a meme image URL using the memegen.link API. + + Args: + template (str): The template identifier in the format "name.ext". + top_str (str): The text for the top line of the meme. + btm_str (str): The text for the bottom line of the meme. + + Returns: + str: The complete URL for the meme image. + """ tmpl_name: str tmpl_ext: str tmpl_name, tmpl_ext = template.split(".") diff --git a/app/main.py b/app/main.py index d8bd01f..13c299b 100644 --- a/app/main.py +++ b/app/main.py @@ -1,5 +1,7 @@ #!/usr/local/bin/python3 +"""Main entry point for the Webex Bot application.""" + from webex_bot.webex_bot import WebexBot from app import close, meme @@ -18,6 +20,7 @@ def create_bot() -> WebexBot: def main() -> None: + """Main function to run the Webex Bot.""" bot: WebexBot = create_bot() bot.add_command(meme.MakeMemeCommand()) bot.add_command(close.ExitCommand()) diff --git a/app/meme.py b/app/meme.py index dc25e31..a6b947e 100644 --- a/app/meme.py +++ b/app/meme.py @@ -1,3 +1,5 @@ +"""Generates meme images using the memegen.link API.""" + from webex_bot.models.command import Command from webex_bot.models.response import Response, response_from_adaptive_card from webexteamssdk.models.cards import ( @@ -22,6 +24,7 @@ class MakeMemeCommand(Command): """Class for initial Webex interactive card.""" def __init__(self) -> None: + """Initialize the MakeMemeCommand with command keyword and help message.""" super().__init__( command_keyword="/meme", help_message="Make a Meme", @@ -29,10 +32,16 @@ class MakeMemeCommand(Command): delete_previous_message=True, ) - def pre_execute(self, message, attachment_actions, activity) -> None: + def pre_execute( + self, message, attachment_actions, activity + ) -> None: # pylint: disable=unused-argument + """Pre-execution logic for the MakeMemeCommand.""" return - def execute(self, message, attachment_actions, activity) -> Response: + def execute( + self, message, attachment_actions, activity + ) -> Response: # pylint: disable=unused-argument + """Execute the MakeMemeCommand and return an adaptive card.""" card_body: list = [ ColumnSet( columns=[ @@ -45,13 +54,13 @@ class MakeMemeCommand(Command): size=FontSize.MEDIUM, ), TextBlock( - "This bot uses memegen.link to generate memes. Click 'View Templates' to view available templates.", + "This bot uses memegen.link to generate memes. Click 'View Templates' to view available templates.", # pylint: disable=line-too-long weight=FontWeight.LIGHTER, size=FontSize.SMALL, wrap=True, ), TextBlock( - "Both fields are required. If you do not want to specify a value, please type a space.", + "Both fields are required. If you do not want to specify a value, please type a space.", # pylint: disable=line-too-long weight=FontWeight.LIGHTER, size=FontSize.SMALL, wrap=True, @@ -103,6 +112,7 @@ class MakeMemeCallback(Command): """Class to process user data and return meme.""" def __init__(self) -> None: + """Initialize the MakeMemeCallback with command keyword and help message.""" super().__init__( card_callback_keyword="make_meme_callback_rbamzfyx", delete_previous_message=True, @@ -113,7 +123,10 @@ class MakeMemeCallback(Command): self.meme: str = "" self.meme_filename: str = "" - def pre_execute(self, message, attachment_actions, activity) -> str: + def pre_execute( + self, message, attachment_actions, activity + ) -> str: # pylint: disable=unused-argument + """Pre-execution logic for the MakeMemeCallback.""" self.meme: str = attachment_actions.inputs.get("meme_type") self.text_top: str = attachment_actions.inputs.get("text_top") self.text_bottom: str = attachment_actions.inputs.get("text_bottom") @@ -127,7 +140,10 @@ class MakeMemeCallback(Command): return "Generating your meme..." - def execute(self, message, attachment_actions, activity) -> Response | None: + def execute( + self, message, attachment_actions, activity + ) -> Response | None: # pylint: disable=unused-argument + """Execute the MakeMemeCallback and return a response with the meme image.""" if self.error: return None @@ -143,5 +159,8 @@ class MakeMemeCallback(Command): ) return msg - def post_execute(self, message, attachment_actions, activity) -> None: + def post_execute( + self, message, attachment_actions, activity + ) -> None: # pylint: disable=unused-argument + """Post-execution logic for the MakeMemeCallback.""" return diff --git a/tests/test_config.py b/tests/test_config.py index 2cf5fc4..e35082a 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,19 +2,22 @@ import os -vars: dict = { +env_vars: dict = { "APP_VERSION": "dev", "WEBEX_API_KEY": "testing", } -for var, value in vars.items(): +for var, value in env_vars.items(): os.environ[var] = value # needs to be imported AFTER environment variables are set -from app.config import config # pragma: no cover # noqa: E402 +from app.config import ( + config, +) # pylint: disable=wrong-import-position # pragma: no cover # noqa: E402 def test_config() -> None: - assert config.webex_token == vars["WEBEX_API_KEY"] - assert config.version == vars["APP_VERSION"] + """Test the configuration settings.""" + assert config.webex_token == env_vars["WEBEX_API_KEY"] + assert config.version == env_vars["APP_VERSION"] -- 2.47.2 From 0a38b8b4a4dea8d3b7dbe6620282a0590bd8b921 Mon Sep 17 00:00:00 2001 From: Luke Tainton Date: Fri, 6 Jun 2025 18:35:24 +0100 Subject: [PATCH 2/4] fix black --- .gitea/workflows/ci.yml | 8 ++++++-- pyproject.toml | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 7852933..b9c3e2a 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -40,11 +40,15 @@ jobs: - name: Install dependencies run: uv sync + + # - name: Lint + # run: | + # uv run pylint --fail-under=8 --recursive=yes --output-format=parseable --output=lintreport.txt app/ tests/ + # cat lintreport.txt - name: Lint run: | - uv run pylint --fail-under=8 --recursive=yes --output-format=parseable app/ tests/ # --output=lintreport.txt - cat lintreport.txt + uv run pylint --fail-under=8 --recursive=yes --output-format=parseable app/ tests/ - name: Unit Test run: | diff --git a/pyproject.toml b/pyproject.toml index aa42eee..d26f212 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,3 +32,6 @@ includes = [] [build-system] requires = ["pdm-backend"] build-backend = "pdm.backend" + +[tool.black] +line-length = 101 -- 2.47.2 From a1644e365297f0ff24c4afb2c876a1c5493db3bc Mon Sep 17 00:00:00 2001 From: Luke Tainton Date: Fri, 6 Jun 2025 18:35:36 +0100 Subject: [PATCH 3/4] run black --- app/img.py | 4 +--- app/meme.py | 7 ++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/app/img.py b/app/img.py index ad4c1ea..a513f21 100644 --- a/app/img.py +++ b/app/img.py @@ -80,7 +80,5 @@ def generate_api_url(template: str, top_str: str, btm_str: str) -> str: top_str = format_meme_string(top_str) btm_str = format_meme_string(btm_str) - url: str = ( - f"https://api.memegen.link/images/{tmpl_name}/{top_str}/{btm_str}.{tmpl_ext}" - ) + url: str = f"https://api.memegen.link/images/{tmpl_name}/{top_str}/{btm_str}.{tmpl_ext}" return url diff --git a/app/meme.py b/app/meme.py index a6b947e..d54a927 100644 --- a/app/meme.py +++ b/app/meme.py @@ -78,8 +78,7 @@ class MakeMemeCommand(Command): id="meme_type", isMultiSelect=False, choices=[ - Choice(title=x["name"], value=x["choiceval"]) - for x in TEMPLATES + Choice(title=x["name"], value=x["choiceval"]) for x in TEMPLATES ], ), Text(id="text_top", placeholder="Top Text", maxLength=100), @@ -147,9 +146,7 @@ class MakeMemeCallback(Command): if self.error: return None - self.meme_filename: str = img.generate_api_url( - self.meme, self.text_top, self.text_bottom - ) + self.meme_filename: str = img.generate_api_url(self.meme, self.text_top, self.text_bottom) msg: Response = Response( attributes={ "roomId": activity["target"]["globalId"], -- 2.47.2 From 8af57254ae188d8dc72eb886bf2fcf6b19949300 Mon Sep 17 00:00:00 2001 From: Luke Tainton Date: Fri, 6 Jun 2025 18:37:21 +0100 Subject: [PATCH 4/4] black line length 120 --- app/close.py | 12 +++--------- app/meme.py | 24 ++++++------------------ pyproject.toml | 2 +- tests/test_meme.py | 6 +----- 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/app/close.py b/app/close.py index 6565749..390471d 100644 --- a/app/close.py +++ b/app/close.py @@ -15,20 +15,14 @@ class ExitCommand(Command): ) self.sender: str = "" - def pre_execute( - self, message, attachment_actions, activity - ) -> None: # pylint: disable=unused-argument + def pre_execute(self, message, attachment_actions, activity) -> None: # pylint: disable=unused-argument """Pre-execution logic for the exit command.""" return - def execute( - self, message, attachment_actions, activity - ) -> None: # pylint: disable=unused-argument + def execute(self, message, attachment_actions, activity) -> None: # pylint: disable=unused-argument """Execute the exit command.""" return - def post_execute( - self, message, attachment_actions, activity - ) -> None: # pylint: disable=unused-argument + def post_execute(self, message, attachment_actions, activity) -> None: # pylint: disable=unused-argument """Post-execution logic for the exit command.""" return diff --git a/app/meme.py b/app/meme.py index d54a927..95ad893 100644 --- a/app/meme.py +++ b/app/meme.py @@ -32,15 +32,11 @@ class MakeMemeCommand(Command): delete_previous_message=True, ) - def pre_execute( - self, message, attachment_actions, activity - ) -> None: # pylint: disable=unused-argument + def pre_execute(self, message, attachment_actions, activity) -> None: # pylint: disable=unused-argument """Pre-execution logic for the MakeMemeCommand.""" return - def execute( - self, message, attachment_actions, activity - ) -> Response: # pylint: disable=unused-argument + def execute(self, message, attachment_actions, activity) -> Response: # pylint: disable=unused-argument """Execute the MakeMemeCommand and return an adaptive card.""" card_body: list = [ ColumnSet( @@ -77,9 +73,7 @@ class MakeMemeCommand(Command): Choices( id="meme_type", isMultiSelect=False, - choices=[ - Choice(title=x["name"], value=x["choiceval"]) for x in TEMPLATES - ], + choices=[Choice(title=x["name"], value=x["choiceval"]) for x in TEMPLATES], ), Text(id="text_top", placeholder="Top Text", maxLength=100), Text( @@ -122,9 +116,7 @@ class MakeMemeCallback(Command): self.meme: str = "" self.meme_filename: str = "" - def pre_execute( - self, message, attachment_actions, activity - ) -> str: # pylint: disable=unused-argument + def pre_execute(self, message, attachment_actions, activity) -> str: # pylint: disable=unused-argument """Pre-execution logic for the MakeMemeCallback.""" self.meme: str = attachment_actions.inputs.get("meme_type") self.text_top: str = attachment_actions.inputs.get("text_top") @@ -139,9 +131,7 @@ class MakeMemeCallback(Command): return "Generating your meme..." - def execute( - self, message, attachment_actions, activity - ) -> Response | None: # pylint: disable=unused-argument + def execute(self, message, attachment_actions, activity) -> Response | None: # pylint: disable=unused-argument """Execute the MakeMemeCallback and return a response with the meme image.""" if self.error: return None @@ -156,8 +146,6 @@ class MakeMemeCallback(Command): ) return msg - def post_execute( - self, message, attachment_actions, activity - ) -> None: # pylint: disable=unused-argument + def post_execute(self, message, attachment_actions, activity) -> None: # pylint: disable=unused-argument """Post-execution logic for the MakeMemeCallback.""" return diff --git a/pyproject.toml b/pyproject.toml index d26f212..b57f890 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,4 +34,4 @@ requires = ["pdm-backend"] build-backend = "pdm.backend" [tool.black] -line-length = 101 +line-length = 120 diff --git a/tests/test_meme.py b/tests/test_meme.py index 3c0a878..28d8aa5 100644 --- a/tests/test_meme.py +++ b/tests/test_meme.py @@ -29,8 +29,4 @@ def test_error_false() -> None: callback.text_top = "TEST" callback.text_bottom = "TEST" result: Response = callback.execute(None, None, {"target": {"globalId": "TEST"}}) - assert ( - isinstance(result, Response) - and result.roomId == "TEST" - and result.files[0] == callback.meme_filename - ) + assert isinstance(result, Response) and result.roomId == "TEST" and result.files[0] == callback.meme_filename -- 2.47.2