Loved to read this, I haven't read such a detailed PR in a long time.
#dev-log
1 messages ยท Page 72 of 1
Connected!
I'm still waiting for my code to be reviewed again. Sorry about the delay
Thanks for the quick reply! I'll poke some people for reviews.
[python-discord/site] New branch created: content\-migration
This PR migrates pages under https://pythondiscord.com/pages/ to the site repo as part of dewikification.
How to Review
- Run the branch locally.
- Compare each page with the corresponding page on the current website.
- Don't suggest grammar/phrasing changes for any existing page content, however new content like category and page descriptions can be brought up for improvement.
- Check if links function as intended, and that any images used are local static images and not hotli...
This won't work because that's not how the data is provided by the API request, it should remain in the form it currently is using multiple fields for the body, wing, etc.
A previous discussion on that is here, although I feel it's fine either way.
I wonder if this will result in questions about None and booleans. Maybe there should be a short note about that.
I'd keep it as short as possible, and also maybe a bit less opinionated.
An important thing to note is that you can only `str.join` strings. For a list of ints,
If you want to display a list (or some other iterable), you can write:
However, the separator is still added to the last element, and it is relatively slow.
Relevant Issues
No relevant issues as this was discussed in #dev-contrib.
Description
Instead of using discord.Emoji for the .emoji, I changed it to discord.PartialEmoji as the PartialEmoji has all the attributes the .emoji command uses.
Reasoning
The current .emoji command doesn't currently allow emojis that the bot cannot see, and this PR changes so that any custom emoji can be used with this command.
Screenshots
Before:

async for message in channel.history(limit=amount):
amount isn't a valid kwarg, but limit is.
message_mappings = defaultdict(list)
Certain files have trailing spaces; If the spaces are 2-wide, this is intentional for proper spacing on the displayed markdown. 1-wide trailing spaces can be cleaned up.
Editors tend to strip trailing whitespace. Is there an alternative to using trailing whitespaces?
What is WebP compat like across browsers? pythondiscord.com serves webp to supported clients and falls back to PNG/JPEG/etc. (controlled by Cloudflare) which is where I presume you got them from. If we want to store the PNG then I can disable that feature for us to collect all the necessary images in a more compatible format.
The check uses the in_whitelist_check check internally
I don't have a problem with that. It means fewer redundancies. The trace logs in the check will be a bit misleading, but they're just trace logs, so I don't mind.
What do you think about making this a separate decorator like @override_blacklist? It would work by catching the InWhitelistCheckFailure raised and suppresing it. I feel like shoving so much into a single decorator makes the API confusing.
Yeah, this should be a new, distinct exception type.
Pretty darn useful tag.
Predicate might be a better name here.
As the until clean is inclusive, meaning it deletes the message which is specified in the command, I think this should be inclusive as well, meaning have <= and >=.
description="You cannot do range clean across several channels."
So just copy the code from the lib with a different class name? I guess that's what's been bugging me.
d14f83a add custom command checks tag - vcokltfre
029f4aa update wording to emphasise checks not decorators - vcokltfre
fddfc76 rename function to in_any_channel in accordance... - vcokltfre
15aa872 chore: update wording as requested - vcokltfre
132c985 Merge branch 'main' into decorator-tag - Xithrius
[python-discord/bot] branch deleted: decorator\-tag
Connected!
You can make it a base class and make the whitelist/blacklist types subclasses with empty class bodies.
closes: #1502
Implements the BOT_TRACE_LOGGERS env var that can be used to set which loggers should log trace logs instead of defaulting to logging them all in a development environment.
The env var can be either * or ROOT to set the root logger (and with it all other loggers) to the trace level, or a string in the format of logger_name,another.logger_name to set specific loggers to the level.
I removed the option to use the COLOREDLOGS_LOG_LEVEL to change the coloredlogs l...
I think it sound ok, I just need to figure out how to do it lol
Certain files have trailing spaces; If the spaces are 2-wide, this is intentional for proper spacing on the displayed markdown. 1-wide trailing spaces can be cleaned up.
Editors tend to strip trailing whitespace. Is there an alternative to using trailing whitespaces?
In Mardown, using <br> is generally accepted for new lines.
Am not sure why did I miss that, thanks for the sharp eye! https://github.com/python-discord/bot/pull/1527/commits/5bf42c7d3c4927dae2a130a95d83295db746338d
What is WebP compat like across browsers?
No IE, everything else within reason fully supports, Safari on >= MacOS 11 Big Sur.
I primarily went with WebP as it's 3x smaller than PNG.
Editors tend to strip trailing whitespace. Is there an alternative to using trailing whitespaces?
I'll look into <br> tags, they are few and far between so it's worth the markup tradeoff to deal with the editor issue.
Main reason as to why this logic even exists is to ensure that, if someone decides to use the function, not from the command interface, they'd get a response, am not sure how useful it is.
I think for that matter it could be removed.
As far as regular user is concerned, that should already be the case as per Line 387 the command will error out
Also, is there a reason to not check the age of the message instead?
This part of the code was inspired by howpurgeworks internally.
Comparison on message age could possibly be less accurate which in turn would resort in problems with message deletion if said messages are very close to the 14d mark.
Merged python-discord/sir-lancebot:main into the PR branch to make the PR up to date with all the changes, the merge introduces no breaking change.
Might be a little less readable this way, although if there's a known limitation I suppose it's fine. In that case though this kind of decision should be added to the comment above the line.
Yeah, DiscordException would be better.
I think this part should be exported to a helper function and replaced with errors. The error handler should translate them into embeds and send them.
But yes, if we don't expect the function to be used in another context then I'm not sure there's a point
Description
The PR template has a lot going for it. I like the fields it has, and the descriptions written there for each one are quite adequate, yet, we still end up with a lot of PRs that either doesn't use the template and fail to provide information in any other way, or fail to fill in on or more fields that contain very important information. This applies to staff, core-devs, and non-staff contributors.
I won't list specific examples here as to not call anyone out, but I have se...
Let's just leave it for now. We can revisit it if we decide it's not helpful.
Preliminary block on this PR (I have not reviewed the actual content yet). This PR can not be merged yet, for the same reason our other projects can not be migrated. A lot of the dependencies you've bumped do not have wheels for 3.9 yet, which means these changes are not acceptable through no fault of your own. Without wheels, you need build tools, which significantly hurts people contributing on systems that don't have them by default (such as windows), and will not work in our CI. You can t...
I'm wondering if this part should be exported to a helper function, and called again on message edits.
Meaning, the embeds of the message should be deleted and resent
Or just edit the embeds message? unsure
This PR adds a large amount of code style changes that I cannot really wrap my head around. I see you decided to run Black on the code, do you think the lines that got broken were too long? New logging is inconsistent in style with both itself and the existing code; some existing logging was changed but not all.
None of the documentation, class or function, was updated to mention the new behaviour.
I'm still not convinced that we need to support more than 10 embeds per report. Such an a...
This logic should be moved to a function like add_signals just below is.
The type hint is incorrect, the value is just a string, delimited with commas. It'd probably be better explained using natural language; the hints don't really work.
Additionally, I'm not sure whether sending exceptions to #incidents makes sense. Wouldn't it be better to log the exception and let it be handled by Sentry?
Update 1: Better explanation on when it is okay to make a PR without an issue.
A lot of the dependencies you've bumped do not have wheels for 3.9 yet
This is not entirely correct, I tested it on docker and with pipenv, the only dependency which doesn't have python3.9 wheels is pycares.
2fb7233 Remove ffmpg and discord.py voice extra - ChrisLovering
e43d311 Remove un-used sound resources - ChrisLovering
[python-discord/sir-lancebot] New branch created: remove\-ffmpg
Description
Removed apt get update and ffmpg install as it's no longer needed.
Removed the voice extra for d.py and deleted the un-used sound clips.
Draft until fully tested.
Reasoning
The sound clips, and dependencies were no longer bring used by any command, so fulfilled no purpose in the bot.
Removing these will speed up build times
Did you:
- [x] Join the Python Discord Community?
- [x] If dependencies have been added or u...
Well we have two cases here:
-
If we support more than 10 links, then say we get 10 links in the message, and the author adds another, it would be 11 links, message edit is not possible in this case. In this case I would go with message delete and send new webhook message.
-
If we don't support more than 10 links, then we can just edit the embeds message.
do you think the lines that got broken were too long?
Not exactly sure, if they were too long or if black decided to break them.
New logging is inconsistent in style with both itself and the existing code; some existing logging was changed but not all.
Could you point them out?
None of the documentation, class or function, was updated to mention the new behaviour.
I completely forgot about them, will have them updated.
I'm still not convinced that we need to suppo...
86c709b Migrate redirections from settings.py -> redire... - ks129
GitHub Actions run 756170199 succeeded.
GitHub Actions run 756170200 succeeded.
GitHub Actions run 756167836 succeeded.
GitHub Actions run 756187046 succeeded.
GitHub Actions run 756190615 succeeded.
GitHub Actions run 756193737 succeeded.
Agreed. I used !eval as an example, because that's one where sometimes you spend a while typing out code. For all of them, it could be fine (I don't know all the commands, so I couldn't tell you), but it's at least worth it to consider each command separately.
Does this update the help command? I might just be blind, but I don't see where it does. Unless that's a plan for a separate pr.
When you remove a command, it automatically updates the help command.
Completely forgot about that, thanks!
[python-discord/sir-lancebot] branch deleted: remove\-ffmpg
2fb7233 Remove ffmpg and discord.py voice extra - ChrisLovering
e43d311 Remove un-used sound resources - ChrisLovering
f121d83 Merge pull request #686 from python-discord/rem... - Xithrius
Connected!
Update 2: Expand on what it means for an issue to be approved. [Discussion](#dev-core message)
Due to this bot neither the Python bot being able to filter out most/all inappropriate emojis at this time, this PR cannot be merged.
Pull requests need to have related issues. Opening a pull request without an issue requires an explicit core-dev approval beforehand.
Could be shorter
Pull requests must have a corresponding issue unless explicitly given permission from a core dev.
Corresponding issue denote a stronger relationship than related issue, though maybe the word is too "fancy". Must has a stronger connotation than needs to.
"Corresponding" could also be "equivalent" or "matching" I suppose.
I agree with shortening that part. I think mentioning core dev approval in there is important, what do you think of:
Opening a pull request without an issue requires explicit core dev approval.
(mostly dropping the first sentence)
I've rewritten that whole section to be more to the point (implicitly addresses your second comment):
Original
This field is mandatory. List relevant issue tickets here.
All changes require explicit Core Developer approval (for issues, those are given us...
Opening a pull request without an issue requires an explicit core-dev approval beforehand.
I think it would be nice to add that if it was discussed in Discord and you were told not to open an issue, you must provide links to the conversation.
It's not uncommon that admins and owners say that you can open a pr, so I think that making sure you provide links is something worth pointing out.
That part is already in the original gist as
Opening a pull request without an issue requires an explicit core dev approval beforehand.
It is also included in the rewritten comment.
Why do we have the at-here ping. Wouldn't the moderators ping suffice on it's own?
Minor nitpick, but both roles do not have to be added to this list, and the staff_roles list, if mods will always have at least 1.
Looks like a solid PR. I just had a couple questions, but otherwise this is good to go.
Aren't there also everyone pings for filters and antispam? Do those also need to be changed to be like the modlog ping?
What happens if the user doesn't have the role (i.e. they're already off-duty)? Will this raise an exception or fail silently?
reschedule_roles needs to be cancelled too.
Is this done to allow a user to extend their off-duty period while they're already off-duty?
Yeah, I would prefer timestamps over formatted strings (now for consistency too since it's a more established pattern) but it's not a dealbreaker.
It seems this hasn't been addressed. I have no opinion on the matter, but everything else looks good to me.
From my tests it fails silently
Yes, or not necessarily extend it, but just change it without having to cancel it first.
There shouldn't be a case for manually removing the role if the user still has the team role. I can remove the check.
@HassanAbouelela Yeah, we talked about it in the server and decided it's more trouble than it's worth, since checks are handled like normal decorators. This would mean this would need to be either rewritten as non-dpy checks, or monkey-patch an attribute to be inspected in another part of the code.
For sir-lancebot, we do monkey patching like this, and it isn't too bad. I do agree this isn't necessary here, as blacklist is not a global check, and can be directly modified by the caller.
d14f83a add custom command checks tag - vcokltfre
029f4aa update wording to emphasise checks not decorators - vcokltfre
fddfc76 rename function to in_any_channel in accordance... - vcokltfre
15aa872 chore: update wording as requested - vcokltfre
132c985 Merge branch 'main' into decorator-tag - Xithrius
Connected!
@MarkKoz from what I see and my tests, the filters and antispam use the modlog method for the alert, so this change should handle everything.
What would be a better solution? Sebastiaan's suggestion on the other issue doesn't seem to deal with the filters that apply to multiple messages.
Using locks or specifying an order for processing. Anything that involves deleting messages should be done at the end. I don't know if it's actually feasible but it's something to consider.
I might not be following. Even if you execute all filters in the right order for a specific message, if it is deleted by one of them, it is possible that in a few seconds it will turn out it's part of a larger stream of spam messages that should be punished. At that point, the message is already deleted and will therefore won't be taken into account.
I guess you could still call it a race condition, but it's one that is caused by the filters not having information on the user's future behavior, thus the reasoning that we need a cache.
I might not be following. Even if you execute all filters in the right order for a specific message, if it is deleted by one of them, it is possible that in a few seconds it will turn out it's part of a larger stream of spam messages that should be punished. At that point, the message is already deleted and therefore won't be taken into account.
You're right; I was just thinking about it the wrong way.
Thanks for the PR! I have a few comments to do:
- Please revert lines broken down by Black. You have free to use formatters on your contributions but they must comply with our code style. We don't use 79 chars limits.
- We decided to not allow more than 10 embeds per report. This can reduce code complexity.
- Entries from the cache should be deleted after the incident is cleared. We shouldn't keep the cache growing exponentially.
- Message edits aren't handled properly, they should. Also ...
I believe there is a space missing here
log.trace(f"Deleted discord links webhook message {x}/{len(webhook_msg_ids)}")
Besides I'd rather log the message ID than the number.
The webhook should be a cog level attribute to not fetch it every time.
Since it seems like we're not supporting more than 10, let's make it work for edits.
Is this extra new line for styling, or is it something that shouldn't be here?
Is there a need for this f-string, or could you pass e directly?
There's quite a few places where you've split single lines into multiline expressions in this PR, I don't find them useful, could you revert them? It would also make this PR easier to read & review.
Yup, I would revert the black formatting changes.
Yes they for styling, if the newlines aren't added after each, then it would be kept to one line, which would look bad.
The tests were complaining that the title is not a string, so I added it here.
I'm specifically talking about the newline on this line, since there's already a new link at the end of the previous one.
Ahh right, maybe just a str() call would suffice then? Just to show intent.
The following changes are mentioned in commit 78333e7 :
- Entries from the cache should be deleted after the incident is cleared. We shouldn't keep the cache growing exponentially.
- Message edits aren't handled properly, they should. Also I haven't tested it but is it handling message deletion too?
- The docstring hasn't been updated to match the new features
2d3e1cd Fix captitilization in docstring - ChrisLovering
This issue documents the planned changes to the filters extension. Minor details may still change, and there will be an accompanying site issue. This issue specifies the full extent of the desired changes, but this can be split into several issues and made into a project.
The changes allow for granular control over the behavior of individual filters, and increase the scope of it. All aspects of the extension, including automatic rules, will be controlled from a single entry-point.
Fil...
Abstract
While https://github.com/python-discord/bot/issues/1530 describe the new changes we want for the filter cog group in our bot functionality-wise, this issue will focus on the new database schema proposed to implement those changes. I'd highly recommend you to check out 1530 before reading this issue.
New Schema Overview
Here is a visual representation of the proposed schema :
 nested checks, these changes shouldn't be solving any of our issues according to sir @HassanAbouelela. Closing this PR.
I don't think we have a deploy job here?
[python-discord/sir-lancebot] branch deleted: reject\-dms\-default\-check
2b4a898 Status embed: use the right action name - Akarys42
This is probably not particularly valuable, but I would have done the exact same thing. :smile:
hello id like to add a new feature to lancebot similar to 8bitify. my idea is to take user's profile image, split it in x pieces, randomize those pieces and stitch it back up. ill show an example below.
original:

modified:

in the example there were 2...
This looks good to me! Do you think you can also make the number of squares customisable too?
This looks good to me! Do you think you can also make the number of squares customisable too?
by splits, i meant the squares, so yes.
Relevant Issues
Closes #1498
Description
This PR makes it so that if you do the !e command, and you use it in a blacklisted channel (i.e #python-general), if you don't have a bypassing role, then the output will be redirected.
Screenshots

Not critical, but maybe the name should be changed here also?
What's the reason for patching the iter?
public_flags = unittest.mock.MagicMock(verified_bot=False)
This can be passed as a kwarg instead of setting it manually below
It'd be helpful for the following pages to have a table of contents:
- FAQ
- Code Reviews: A Primer
- Function Parameters and Arguments in Python
- Helping Others
- Help Channels
- Asking Good Questions
- Working with Docker & Docker Compose
- Preparing Your Hosts file
Thoughts?
None of the "more" links in the navbar work. Will that be addressed later?
The compression artefacts on many images are fairly noticeable. Can you use higher-quality im...
description: Information on roles, tooling, and infrastructure at Python Discord.
description: "Mutable and immutable data types: what they are and how they work."
Was there a discussion about merging the CoC pages into one? Since the content is important, we should be mindful of how a longer page may detract readers. I'm not necessarily for or against it; I just want to make sure some collective thought was given to the decision.
This actually applies to all images in guides, but I don't consider it too important.
I would still advise we migrate back to using PNG/JPEG format where appropriate and having Lossless compression applied at the Edge as and when it is necessary/supported.
I completely forgot this issue existed, and yes, I think this issue should be replaced by that one in the end.
Doc item doc_item.symbol_id='assert' present in loaded documentation inventories not found on site, inventories may need to be refreshed.
Doc item doc_item.symbol_id='fixtures' present in loaded documentation inventories not found on site, inventories may need to be refreshed.
Doc item doc_item.symbol_id='module-pytest' present in loaded documentation inventories not found on site, inventories may need to be refreshed.
<img alt="image" width="595" src="https://user-images.githubusercontent.com/20439493/115128047-fa868300-9fd2-11eb-9254-51baafea0ba5.png">
I feel teased.
You marked the conversation as resolved, have you reverted this?
Looks & works great. I agree that having trace logs enabled globally by default is annoying, so this will be a great change. Let me share some thoughts.
Have you considered defining the config directly in the YAML? It would allow us to use the list structure, rather than a comma-delimited string. The local config is already git-ignored, so I don't think we would lose out on the convenience there.
It may even allow us to drop support for the * and ROOT aliases since having an empty strin...
You marked the conversation as resolved, have you reverted this?
It was resolved and the change had been done, but sometimes PyCharm pops up a message of Reformat code, and on clicking that, this change happens.
I must have missed this piece of code while going through the code before committing.
I'd also still like to see tests for the new feature.
Errors shouldn't be sent in #incidents. Instead, they should be logged with log.exception and the function should return.
This should still be reverted
This hasn't been addressed
Yes, I know that, I still need to have a look what happens when you remove the last \n, hence I didn't mark it as resolved.
Scaleios suggested doing something like this: #dev-contrib message.
Is there any better solution or should I go ahead and try doing this?
Have you considered defining the config directly in the YAML? It would allow us to use the list structure, rather than a comma-delimited string. The local config is already git-ignored, so I don't think we would lose out on the convenience there. I think this would also allow us to make it a list always (empty by default), rather than consider None.
I considered it at first, but saw the env var as something that's easier to change for the user with the config being mostly static
It ...
Connected!
I think there may be some merit in allowing the root aliases to be part of the list, rather than the sole entry. It seems unexpected that a,a.b would work to enable a.c, bot not *,a,a.b to enable c.
I actually think it would be a good opportunity to implement a blacklist. That is, if * is present, then all other specified loggers have trace disabled. If *, then all specified loggers have trace enabled. A blacklist works well with my flow since there are only a couple modules that ha...
Since it's trying to mention someone that isn't the one who invoked the command, I believe a mention in an embed is the best approach. If it was to mention the author, then using the "new" replies feature would've sounded nicer.
I'd be willing to implement this.
Notice: the account that the code was pushed from belongs to me. There was a mistake.
TItle: Adding new cog - splitify
Description: Merged splitifer and a discord command for it together, added neat descriptions for each function and the discord command, fixed all the styling errors
Connected!
I think this part should be in a separate function, and it should be ran in the executor.
Thanks for the PR! Just couple suggestions.
raise commands.BadArgument('Squares must greater than zero.')
I think this is more clear. I also don't like the idea of emojis in error messages.
Maybe there should be a default value like 16?
Well those errors get shown to users so I thought it would be more interactive and would look nicer, not so bald.
I actually think it would be a good opportunity to implement a blacklist. That is, if
*is present, then all other specified loggers have trace disabled. If*, then all specified loggers have trace enabled. A blacklist works well with my flow since there are only a couple modules that have annoying trace logs; the rest don't bother me most of the time. A blacklist would mean I don't have to change the value of the env var every time I test a different feature.
That also sounds useful...
I made a typo. I meant that if * is not present, then specified loggers will be set to trace. To enable it globally all you'd need is a lone *.
Examples:
*,a.b.c: enable trace for all excepta.b.c*: enable trace for alla.b.c: enable trace only fora.b.c
But yeah, I suppose making it a separate token is fine.
I made a typo. I meant that if
*is not present, then specified loggers will be set to trace. To enable it globally all you'd need is a lone*.
Yep, but to enable it, the old logger names would be lost from the env var which could be annoying when doing it temporarily.
So we'd have something like
a - enables for module a
*,a or *a - enables for everything
!,a or !,a - disables for a
Relevant issues
Closes #1515
Description
Makes the duration parameter optional giving it a default value of 1 hour as suggested in the issue
Do the filters apply only in specific channels / categories
What about filtering by roles? The obvious use case is to exclude staff members from some filters.
Reaction Menus
While I'm not the target user for this feature, I'm not sold on the necessity of it.
it should be explored whether it's possible to present in the alert all tokens which triggered unique filters (meaning, we don't have to show all tokens that triggered a specific filter).
Can you rephrase this? I don'...
@RohanJnr Did u get time to find out why this was happening?
Some reddit posts don't have any images, so the problem is most likely these two lines.
When using the !docs command to see a list of all of the available packages, any package that starts with a capital letter seems to be brought to the top of the list. Currently the only package starting with a capital letter is GitPython
Image of returned embed when !docs is used:

I would be happy to fix this myself.
Go for it! I've assigned you to the issue.
Hmm, I can find any difference, and for a proof, I even ran a internal eval code to see the difference.

We are moving all image processing related commands into a single executor, #597 like you can see here.
I would suggest waiting until that PR gets merged and then moving this into it's group, so they will be inside the same executor.
Or if the PR is not getting merged anytime soon, you can move it into a executor like toxic said.
cc: @ChrisLovering
This shouldn't be necessary, package names with capital letters are refused by the bot and https://github.com/python-discord/site/pull/373 will add it to the site

Good work on your first PR to sir-lancebot, if anything seems unclear to you, let me know, I would be happy to help you out ๐
Could you explain the algorithm you used for solving this task in the doc-string?
Any specific reason for why you are limiting the squares to this particular number?
Could you explain the algorithm you used for solving this task in the doc-string?
Is there an issue with it or are you just personally interested?
Is there an issue with it or are you just personally interested?
It would help one going through the code and understanding how it is done.
Say, one contributor wants to refactor this code and change the implementation a bit, he would need to understand this code for doing that, when you put the doc-strings in there, it would help them do it.
A greater number than 193,600 causes me PIL errors, I did a lot of testing. If I wanted, I could probably recode it to work with bigger numbers, but since 193,000 squares (split pieces) is already so many for a single Discord PFP, I decided it would serve as a great cap.
This problem exists for me on Windows 10 Pro 20H2 using the following browsers:
- Vivaldi: 3.7.2218.45 (Stable channel) (64-bit)
- Brave: Version 1.23.71 Chromium: 90.0.4430.72 (Official Build) (64-bit)
- Google Chrome: Version 92.0.4482.0 (Official Build) canary (64-bit)
- Google Chrome: Version 89.0.4389.128 (Official Build) (64-bit)
- Opera: Version:75.0.3969.171
- Edge: Version 89.0.774.77 (Official build) (64-bit)
- Firefox: 87.0 (64-bit)
Well may I explain myself then.
-
I get the width and the height of the Image passed to the function.
-
I get the root of a number of squares passed which I call xy. Reason: if let's say 25 squares were passed, that is the total squares (split pieces) that the image is supposed to be split into. As you know, a 2D shape has a height and a width, and for this case I think of it as rows and columns. Rows multiplied by columns is equal to the passed squares. To get rows and columns, since...
I did understand the code originally but Thanks for the awesome explanation, what I was asking for to include this explanation in your code as comments and doc-strings so the algorithm can be much clear to other contributors.
This shouldn't be necessary, package names with capital letters are refused by the bot and python-discord/site#373 will add it to the site
In that case, I can either:
- Go ahead with the planned changes to handle capital letters
- Ask one of the admins to remove the docs and add them back with all lowercase letters
GitHub Actions run 762653847 succeeded.
GitHub Actions run 762663924 failed.
GitHub Actions run 762692325 succeeded.
We're interested in having branding for Ramadan, or at least for Eid al-Fitr.
Remember to follow the event branding instructions found here:
https://github.com/python-discord/branding/blob/main/events/README.md
Here it is.
-
I shuffle passed imgs. Reason: to randomize the squares (split pieces).
-
I get a single square (split piece) out of the list and define single_width as the square's width and single_height as the square's height.
-
I get the root of type integer of the number of imgs (split pieces) in the list and call it multiplier. I then proceed to calculate total height and width of the new image that I am creating using the same multiplier.
-
I then define new_img as the im...
Mandarin is the world's most beautiful duck, it is full of colors.

Got the idea from the duck builder project, where we build ducks.
A possible implementation can be a ๐ฆ with a ๐งโ๐ญ 's cap and a ๐จ .
carpenter ducky = duck + factory worker's cap + hammer
Huh, this sounds interesting, could you create a couple of mock-up ducks so we could see how it looks and attach them to this issue?
bd54449 Renamed Duty cog to Modpings - mbaruh
e30667f Renamed duty.py to modpings.py - mbaruh
0009db8 Merge branch 'mbaruh/offduty' of https://github... - mbaruh
Description
The ability to use the bookmark command without a message link argument to bookmark a message by replying to it. Like this:

(I already have the code since I was curious, but I need to make an issue so everything is done by the book)
Reasoning
It's just a small QoL change that means people wouldn't need to copy the message link to bookmark the message, whic...
I'd suggest waiting until https://github.com/python-discord/sir-lancebot/pull/645 is merged, and integrating your code with the changes there.
Will do, mind pinging me on Discord when that's done :P
This is solved with the move back to PNG.
Description
The !zen command has support for negative indexing. This means that since there are 18 lines of the zen of python, doing !zen -18 should give the first line (0th index). However, this is not the case; doing !zen -18 shows the second line (1st index). The problem seems to be this line: https://github.com/python-discord/bot/blob/main/bot/exts/utils/utils.py#L112
Screenshots
, not -1 * upper_bound.
The current implementation means !zen -18 would spit out line 1, and not the last line.
I found that it only applies to images in lists, as in the other cases it would be separated by paragraph padding.
One solution was to add even more <br> tags (we can't put a newline in the markdown otherwise the image would extend past the list item's left margin), but I've decided to use CSS to avoid having article writers think about it.
I merged them initially because the page had a custom sidebar, I'll bring it up with the admin team.
It'd be helpful for the following pages to have a table of contents:
Addressed in 0697d89.
None of the "more" links in the navbar work. Will that be addressed later?
yes
The compression artefacts on many images are fairly noticeable. Can you use higher-quality images?
I would still advise we migrate back to using PNG/JPEG format
Images are now in PNG format.
Description
when running spookify with a id, it shows the other users pfp and name in the embed header, and the own profile pic spookified.
Steps to Reproduce
The header should match the spookified image
Expected Behaviour
The other persons pfp should be spookified, or the header should match the
Actual Behaviour

Would you like to implement a fix?
...
This is already fixed in #597, however, I don't know how long it will take to get merged.
Description
Would intersplice args and add แแแข between them
Reasoning
Because แแแข
Proposed Implementation
Kind of like .uwu
Would you like to implement this yourself?
- [x
] I'd like to implement this feature myself - [ ] Anyone can implement this feature
When a user sets a reminder, an confirmation embed is sent, to inform the user that the reminder was successfully saved.
In this reminder, we currently include the time at which it is due to be sent. This time is in UTC.
I propose we refactor this part of the code to instead use the timestamp field in the Embed.
https://github.com/python-discord/bot/blob/f2970481e1cd8950dbbb2d3b871df68e90f5a932/bot/exts/utils/reminders.py#L270-L284
This would mean that the time would automatically g...
To clarify, this would take an arbitrary string and add in the cat unicode at various points inside the string?
Was talking in dev-contrib, was thinking maybe would add the cat to the end of a user's nickname
Description
We would like to see an addition to the Sir Lancebot commands: .catify. This would insert random แแแข's into a message sent by the invoker of the command.
Reasoning
This would be useful since it enhances the แแแข cult.
Proposed Implementation
Additional Details
Would you like to implement this yourself?
- [ ] I'd like to implement this feature myself
- [x ] Anyone can implement this feature
I like it where it's stuck between words since it can be used more than once.
#691 is the same thing/
Yeah I kinda beat you to it
I'm going to close this as it's a duplicate of #691. We can move discussion there.
this is magnificent. for proposed implementation, see dev squid's meme func
Hmm, maybe those interested could vote and I'll implement one of them
I would have moved this into the user's nickname instead, as this is were it is getting used mostly. For example, when i do .catify, my nickname should be changed to Shivansh-007 แกแแข.
Another feature I would like to have is, a list of different cats, from which it would be randomly chosen and put into the user's nickname.
You can do it so if it's just .catify with no arguments, it uses the invoker's username, but if there is text after it, it'll catify the text.
You can do it so if it's just
.catifywith no arguments, it uses the invoker's username, but if there is text after it, it'll catify the text.
Yeah, that sounds better, but how would catify text work, adding cats after each word would not look that great, the cat are a bittt long.
We have somewhat of a catify function in ot0
Not every word. They could be randomly interspersed throughout the message
@Kronifer you are assigned! Y'all can have fun discussing the implementation details.
Yeah, it also replaces all the words that have "cat" in them with the แแแข
The only way I can think of doing this is by moving the user to a temporary voice channel and then back to the original voice channel. Discord does not even provide a way to stop stream in their UI, maybe this feature is gonna come up in the future version of discord.
Why not do this for both ordered and unordered lists?
[python-discord/bot] New branch created: list\-non\-staff\-with\-stream\-perms
This command is useful to audit users who still have the permission to stream.
I have chosen to also sort and paginate the embed to make it easier to read.
The sorting is based on how long until the user's streaming permissions are revoked, with permanent streamers at the end.
[python-discord/workers] New branch created: shipit
This should make the GitHub filter worker lookup a new emojis namespace for how to translate literal emojis such as :shipit: to their in-server version.
Not tested yet, I can't really make the worker work.
I don't know html and css that much, but it all looks good to me.
a6b7609 Update wording of comment to be clearer. - ChrisLovering
The HTML and CSS looks good to me.
I'm Mr. Hemlock, and this is my favorite PR on the citadel.
Looks good, a few minor JS things.
We'll need to add a KV binding to EMOJIS, the ID is 183f1ae82b8d458f983e39eb2c99fa9a.
It should be this key in the wrangler.toml:
kv_namespaces = [
{ binding = "EMOJIS", id = "183f1ae82b8d458f983e39eb2c99fa9a", preview_id = "183f1ae82b8d458f983e39eb2c99fa9a" }
]
(match) => lookupEmoji(match)
Should be uppercase.
const EMOJIS: KVNamespace
null is falsey, so explicit comparison is not required:
> let val = null;
undefined
> val ? "a" : "b"
'b'
> val = "abcdef"
'abcdef'
> val ? "a" : "b"
'a'
return value ? value : name
94db90b Remove unnecessary _ in variable name - ChrisLovering
Connected!
I find the wording a bit weird but I really don't mind either way haha
title=f"Members with streaming permission (`{len(lines)}` total)",
Lgtm, left one nitpicking
131dab3 Improve the wording of the list streamers embed - ChrisLovering
-18 shouldn't show the first line, it should show the second, because we're using Python list indexing. Meaning -1 is the last line (the 19th line). The error then is that the lower bound should be one number lower, meaning it should accept -19.
I think something like
title=f"Found `{len(lines)}` members with streaming permission",
Description
The ability to run .duck or .manduck command to get a random duck or manduck, generated by quackstack.
Reasoning
Quackstack is currently fairly inaccessible since it's pretty much just a raw API. One thing we can do to make it more accessible to everyone is to allow them to use it through lancebot to create their own duckies!
Proposed Implementation
Unsure of exact implementation, but roughly:
- Make POST to quackstack to generate a random duck
- Send t...
c001456 Update comment in list stream for readibility - ChrisLovering
GitHub Actions run 764467007 succeeded.
GitHub Actions run 764467019 succeeded.
GitHub Actions run 764469285 succeeded.
Yea, agreed. My first thought was to move them to #AFK and back.
[python-discord/bot] branch deleted: list\-non\-staff\-with\-stream\-perms
cb25375 Require a mod role for stream commands - ChrisLovering
90ed28f Add command to list users with streaming perms - ChrisLovering
a6b7609 Update wording of comment to be clearer. - ChrisLovering
94db90b Remove unnecessary _ in variable name - ChrisLovering
131dab3 Improve the wording of the list streamers embed - ChrisLovering
I think each of them could be ported across to tags, using their root aliases. I rarely ever see people doing !site resources, instead they opt for !resources, similar story for the others.
As for the site-help tag specifically, I brought it up with other core devs, and we agreed that it should be dropped entirely.
Connected!
Relevant Issues
Closes #691
Description
Implemented the .catify
Reasoning
because แแแข
Screenshots

Did you:
- [แแแข] Join the Python Discord Community?
- [แแแข] If dependencies have been added or updated, run
pipenv lock? - [แแแข] Lint your code (
pipenv run lint)? - [แแแข] Set the PR to **a...
here's how it looks because I'm bored and decided to make it, but I'll wait for approval before PRing

What about filtering by roles? The obvious use case is to exclude staff members from some filters.
You're right; edited.
While I'm not the target user for this feature, I'm not sold on the necessity of it.
The commands are kinda long and hard to remember, so what ends up happening is that someone will use !bl, and then they see the available commands, and then they use say !bl list, because we don't remember what the names of the lists are, and only after seeing the list name...
Missed this one
What kind of granularity is needed? Specific filter ID(a), filter list type(s), or all filters?
Whatever is needed to uniquely identify a filter. By how the site schema looks right now (not sure if Akarys updated it after opening the issue, we continued discussing it since), it seems that each filter will have a unique ID. So a filter ID - user ID's pairing should be enough.
Could you explain in the PR description what this command specifically does? This does a bit more than what the screenshot implies and that's not apparent in the PR.
@janine9vn i have updated the description
The return annotation is None, but you returned a Message object.
Mostly looks good to me, a couple of suggestions.
Maybe we should use display_name
I don't think we should edit the nickname here.
Changed in cc8901a i believe
why, thats part of the command
this breaks the command
This also breaks the command
did this as of d8e42a2
I mentioned that it would remove then need of " ".joining the string.
actual fix as of
9bc19a6
I'm assuming it should only be sent once, not multiple times, so this should be un-indented.
Overall looks good. I've requested some documentation improvements and other logic fixes.
for _i in range(random.randint(1, len(string_list) // 2)):
I'd prefer this argument to be called text for better UX, string is too technical.
We should use the display name of the user so that if they have an in-server nickname that is the text that is used.
display_name = ctx.author.display_name
closes #1506
Suspend a member's stream when the !rstream command (used to revoke stream permissions).
This is done by moving the member to the AFK voice channel and then back to the original voice channel.
What error are you getting? I don't get any error with that change.
I tested this again, still breaks
GitHub Actions run 764607610 succeeded.
GitHub Actions run 764608277 succeeded.
GitHub Actions run 764608278 succeeded.
GitHub Actions run 764607609 succeeded.
GitHub Actions run 764608789 succeeded.
GitHub Actions run 764608764 succeeded.
GitHub Actions run 764609494 failed.
GitHub Actions run 764609544 failed.
GitHub Actions run 764620064 failed.
This isn't valid anymore, we can now use a None check.
if not text:
Minor feedback and then I'm going to give it a whirl locally.
alright, ill try this out!
# Set the duration to 1 hour if none was provided
duration = duration or datetime.datetime.utcnow() + datetime.timedelta(hours=1)
also, it would be better to store the default duration as a constant
like
DEFAULT_DURATION = 1
duration = duration or datetime.datetime.utcnow() + datetime.timedelta(hours=DEFAULT_DURATION)
in the file, as a constant
I'm Kronifer [REDACTED], and I approve this PR :shipit: ๐๐ผ
I'm wondering if it would be better to do the same thing done to set the default duration of the mute command, meaning use the Duration converter to create the default time. This would ensure that if there is ever a change to the implementation of the converter, the behaviors won't diverge.
I'm wondering if it would be better to do the same thing done to set the default duration of the mute command, meaning use the
Durationconverter to create the default time. This would ensure that if there is ever a change to the implementation of the converter, the behaviors won't diverge.
I thought of doing that, but the Duration().converter(...) needs to parse and convert the string 1h to a timedelta object first and then add the date and timedelta object.
Whereas here, we can di...
I thought of doing that, but the Duration().converter(...) needs to parse and convert the string
1hto a timedelta object first and then add the date and timedelta object.
Whereas here, we can directly add the date and timedelta object
True, but I don't really mind the extra operation. It's cheap and hidden anyway.
Make sure to thank @AbooMinister and @Wait, its all objects? in the discord, they helped out a lot with this
after all the suggestions joe made, i think this is perfect. LONG LIVE THE CAT CULT!!!
im object btw.
iirc the max nickname length is 32 characters. Since the longest cat is 3 chars long, and we're adding " | " too, this should check that the name isn't longer than 32-6 (26) rather than 28.
The commands are kinda long and hard to remember
Fair enough. However, a menu seems clumsy to me, and the amount of code required to implement one of this scale seems non-trivial.
The issue is that it's not possible for the list of custom filters, because each such custom filter will have its own predicate, which can be arbitrarily complex. So I'd rather if those classes contained their predicates, and then load those filters dynamically from a module, instead of the filter list con...
I thought of doing that, but the Duration().converter(...) needs to parse and convert the string
1hto a timedelta object first and then add the date and timedelta object.
Whereas here, we can directly add the date and timedelta objectTrue, but I don't really mind the extra operation. It's cheap and hidden anyway.
alright then, we can use the Duration() class directly
duration = duration or await Duration().convert(ctx, "1h")
You can have the 1h as a constant at the top of the file.
make sure to import Duration
GitHub Actions run 764820956 succeeded.
GitHub Actions run 764843801 succeeded.
GitHub Actions run 764846427 succeeded.
Creates the resources, faq and tools tags from the corresponding site commands and the site tag from the home/about command. The rules command was moved to the Information cog, and site help was removed along with the cog.
closes: #1473
Description
If someone forgets the ! or misspells a command and they edit their message to fix it, the bot should notice that edit and run that command normally - as if it was originally typed correctly. This would only work for messages that were edited within the past 30 seconds or so.
This could be done automatically upon edit or by adding a repeat emoji reaction ๐ to the message that the user has to click when the bot recognizes the message is now a valid command. The latter is s...
Thanks for contributing!
Connected!
Since this issue seems to be resolved by the restrictions applied on package names, I'll close this issue.
# RedisCache[discord.Member.id, 'Naรฏve ISO 8601 string']
Minor comment which might help readability, but looks good to me otherwise!
Had a test locally, things mostly work although when a single word is passed (e.g. .catify hello) the command crashes out with:
04/19/21 22:00:45 - root DEBUG: Error Encountered: ValueError - empty range for randrange() (1, 1, 0), Command: catify, Author: joe#6000, Channel: bot-commands
04/19/21 22:00:45 - bot.exts.evergreen.error_handler ERROR: Unhandled command error: empty range for randrange() (1, 1, 0)
Traceback (most recent call last):
File "/workspaces/sir-lancebot/.venv/l...
we already spent half an hour on this bug and it worked but now it don't work no more?!
ok wait. aboo says our code was right, and that @Kronifer changed it... @Kronifer could you please come to the chat and take a look?
Hold on, I'm not sure its kronifer, but I may have a fix
@AbooMinister25 carrying the team once more
Sorry guys I was out for a bit
@commands.command(aliases=["แแแขify", "แแแข"])
async def catify(self, ctx: commands.Context, *string: Optional[str]) -> None:
"""Catifies a string or username."""
if string == ():
username = ctx.author.name
if len(username) >= 28:
return await ctx.send("Your username is too long to be catified! Please change it.")
else:
username += f" | {random.choice(Cats.cats)}"
await ct...
me and aboo refined it, got rid of the unpythonic if patch
@commands.command(aliases=["แแแขify", "แแแข"])
async def catify(self, ctx: commands.Context, *string: Optional[str]) -> None:
"""Catifies a string or username."""
if string == ():
username = ctx.author.name
if len(username) >= 28:
return await ctx.send("Your username is too long to be catified! Please change it.")
else:
username += f" | {random.choice(Cats.cats)}"
await ct...
@commands.command(aliases=["แแแขify", "แแแข"])
async def catify(self, ctx: commands.Context, *string: Optional[str]) -> None:
"""Catifies a string or username."""
if string == ():
username = ctx.author.name
if len(username) >= 28:
return await ctx.send("Your username is too long to be catified! Please change it.")
else:
username += f" | {random.choice(Cats.cats)}"
await ctx...
^ That's still being refined to make some things clearer, such as what text is from the word cat and what is randomly injected.
we are currently adding something to catch httpexception when char limit of 2000 words is exceeded
More code :D
@commands.command(aliases=["แแแขify", "แแแข"])
async def catify(self, ctx: commands.Context, *string: Optional[str]) -> None:
"""Catifies a string or username."""
if len(" ".join(string)) > 2000 - 2000//3:
embed = discord.Embed(title="your message was so immense it overloaded my computing core. no cats for you.", color=discord.Colour.red())
await ctx.channel.send(embed=embed)
return
if string == ():
...
^ This checks if the given string is too long
since the max cats is 1/3 of words
now that i think of it, the 2/3 doesn't make sense since 1/3 of words is... well, words, not letters. but i guess the words are separated by spaces and so i f y o u t y p e l e t t e r b y l e t t e r l i k e t h i s it will work... but then it also won't, bc spaces count as well towards limit... AHHHHHHHHHHHHHHHHHHH TO MANY STUFF TO THINK ABOUT
If it's that complicated, you don't have to check the message before translating. There isn't much cost in translating, so translate first, then check the length of the final message.
The patch suggested here was implemented, with some quality of life changes. @jb3 the one word thing should be fixed now!
lessgo, solution to char limit thing was never decided on, so i guess we'll leave that for now (no one will possibly send 2000+ chars, right?)
@hypergamer80 i implemented the char limit
@francisdbillones before creating a PR, please ask for approval from a core developer on the opened issue.
Spectacular first pr for sir lancebot. Great work!
Sorry, how would I do that? @eivl told me to create this pull request.
For this PR you would ask under the issue https://github.com/python-discord/bot/issues/1534.
Ordered and unordered lists both use the <li> tag for list items, which is what I'm styling here, so it works for both.
@RohanJnr Did u get time to find out why this was happening?
Some reddit posts don't have any images, so the problem is most likely these two lines.
good catch. I also found a way to fix it, will open an issue to deal with this.
Description
With the current paginator, when a new image is set on a page, the paginator shows the same image in the next page if the next page does not have an image of its own
Current source code:
image = paginator.images[current_page]
if image:
embed.set_image(url=image)
If the next page's image is an empty string, then the paginator uses the image from the last page.
Solutions
- Set image to empty string when required.
image = paginator.i...
@melodicht I hope your exams went well. Will you be able to finish up this PR?
If you're able to get on this, a file conflict still needs to be resolved.
Hi, I have resolved the file conflict.
Hi @Xithrius, thanks for your feedback. What do you mean by sanitize? Is it just to make it so that only letters go through?
Yep, so that the help command displays the possible traditional rhyme schemes. Here is what it looks like:

But if u make the time less (from 30 to 5 minutes), then people won't be able to get help. Sometimes it takes more than that (more than 5 min), for anyone to answer the question. But then, the person will have to open another channel, resulting in more waiting time, and opening of channels again and again...
In https://github.com/python-discord/organisation/issues/341 we discussed the want to store and process messages from help channels. This is so that we can better investigate the usages of our help channels, in order to improve them effectively.
Implementation suggestions (from Akarys) are:
- Store content of messages posted in help channels in metricity
- The whole infra is built around data coming from metricity, I think it is the most obvious choice. It won't require too much
...
- The whole infra is built around data coming from metricity, I think it is the most obvious choice. It won't require too much
Dropped this internally, but here is my list of recommendations from a privacy standpoint:
- opt-out system which erases on opt-out
- controlled access to the dataset (admins + select few others)
- holding for no longer than a month or two
- no user data above a discord user ID
- on message delete on the server we remove from our dataset, even if the user is opted in
- data is held and collected by a separate service
I'm very against putting this information in Metricity since we mad...
Ok, I understood it wrong, will do the required changes.
closes #1301
Remove the Reddit cog and traces of reddit constants.
The reddit cog is moving to sir-lancebot.
This PR should be merged along with https://github.com/python-discord/sir-lancebot/pull/569
A couple comments/questions I had:
- Will the preexisting metricity opt out users (if the list still exists) be opted out of this automatically?
- If we made promises not to store messages in metricity, wouldnโt it be a bit scummy to store them in what is effectively metricity, but under a different name.
- Completely agree on not making the dataset public (side note: not even admins need access to be honest. I imagine youโll want to analyze those messages and extract some statistics whic...
-
No, that list is gone as of Sunday 12UTC. The list was fairly small, and in fact the majority of users on the list had left by the time that it was discontinued on Sunday.
-
I don't think it's scummy, this is just clarity. We've said before that Metricity won't store message contents and I think then later altering that so that it does collect it a bad idea, it's not just that it doesn't meet the goals of the project but that it's odd to integrate message collection into a service wher...
Just a small consistency change here, below you use a space between 193,000 and :nerd: which should be replicated here for a consistent look
I'm guessing we don't need to set AlllowedMentions for @everyone True anymore.
Just a small consistency change here, below you use a space between
193,000and :nerd: which should be replicated here for a consistent lookThanks github for not showing where :/
around line 86
Sorry, I don't understand what you meant. Could you try showing in code?
-18 shouldn't show the first line, it should show the second, because we're using Python list indexing. Meaning -1 is the last line (the 19th line). The error then is that the lower bound should be one number lower, meaning it should accept -19.
I right, my bad. I was looking at it like it was 18 lines.
Hey @hypergamer80 ensure you lint before committing using flake8 or precommit, ok?
i wanted to say hi แกแแข
alright @Kronifer, i'll lint don't worry
also does jb3 know that the bug was fixed?
@jb3 i think this is the good copy, would you mind looking at it and review? thank you very much!
quick summary on additions & bug fixes while you were offline, in chronological order:
- fixed one-word crash bug
- added 1500 input character cap
- change any elements in bot.constants.Cat.cats to "cat"
- docstring update, more spacing, whitespace cleaning
minor changes:
- "quality-of-life changes - from @Kronifer, not sure what it means
- changed displayname limit from
< 26...
This is a duplicate of #652.
9aa2b42 Tests: AsyncMock is now in the standard library! - Akarys42
[python-discord/bot] New branch created: test\-async\-mock
The tests/README.md file still referenced our old custom AsyncMock that has been removed in favour of the standard library one that has been introduced in 3.8. This commit fixes this by updating the section.
[python-discord/bot] Checks Successful on PR: #1543 Tests: AsyncMock is now in the standard library!
GitHub Actions run 767629252 succeeded.
Looks pretty good, a couple more suggestions.
string_len = len(string_list) // 3 or len(string_list)
await ctx.send(f">>> {text}")
I think that this suggestion still stands.
holy crap that is elegant. will implement this
@ToxicKidz all changes added
Connected!
d14f83a add custom command checks tag - vcokltfre
029f4aa update wording to emphasise checks not decorators - vcokltfre
fddfc76 rename function to in_any_channel in accordance... - vcokltfre
b38e645 AntiSpam: prevent attempts to punish a user mul... - MarkKoz
73b49b5 AntiSpam: create tasks in a safer manner - MarkKoz
Looks like a solid PR. I just had a couple questions, but otherwise this is good to go.
we did it, thanks to everyone who worked on the project and everyone who reviewed it!!!
[python-discord/bot] branch deleted: mbaruh/offduty
Connected!
30c7a58 Github emojis: add the KV to wrangler.toml - Akarys42
Golden. [object Promise]
Try again. [object Promise]
Relevant Issues
Nothing, talked about in discord outside of pydis
Description
added text.lower()
Reasoning
Did you:
- [x] Join the Python Discord Community?
- [x] If dependencies have been added or updated, run
pipenv lock? - [x] Lint your code (
pipenv run lint)? - [x] Set the PR to allow edits from contributors?
Description
I indented some code into the else statement because some variables that were defined in it were used outside of it, and suppressed discord.Forbidden when someone with a higher role than Sir Lancebot uses the command.
Did you:
- [x] Join the Python Discord Community?
- [x] If dependencies have been added or updated, run
pipenv lock? - [x] Lint your code (
pipenv run lint)? - [x] Set the PR to **allow edits from cont...
Relevant Issues
Nothing, talked about in discord outside of pydis
would you please kink to the relevant conversation? [object Promise]
@onerandomusername turns out it was in pydis. Read [here](#ot0-psvmโs-eternal-disapproval message)
I think this better fits into #697. @ToxicKidz would you be cool with assessing this PR and incorporating necessary changes there?
c20f84f Add the Moderators role to moderation_roles in ... - jb3
[python-discord/bot] New branch created: mods\-role\-in\-allowed\-mentions
This allows mod alert pings to go through in #mod-alerts, the allowed mentions only included the mods team role which is not pinged on mod alerts.
[python-discord/bot] branch deleted: mods\-role\-in\-allowed\-mentions
Connected!
Fantastic, thanks. I'll close this now.
It's been a concern lately of tags cluttering the bot's command namespace. To mitigate the issue, we can split certain tags into groups, and then having a lot of related tags under that group won't be an issue.
For example, !intents can become dpy intents, and then we can add however many tags we want under dpy.
The tag group's md files can be stored in the same folder under resources.
Marvellous, so... let's .
But if u make the time less (from 30 to 5 minutes), then people won't be able to get help.
The time is only reduced when their message is deleted.
The tag group's md files can be stored in a common folder under
resources.
The current implementation uses folders for the (unused) role restricted tags, would we just ditch that as it's not currently in use by anything?
We could. I suppose we can also create a special _roles or a similarly named folder and to put restricted tags there, if we ever have any.
Can I fix this? It should be a rather simple fix.
Thoughts on making it so some groups are tied to certain channels, e.g. so !intents run in the #discord-py channel would work as it would search in the dpy group. An issue with this is that it may be confusing for certain tags to work in some channels and not others though.
Nevermind, this would have to be fixed by staff or wait until after dewikification
Yeah that sounds a bit unintuitive. Long time users learn to remember certain tags, and it would be harder if they were called differently in different channels
@kwzrd Hey, are you still interested in working on this issue? I'd love to give it a try if you no longer want to implement it.
[python-discord/bot] branch deleted: test\-async\-mock
[python-discord/bot] Checks Successful on PR: #1543 Tests: AsyncMock is now in the standard library!
GitHub Actions run 768231760 succeeded.
Marvellous, so... let's .
Connected!
I would like to implement this.
Thanks!
As I said on the issue, -18 should indeed give the second line, not the first. The first line can be fetched with -19.
The fix however is correct.
International earth day is just around the corner, on April 22, so @Akarys42 proposed that we put together some server branding for the event!
Marvellous, so... let's .
I would love to help out with branding for Earth Day!
Connected!
Marvellous, so... let's .
[python-discord/workers] branch deleted: shipit
@jb3 I would like to help
When the target channel is set, the unsilence wrapper uses its permissions to determine behavior. Without setting the overwrites, the error message changes from MSG_UNSILENCE_FAIL to MSG_UNSILENCE_MANUAL.
Is this PR still being worked on? If not, I'd be happy to complete it.
@dawnofmidnight You can take it; it's been blocked for a long time and I forgot about it.
Relevant Issues
Closes #667
Description
Implemented .cowsay by using the cowsay module.
Reasoning
Issue approved by staff.
Screenshots

Additional Details
ASCII art is broken on mobile
Did you:
- [x] Join the Python Discord Community?
- [x] If dependencies have been added or updated, ru...
Resolved in 2446c172 (along with all other instances of this).
The branch seems to have been created strangely, so it has the commits from .catify
Relevant Issues
Closes #667
Description
Added Cowsay command using the cowsay module
Reasoning
Added because of approved Issue
Screenshots

Additional Details
ASCII art breaks on mobile for some reason
Did you:
- [x] Join the Python Discord Community?
- [x] If dependencies have been add...
One pointer:
- What happens if the user enters a character that isn't supported? Add some sort of error for this.
from cowsay import get_output_string
Since you're only using this one function I don't see a reason to import the package as a whole.
msgbody = msgbody.replace(" ", "")
This for loop is unnecessary. Utilise the str.replace() method.
msgbody = get_output_string(character, text)
If you decide to go ahead with the changed import.
GitHub Actions run 768663552 failed.
GitHub Actions run 768663924 failed.
GitHub Actions run 768663932 failed.
i believe i removed the loop
@InvisibleOS may i collaborate with you on this project? It seems as if you've forgotten about this issue or has other things to do, so if you'd like I could work with you on this, making it easier.
My nickname on the Python Discord server is "wait... it's all แแแข? | ๐"
Best regards.
Description
This PR makes it so that when you the use !remind command, the success embed sends the date in the embed's timestamp, and not in the footer. This is so that the time can update how discord formats it, and so that it will convert to your local timezone. This closes #1536.
This shouldn't be a bare except. Can you except a function that would be raise if there was an invalid character?
Thanks for the PR! This looks pretty good to me, just one comment. Will test this later.
Re-lock the Pipfile to bump some dependencies.
[python-discord/site] New branch created: joe/pipfile\-relock
I want to take a step back for a moment, because I feel like my original description didn't convey my full thoughts properly.
This is how I envision things working:
Overview
We have the Filtering (or however we name it) cog. The cog has an on_message listener, and for each message it asks the question: what should I do with it?
What should the cog do with the message?
To answer that question, it has an array of filter lists at its service, each represented as an instance o...
what would you suggest?
Try sending an "invalid character", and if it errors, you should except that error. If it doesn't error (which I think it might not), then there will be no need to catch the error.
Currently, the index.html file says that we have 90 dedicated helpers under the "Who are we?" section. This pull request changes that to 100.
This was discussed in Discord here: #dev-contrib message
I think we should wait until @MarkKoz implements the change in snekbox. This would reduce this PR down and won't make the bot break into the user's code to add some timeit lines.
Thanks for the PR! I have some minor recommendations to make this command a bit more robust to user input. Otherwise the command is fun and simple, so the rest of my review will focus on the overall contribution process and things to keep in mind for the future.
Commit messages!
Commit messages are hugely important in the review process and also looking back if we're curious why a command was coded a specific way. I'd recommend adding reasoning as to why you're add/removing/changing ...
You removed the trex from the documentation but I'm still able to call it technically. The trex is also the only one where .cowsay trex errors out with 400 Bad Request error. It's probably worth catching it or forcing trex to be passed as an invalid character and call the error embed.
It would help in general if in the commit body of your commit messages you include some reasoning as to why things are removed/added/the way that they are.
Even though you check if the text is less than 150, for some of the bigger ASCII art characters, like the dragon, I can still generate something too large for discord to process. It results in a Bad Request error that is currently not getting caught or dealt with. It would be worth it to add a check to make sure than the final ascii art you paste is under the discord length or completely remove the ability to use some of the larger ascii characters.
dc7923a chore: Fix UnboundLocalError and discord.Forbid... - ToxicKidz
3477069 chore: lower the input to fine more cats - ToxicKidz
5f889e4 fix: Use name.replace not text.replace - ToxicKidz
daf7dc7 chore: use 'nickname' and 'display name' in the... - ToxicKidz
38c5d61 Merge pull request #697 from ToxicKidz/fix_catify - janine9vn
Could you explain why you removed Trex from the documentation in commit 2a58874.
I don't think we should keep text a default value in the parameter as when one specifies the character to be a Dragon, the text which should come is I'm a Dragon, but here it would be I'm a Cow.
One possible solution is to keep the text None, and then check using a if statement, and if it is None, we can put in the default string
if not text:
text = f"I'm a {character}"
Another comment, rather than putting these characters manually, we would have to change the documentation whenever a new character is added. This wouldn't something nice.
A possible solution to this is to use help= parameter in discord.ext.commands and pass in the characters to it, using f-strings. The characters can be seen like this:
cowsay.char_names
Could we make them be separated by commas i.e. ,.
The current help embed takes a lot of space.
Hey @vincepy! Could you resolve the changes which you have implemented, this would help reviewers know which changes have been implemented which have not.
Thanks!
Connected!
Tested it! Works perfectly!
I feel like we should make it dynamic by fetching the amount of users with the Helpers role in the database. :eyes:
I feel like we should make it dynamic by fetching the amount of users with the Helpers role in the database. ๐
Bear in mind that after dewikification & the API move there will not be a database to fetch this from. Let's just keep it as a constant in the HTML right now, we could add an API route at some stage.
This is a simple idea where a man-duck is holding a rope attached to a duck. Here the two characters are generated using the same color scheme.
Additional Details
This would require another asset to the stack called pet_rope (can be done by someone else, am not good at branding).
Example

Something that bothers me is that it isn't clear which embed relates to which message link, which is exacerbated if any of the messages error out and get skipped. Add the message link in the title (but then the embed is even bulkier)? in the footer? just the message ID?
Something that bothers me is that it isn't clear which embed relates to which message link, which is exacerbated if any of the messages error out and get skipped. Add the message link in the title (but then the embed is even bulkier)? in the footer? just the message ID?
Yeah, I would add the message ID in the footer, I had tried adding the message link as the Title and Footer but then it breaks (half link in line, second half in the next line) due to embed lengths and the embed is bulkier.
Currently you cannot pass in the configuration and make the man duck using that, it just generates a random man duck.
It would be great for the man duck to take in optional JSON data containing the configuration for the man duck.
I would like to work on this.
Can you give invocation examples for the different commands that use the new functionalities?
I also think that the channel ID should be a channel mention, and the user should also be mentioned.
And a minor nitpick, but can you try a gold color for the embed? :D
GitHub Actions run 770485256 succeeded.
GitHub Actions run 770488991 succeeded.
GitHub Actions run 770504767 succeeded.
Looks perfect for me, Ubuntu20.10 + Firefox Developer Edition

bufferedio = await self.bot.loop.run_in_executor(EXECUTOR, self.splitify, img_bytes, squares)
def join_images(imgs: list) -> Image.Image:
Same thing here.
def split_image(img: Image.Image, squares: int) -> list:
Currently you're type hinting to a module.
Hey @vincepy! Could you resolve the changes which you have implemented, this would help reviewers know which changes have been implemented which have not.
Thanks!
Done.
Could you explain what do you mean here?
The bot instance has a loop attribute.
GitHub Actions run 770655248 failed.
GitHub Actions run 770655249 failed.
GitHub Actions run 770660229 succeeded.
LGTM (does the emoji show in dev-log?)
It's a great PR, thanks!
Whoops, missed out one change, everywhere you use I in the code, first-person (and second-person) pronouns should be avoided, especially in doc strings. You can use it rather,
target_message will be a Message object.
def build_bookmark_dm(target_message: discord.Message, title: str) -> discord.Embed:
Cowsay.char_names returns a dictkeys object, so we'd have to filter it before returning it or it looks bad
Here is the current output:

I think that's pretty good, if grammatically a little awkward. I think the original wording ~

~ reads somewhat better to me, but maybe it's not as direct in what it's trying to convey. What do you think?
Does removing this make sense? The channel will continue to exist, right? This is config for a different feature.
I pointed out one place in the config that I'm not sure whether it should be removed.
On the other hand, these emojis seem unused now.
Hello,
I have already made both the commands (rock-paper-scissors and coin-flip) long ago. I have also shared the code in #dev-log but I didn't receive a definite reply which was why I accidentally forgot about it. I'm ready with the code now, I just need some help getting it added to Sir Lancebot.
Maybe we can discuss further on PyDis, I'll hit you up.
I wasn't sure if Due โข10/20/21, but now thinking about it, it looks fine.
Yeah, perhaps what you have will be the easiest to understand. I don't feel strongly either way.
Connected!
You can get None from get_channel if the cache isn't ready yet. Usually this problem is circumvented by awaiting the wait_until_guild_available event on the bot instance. Although I guess it's not much of a concern here since it's only called from a command.
From the docs, it looks like if you do get None here it will kick the user from voice, and L85 will fail since you cannot reconnect them.
6c7ed8d Switch random generation to use HSV over RGB - Shivansh-007
90c1990 fix the image save error due to the namedtuple - vcokltfre
f2000a7 Allow to pass colors separately. - Shivansh-007
4081d8c Updates pydantic model according to 6c7ed8d8 ch... - Shivansh-007
f07da7c Trim Trailing Whitespaces - Shivansh-007
e08c7ce Dockerfile: don't install dev dependencies - Akarys42
[python-discord/quackstack] New branch created: no\-dev\-deps\-in\-dockerfile
Development :clap: dependencies :clap: should :clap: never :clap: be :clap: installed :clap: in :clap: a :clap: container
For real though, this takes time and build space and I doubt anyone is linting their code from inside a container. Even if you do, you can run poetry install again to have development dependencies.
[python-discord/quackstack] branch deleted: no\-dev\-deps\-in\-dockerfile
I get this weird output:

But I can't reproduce it in any way other than doing .savatar 796775205065457695, so it might not be a problem.
I've only moved the content to the bodies of the tags so far, do we also want to have a "title" in the tags?

These are amazing! Wonderful job!
Also, there are borders around the svg banner. Was that intended?
Thank for the PR; this is looking fantastic! I only have a few minor comments (only about the file names and structure).
Many files are named things like Python_Earth_Day-33.png. Something like earth_day.png or icon.png would seem more logical imo.
The static folder includes Python_Earth_Day-33.png, which is a duplicate of the server icon that exists in /server_icons. I think this can simply be removed.
The svg for the banner seems to have the strange additional space on around...
The banner doesn't have the same spacing as the other banners (I'm not talking about the spacing outside that someone else mentioned). The colour of the Python text is also blue despite it being white in all other banners.
You've also duplicated the banner. I don't see the difference between the 34.png and banner.png.
You can use this one as a base or [this](https://github.com/python-discord...
These are amazing! Wonderful job!
Also, there are borders around the svg banner. Was that intended?
Thank you!
The space is not intended.... Gustav said he will check on his end and show
me how to fix it in case it is an illustrator export thing.
On Wed, Apr 21, 2021 at 12:25 PM DawnOfMidnight @.***>
wrote:
@.**** approved this pull request.
These are amazing! Wonderful job!
Also, there are borders around the svg banner. Was that intended?
โ
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<https://gi...
@MarkKoz regarding the light blue text, we looked at it in #media-branding and tried a completely white text. The overwhelming consensus was that the slightly blue version worked better with the rest of the logo.
which simply calls the execute of each of its entries
It is not so simple because the order of execution could be important (e.g. it can't DM a user that's banned).
The class also defines what action should be taken, using a method, let's call it execute.
Another type of entry is one which decides whether any action should be taken at all (for example if the message was sent by a staff member). For this entries will have another method, a predicate, which will return a boolea...
When a mods turns off mod pings, a confirmation is sent to inform the user that their pings have successfully been turned off.
In this confirmation, we currently include the time at which it is due to be sent, this time is in UTC.
I propose we refactor this part of the code to instead use an Embed, with a the timestamp field.
https://github.com/python-discord/bot/blob/ce819ade482e82ecbc474bce5fb8ac9dd8b37b40/bot/exts/moderation/modpings.py#L107
This would mean that the time would auto...
Whoops, missed out one change, everywhere you use
Iin the code, first-person (and second-person) pronouns should be avoided, especially in doc strings. You can useitrather,
Done.
These changes don't quite seem to work on my end. For example, static/banner.svg includes the entire document you used when designing this. Properly adding this banner or logo as an svg seems close to impossible using Illustrator, so I'd be fine with either not including the svgs, or that you include the SVGs, without the shadow. Both ways are fine with me. I'd rather have this merged soon (since the event starts any time now) and fix the shadow later, if we can.
The earth seems to have ...
@gustavwilliam No worries! I will fix these very soon! Sorry they didn't work!
The doc commands !d if and !d for (and possibly others) are grabbing from django docs. The expected behavior is the python syntax for if/elif/else.
!d label.if kind of pulls the right doc, but it's the grammatical usage and not very helpful for trying to understand the usage.
Maybe there could be some dedicated tags for them?
I've written a suggestion explanation for a dedicated !if-else tag here. This is just how I might explain it. Maybe it should be simplified, but I'll leave ...
The spacing issues were not fixed. Here is a fixed version

Is it intentional that the colour of the "python" text does not match the colour of either snake?
Looks almost perfect! Just a final comment from my side.
The logo has a bit of a transparent background around it. When put into the list of servers, this means that the server icon looks very small.

This is the space I'm referring to:

Update 4: Dropped the reasoning field.
This has been prompted by internal discussions [here](#dev-core message) and here.
The gist of it is: In theory, it's great, but it often does not work (perhaps that was the old wording, perhaps people just don't understand it). It also is not necessary most of the time, and where it is necessary, the author could choose ...
fe4d1ff Rewords PR Template - HassanAbouelela
[python-discord/sir-lancebot] New branch created: update\-pr\-template
This is a rewording of the comments in the PR template, to hopefully clarify intentions.
It also removes unneeded fields.
Relevant Issues
Closes #685.
Description
Rewords portions of the PR template to clarify intentions through comments, and removing unneeded fields.
Make sure to view the raw file to see the comments.
Reasoning
This field is gone, shoo.
Screenshots
This field is gone as well.
Additional Details
This one too.
Did ...
I assume this is completed and can be closed now?
Actual final update: removed screenshots and additional details section, for the same reason as reasoning.
[sir-lancebot] Branch update\-pr\-template was force-pushed to `4cc5b44`
I think we should keep screenshots, it helps reviewers see how the output looks, like the other day, there was a suggestion by Alec on consistent spacing. But once he saw the screenshots of the error embed, he was convinced with the embed.
We could not make it compulsory, but yeah it is a really good field.
c1defcf Updates Punctuation In PR Template - HassanAbouelela
@xkawixgirlx fantastic work on this! This all looks ready to merge.
6950d2a Earth Day - xkawixgirlx
0361eb6 Merge branch 'main' of https://github.com/pytho... - xkawixgirlx
3e84e24 Edits Made to file names on the commit for merge - xkawixgirlx
1a8b820 Made changes to files according to comments - xkawixgirlx
6e73b8f Removed all files in the static, fixed banner png - xkawixgirlx
As 179292f64ae64dd93c144c6808fbaf4bed0f8973 explains, the version added in #140 is not considered complete and will be updated in the future. We decided to merge it in the current state to unblock #129. However, writing a separate issue to finish the work may make more sense than leaving this one open.
I had to read this sentence twice to understand it, does this read better?
Linking an issue approved by a Core Developer, that has the "approved" label, is mandatory.
Maybe the commas aren't necessary too
Lgtm, thanks scal! I just have a comment on one of the lines
Relevant Issues
Closes #33
Description
This PR does few miscellaneous changes and the major change: allows to pass options while generating a cute man duck.
Miscellaneous Changes:
- Moves all Color named-tuples to
src/colors.py, to keep them together and not define them at multiple places. - Changes
ManDuckynamed-tuple to only holdimageas rest options aren't needed.
Major Change
This PR adds two models, one for the Dress Colors of man-ducks and oth...
dragon, stegosaurus and trex are valid characters and are part of the library.
Can you include the reason why they are not being allowed in the command?
Also, this should be done before we format the message for the cowsay output. i.e. line 44
And also note, this doc-string is not send or visible to a user on discord, it is only there for a contributor to see.
I agree with kwzrd, this should probably be closed.
It is not so simple because the order of execution could be important (e.g. it can't DM a user that's banned).
In the schema shown in the site issue, there is a type of setting in a separate table called filter_action, which bundles the user-facing actions (it might be better to move the message deletion to a normal setting), so it will handle both DMing the user and issuing the infraction.
These could be combined into a single function that takes some sort of FilterContext object...
Comment because I need to comment because I'm doing this.
Hey @doublevcodes, do you want to be assigned to the issue?
Two things to bear in mind here:
- The objects derived from pydantic's BaseModel support dot access, so it would be better in all cases where you're subscripting the objects like this to just do it like
options.colors. - Objects derived from pydantic's BaseModel are not mappings, and as such can't be used with
**, instead to use them like this you can calloptions.colors.dict()on them.
Do note that this comment also applies to the other places in the file you do this on the next...
29084d1 Fix errors when a subreddit has <5 posts. - ChrisLovering
[python-discord/sir-lancebot] New branch created: fix\-reddit\-index\-error
Relevant Issues
Closes #701
Description
Changed a list slice from [1] to [0].
Added a min check for length of the respond, before shuffling.
Reasoning
If a subreddit has <2 posts, the posts[1] check would fail with an IndexError.
If the subreddit had less than 5 posts, then the k=5 check would also error. These changes harden the command for these edge cases.
Did you:
- [x] Join the Python Discord Community?
- [x]...
With the bounty board archived I'll close this now. Can be re-opened if becomes relevant again.
With the bounty board archived I'll close this now. Can be re-opened if becomes relevant again.
Thanks for the explanation, I will do the required changes, this is how it was done for a Ducky Request so I went ahead and used the same implementation
Description
Commands that echo user input have the vulnerability of allowing embedded images where they otherwise should not be allowed. It manifested today multiple times through the catify command, but has implications for other commands such as uwu and randomcase.
Steps to Reproduce
- Use the catify command with a CDN link.
- The bot should embed the link (even if the user can't).
Expected Behaviour
- The link is escaped.
Actual Behaviour
The ...
[python-discord/sir-lancebot] New branch created: link\-suppressing
Relevant Issues
Closes #703
Description
I've added a helper that does a regex search through a given string, looks for http or https, and surrounds that with <>. I've called it in places I could find where the bot tries to echo part of, or the full user input back to the user.
Reasoning
Regex seemed like the most simple way to deal with finding links. This solution does not take into account that an already escaped link will end up with weird extra brackets...
Description
Unloaded cogs should be saved in redis, and should not be loaded after restarts.
Reasoning
From time to time, we may end up with problematic code that we choose to unload. This can happen for many reasons, from slight oversights to huge breaking bugs. The main point is, when we unload something, we usually don't want it loaded again until the problem is addressed.
Unloading right now works well enough, but it does not persist across bot restarts. There is no go...
Cool, I will go ahead and implement this, thanks!
It's not approved yet, I want discussion from people who rejected it previously.
"You cannot access this Subreddit as it is meant for those who "
[python-discord/sir-lancebot] branch deleted: link\-suppressing
Connected!
I don't agree that we should have it when most of the time most people won't use it. Screenshots may be useful when deciding what looks best, but I still expect reviewers to actually test out the features they are approving (because when they don't, we end up with broken code. ask me how I know).
There is also something to be said about keeping the template concise and limited to what is absolutely required, something I hope to address in the other templates once we're done here.
Certain edge cases may occur if a module changes names while unloaded, and in such cases, it may be best to ignore it in code, and send a warning in a dev channel.
Do you have any ideas for how this could work?
The bot could walk modules in the cache and verify membership in the extensions constant. This would mean looking into the cache before the bot connects, ...
Yup, that's mostly what I had in mind. To answer a few of your points:
- Trying to figure out where a module might have been moved is not something I think is worth much time or effort.
- Any cog that should've been unloaded, but was not found will just be ignored.
- Once the bot reconnects, it'll send out a ping in some channel (preferably hidden), to alert core-devs, or anyone with permissions to unload cogs, much like defcon (used to?) does. Logging an error will have the same effect, b...
Sounds good. Sending a manual alert in the desired staff channel probably makes more sense to me than logging an error, since the situation requires administrative action more so than a fix in the code.
Tbh the wording sounds a bit unnatural in general.
It is mandatory to link an issue with the "approved" label.
We don't really need to outline that it's approved by a Core Dev, when the label already says that in it's description, do we?
The reason for adding it in the first place was to address concerns about who is approving issues. Currently, anyone with write permissions (all staff members) can add the approved label. The conversation was linked in the issue, but [here](#dev-core message) it is again (staff channel). I don't mind it either way, but the consensus at the time was approving issues is a core dev responsibility, we should outline that.
Okay. In that case, it's really only getting rid of the inner phrasing to make it flow better while keeping the same info.
It is mandatory to link to an issue that has been approved by a Core Developer, indicated by an "approved" label.
[python-discord/bot] New review comment on pull request #836: Tags cog unit tests and tags cog fixes
You say that you've 'made some fixes there', could you expand on that? What is the reason for the diff here?
Okay! This now works perfectly when giving it correct options, however if I give it an invalid option, for example i set the outfit to aaaaaaaaaaa rather than a valid one, instead of getting a 400 bad request I get a 500, so I'd like to see that handled internally too, here's how it's done in normal duck generation, but you may want to refine it: (line 68, ducky.py)
if equipment and equipment not in cls.equipments:
raise HTTPException(400, "Invalid equipment pro...
[python-discord/bot] New review comment on pull request #836: Tags cog unit tests and tags cog fixes
description field is ignored by the paginator.
Changes mentioned @vcokltfre !
[python-discord/bot] New review comment on pull request #836: Tags cog unit tests and tags cog fixes
Okay, thanks, that makes sense. I'll try to do a full review soon.
d77986e Fix spelling of a user facing message in reddit... - ChrisLovering
Tested locally, seems to be working good, taking the correct options, giving correct errors, LGTM!
dfb1a78 Take DuckyColors from colors.py - Shivansh-007
396c528 Refactor ManDuck generation to support from opt... - Shivansh-007
3d84a4d fix: use .dict() on pydantic model - Shivansh-007
eb48ced Raise 400 error of invalid option on passing in... - Shivansh-007
9b0ebb1 Enhance invalid error message to include option... - Shivansh-007


