aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/lint-test.yml62
-rw-r--r--Dockerfile28
-rw-r--r--bot/exts/info/help.py8
-rw-r--r--bot/exts/utils/reminders.py64
-rw-r--r--bot/pagination.py2
-rw-r--r--pyproject.toml6
-rw-r--r--tests/helpers.py2
7 files changed, 63 insertions, 109 deletions
diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml
index 2b3dd5b4f..a331659e6 100644
--- a/.github/workflows/lint-test.yml
+++ b/.github/workflows/lint-test.yml
@@ -33,57 +33,16 @@ jobs:
REDDIT_SECRET: ham
REDIS_PASSWORD: ''
- # Configure pip to cache dependencies and do a user install
- PIP_NO_CACHE_DIR: false
- PIP_USER: 1
-
- # Make sure package manager does not use virtualenv
- POETRY_VIRTUALENVS_CREATE: false
-
- # Specify explicit paths for python dependencies and the pre-commit
- # environment so we know which directories to cache
- POETRY_CACHE_DIR: ${{ github.workspace }}/.cache/py-user-base
- PYTHONUSERBASE: ${{ github.workspace }}/.cache/py-user-base
- PRE_COMMIT_HOME: ${{ github.workspace }}/.cache/pre-commit-cache
-
- # See https://github.com/pre-commit/pre-commit/issues/2178#issuecomment-1002163763
- # for why we set this.
- SETUPTOOLS_USE_DISTUTILS: stdlib
-
steps:
- - name: Add custom PYTHONUSERBASE to PATH
- run: echo '${{ env.PYTHONUSERBASE }}/bin/' >> $GITHUB_PATH
-
- name: Checkout repository
uses: actions/checkout@v2
- - name: Setup python
- id: python
- uses: actions/setup-python@v2
- with:
- python-version: '3.10'
-
- # This step caches our Python dependencies. To make sure we
- # only restore a cache when the dependencies, the python version,
- # the runner operating system, and the dependency location haven't
- # changed, we create a cache key that is a composite of those states.
- #
- # Only when the context is exactly the same, we will restore the cache.
- - name: Python Dependency Caching
- uses: actions/cache@v2
- id: python_cache
+ - name: Install Python Dependencies
+ uses: HassanAbouelela/actions/setup-python@setup-python_v1.3.1
with:
- path: ${{ env.PYTHONUSERBASE }}
- key: "python-0-${{ runner.os }}-${{ env.PYTHONUSERBASE }}-\
- ${{ steps.python.outputs.python-version }}-\
- ${{ hashFiles('./pyproject.toml', './poetry.lock') }}"
-
- # Install our dependencies if we did not restore a dependency cache
- - name: Install dependencies using poetry
- if: steps.python_cache.outputs.cache-hit != 'true'
- run: |
- pip install poetry
- poetry install
+ # Set dev=true to install flake8 extensions, which are dev dependencies
+ dev: true
+ python_version: '3.10'
# Check all of our non-dev dependencies are compatible with the MIT license.
# If you added a new dependencies that is being rejected,
@@ -94,17 +53,6 @@ jobs:
pip-licenses --allow-only="$ALLOWED_LICENSE" \
--package $(poetry export -f requirements.txt --without-hashes | sed "s/==.*//g" | tr "\n" " ")
- # This step caches our pre-commit environment. To make sure we
- # do create a new environment when our pre-commit setup changes,
- # we create a cache key based on relevant factors.
- - name: Pre-commit Environment Caching
- uses: actions/cache@v2
- with:
- path: ${{ env.PRE_COMMIT_HOME }}
- key: "precommit-0-${{ runner.os }}-${{ env.PRE_COMMIT_HOME }}-\
- ${{ steps.python.outputs.python-version }}-\
- ${{ hashFiles('./.pre-commit-config.yaml') }}"
-
# We will not run `flake8` here, as we will use a separate flake8
# action. As pre-commit does not support user installs, we set
# PIP_USER=0 to not do a user install.
diff --git a/Dockerfile b/Dockerfile
index 5bb400658..205b66209 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,28 +1,16 @@
-FROM --platform=linux/amd64 python:3.10-slim
+FROM --platform=linux/amd64 ghcr.io/chrislovering/python-poetry-base:3.10-slim
-# Set pip to have no saved cache
-ENV PIP_NO_CACHE_DIR=false \
- POETRY_VIRTUALENVS_CREATE=false
-
-
-# Install poetry
-RUN pip install -U poetry
-
-# Create the working directory
-WORKDIR /bot
+# Define Git SHA build argument for sentry
+ARG git_sha="development"
+ENV GIT_SHA=$git_sha
# Install project dependencies
+WORKDIR /bot
COPY pyproject.toml poetry.lock ./
-RUN poetry install --no-dev
-
-# Define Git SHA build argument
-ARG git_sha="development"
-
-# Set Git SHA environment variable for Sentry
-ENV GIT_SHA=$git_sha
+RUN poetry install --without dev
# Copy the source code in last to optimize rebuilding the image
COPY . .
-ENTRYPOINT ["python3"]
-CMD ["-m", "bot"]
+ENTRYPOINT ["poetry"]
+CMD ["run", "python", "-m", "bot"]
diff --git a/bot/exts/info/help.py b/bot/exts/info/help.py
index 282f8c97a..48f840e51 100644
--- a/bot/exts/info/help.py
+++ b/bot/exts/info/help.py
@@ -307,7 +307,7 @@ class CustomHelpCommand(HelpCommand):
# Remove line breaks from docstrings, if not used to separate paragraphs.
# Allow overriding this behaviour via putting \u2003 at the start of a line.
formatted_doc = re.sub("(?<!\n)\n(?![\n\u2003])", " ", command.help)
- command_details += f"*{formatted_doc or 'No details provided.'}*\n"
+ command_details += f"{formatted_doc or 'No details provided.'}\n"
embed.description = command_details
# If the help is invoked in the context of an error, don't show subcommand navigation.
@@ -331,7 +331,7 @@ class CustomHelpCommand(HelpCommand):
for command in commands_:
signature = f" {command.signature}" if command.signature else ""
details.append(
- f"\n**`{PREFIX}{command.qualified_name}{signature}`**\n*{command.short_doc or 'No details provided'}*"
+ f"\n**`{PREFIX}{command.qualified_name}{signature}`**\n{command.short_doc or 'No details provided'}"
)
if return_as_list:
return details
@@ -372,7 +372,7 @@ class CustomHelpCommand(HelpCommand):
embed = Embed()
embed.set_author(name="Command Help", icon_url=constants.Icons.questionmark)
- embed.description = f"**{cog.qualified_name}**\n*{cog.description}*"
+ embed.description = f"**{cog.qualified_name}**\n{cog.description}"
command_details = self.get_commands_brief_details(commands_)
if command_details:
@@ -412,7 +412,7 @@ class CustomHelpCommand(HelpCommand):
filtered_commands = await self.filter_commands(all_commands, sort=True)
command_detail_lines = self.get_commands_brief_details(filtered_commands, return_as_list=True)
- description = f"**{category.name}**\n*{category.description}*"
+ description = f"**{category.name}**\n{category.description}"
if command_detail_lines:
description += "\n\n**Commands:**"
diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py
index 45cddd7a2..c65785314 100644
--- a/bot/exts/utils/reminders.py
+++ b/bot/exts/utils/reminders.py
@@ -209,6 +209,29 @@ class Reminders(Cog):
log.debug(f"Deleting reminder #{reminder['id']} (the user has been reminded).")
await self.bot.api_client.delete(f"bot/reminders/{reminder['id']}")
+ @staticmethod
+ async def try_get_content_from_reply(ctx: Context) -> t.Optional[str]:
+ """
+ Attempts to get content from the referenced message, if applicable.
+
+ Differs from botcore.utils.commands.clean_text_or_reply as allows for messages with no content.
+ """
+ content = None
+ if reference := ctx.message.reference:
+ if isinstance((resolved_message := reference.resolved), discord.Message):
+ content = resolved_message.content
+
+ # If we weren't able to get the content of a replied message
+ if content is None:
+ await send_denial(ctx, "Your reminder must have a content and/or reply to a message.")
+ return
+
+ # If the replied message has no content (e.g. only attachments/embeds)
+ if content == "":
+ content = "*See referenced message.*"
+
+ return content
+
@group(name="remind", aliases=("reminder", "reminders", "remindme"), invoke_without_command=True)
async def remind_group(
self, ctx: Context, mentions: Greedy[ReminderMention], expiration: Duration, *, content: t.Optional[str] = None
@@ -282,18 +305,11 @@ class Reminders(Cog):
# If `content` isn't provided then we try to get message content of a replied message
if not content:
- if reference := ctx.message.reference:
- if isinstance((resolved_message := reference.resolved), discord.Message):
- content = resolved_message.content
- # If we weren't able to get the content of a replied message
- if content is None:
- await send_denial(ctx, "Your reminder must have a content and/or reply to a message.")
+ content = await self.try_get_content_from_reply(ctx)
+ if not content:
+ # Couldn't get content from reply
return
- # If the replied message has no content (e.g. only attachments/embeds)
- if content == "":
- content = "See referenced message."
-
# Now we can attempt to actually set the reminder.
reminder = await self.bot.api_client.post(
'bot/reminders',
@@ -382,20 +398,7 @@ class Reminders(Cog):
@remind_group.group(name="edit", aliases=("change", "modify"), invoke_without_command=True)
async def edit_reminder_group(self, ctx: Context) -> None:
- """
- Commands for modifying your current reminders.
-
- The `expiration` duration supports the following symbols for each unit of time:
- - years: `Y`, `y`, `year`, `years`
- - months: `m`, `month`, `months`
- - weeks: `w`, `W`, `week`, `weeks`
- - days: `d`, `D`, `day`, `days`
- - hours: `H`, `h`, `hour`, `hours`
- - minutes: `M`, `minute`, `minutes`
- - seconds: `S`, `s`, `second`, `seconds`
-
- For example, to edit a reminder to expire in 3 days and 1 minute, you can do `!remind edit duration 1234 3d1M`.
- """
+ """Commands for modifying your current reminders."""
await ctx.send_help(ctx.command)
@edit_reminder_group.command(name="duration", aliases=("time",))
@@ -417,8 +420,17 @@ class Reminders(Cog):
await self.edit_reminder(ctx, id_, {'expiration': expiration.isoformat()})
@edit_reminder_group.command(name="content", aliases=("reason",))
- async def edit_reminder_content(self, ctx: Context, id_: int, *, content: str) -> None:
- """Edit one of your reminder's content."""
+ async def edit_reminder_content(self, ctx: Context, id_: int, *, content: t.Optional[str] = None) -> None:
+ """
+ Edit one of your reminder's content.
+
+ You can either supply the new content yourself, or reply to a message to use its content.
+ """
+ if not content:
+ content = await self.try_get_content_from_reply(ctx)
+ if not content:
+ # Message doesn't have a reply to get content from
+ return
await self.edit_reminder(ctx, id_, {"content": content})
@edit_reminder_group.command(name="mentions", aliases=("pings",))
diff --git a/bot/pagination.py b/bot/pagination.py
index 8f4353eb1..10bef1c9f 100644
--- a/bot/pagination.py
+++ b/bot/pagination.py
@@ -236,7 +236,7 @@ class LinePaginator(Paginator):
raise EmptyPaginatorEmbedError("No lines to paginate")
log.debug("No lines to add to paginator, adding '(nothing to display)' message")
- lines.append("(nothing to display)")
+ lines.append("*(nothing to display)*")
for line in lines:
try:
diff --git a/pyproject.toml b/pyproject.toml
index 43eb799b6..36c3b5392 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -85,3 +85,9 @@ case_sensitive = true
combine_as_imports = true
line_length = 120
atomic = true
+
+[tool.pytest.ini_options]
+# We don't use nose style tests so disable them in pytest.
+# This stops pytest from running functions named `setup` in test files.
+# See https://github.com/python-discord/bot/pull/2229#issuecomment-1204436420
+addopts = "-p no:nose"
diff --git a/tests/helpers.py b/tests/helpers.py
index 687e15b96..a4b919dcb 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -317,7 +317,7 @@ class MockBot(CustomMockMixin, unittest.mock.MagicMock):
guild_id=1,
intents=discord.Intents.all(),
)
- additional_spec_asyncs = ("wait_for", "redis_ready")
+ additional_spec_asyncs = ("wait_for",)
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)