#dev-contrib
1 messages ยท Page 135 of 1
So, thinking on the contributing tag, something like this? Or do y'all think it's not worth having?
Ooh, I love that command! I think we should definitely have it!
That looks amazing!
One suggestion - link buttons to the sir lancebot and python repos
but it may be inconsistent with the current tags
Not sure if the main bot has upgraded to the latest DPY version tho
That would require a large overhaul to how our tags are currently processed
Ah
All of our tags are markdown files that are processed into embeds
Ah alright, that makes more sense than just having one large cog with a ton of different commands
I wonder if the .tictactoe could be rewritten with the discord UI
Hmm, that sounds interesting
It could be buttons attacked in a 3x3 or something like that
Here's your reminder: that
[Jump back to when you created the reminder](#dev-contrib message)
what are you gamering
Hi
rimworld
Pressing submit review when entering a tunnel is always fun
@green oriole what exactly do you mean by an "explanation" of the regex?
I figured the variable name was enough to tell you what it does
Like comments saying what each part do, similar to https://github.com/python-discord/bot/blob/main/bot/utils/regex.py#L3
Yes, you did say what it does, but you didn't say how
Ah right
This regex is too complex to be understood like that
reg = r"(?:`[^`\\]*(?:\\.[^`\\]*)*`)" \ # matches inside codeblocks without a group
r"| ([_|])" # matches `_` and `|` that weren't captured by previous part, in group 1 for access```something like this?
Not quite sure how to word it
And I guess I should use re.compile? (never used that before)
you can use () rather \, liek:
reg = (
r"(?:`[^`\\]*(?:\\.[^`\\]*)*`)" # matches inside codeblocks without a group
r"| ([_|])" # matches `_` and `|` that weren't captured by previous part, in group 1 for access
)
I just prefer \ for separating strings
But yeah
What do you think of the comments though? @short snow
Are they good enough?
gimme a minute, need to put it into regex101, i don't remember regex symbols ๐
^ we use this style for multi-line strings
@static canyon seems like I forgot to mention we should use named capture groups, sorry
I'd personally add more comments, but I guess that's good enough
yeah the coments are prett nice, what does without a group mean in the first comment 
As in it only matches, it doesn't give any groups
All the () are non-capturing
Nw, will do that and change the multi-line string format
Currently gotpy markdown_regex = ( r"(?:`[^`\\]*(?:\\.[^`\\]*)*`)" # matches inside codeblocks (no capturing groups) r"|(?P<markdown>[_|])" # matches `_` and `|` that weren't captured by previous part inside `markdown` group ) markdown_outside_codeblocks_indices = [ m.span()[0] for m in re.finditer(markdown_regex, content) if m.groupdict().get('markdown') ]
Thoughts?
you don't need a non capturing group anymore
True
I'll get rid of it
markdown_regex = (
r"(`[^`\\]*(\\.[^`\\]*)*`)" # matches anything inside codeblocks (backquotes)
r"|(?P<markdown>[_|])" # matches `_` and `|` that weren't captured by previous part inside `markdown` group
)
markdown_outside_codeblocks_indices = [
m.span()[0]
for m in re.finditer(markdown_regex, content)
if m.groupdict().get('markdown')
]```
Would help to shorten the second comment but not sure what to (line is exactly 120 chars)
One source or confusion I can find is why this means that we now ignore underscores inside codeblocks
Can you just mention like "By matching whole codeblocks here first, it means that the following regex won't match characters inside codeblocks"
Pretty rough comment, but should get the idea across of what I am imagining @static canyon
Yep
Will add that before
# By first matching everything inside codeblocks, the part that
# matches underscores and pipes won't match those within backquotes
markdown_regex = (
r"(`[^`\\]*(\\.[^`\\]*)*`)" # matches anything inside codeblocks (backquotes)
r"|(?P<markdown>[_|])" # matches `_` and `|` that weren't captured by previous part inside `markdown` group
)
markdown_outside_codeblocks_indices = [
m.span()[0]
for m in re.finditer(markdown_regex, content)
if m.groupdict().get('markdown')
]```this good? @brisk brook
Yeah I like that
maybe add an example, like the __eq__ one, which was included in the issue description
There's an example in the PR. It's a bit much to include it in the code really
I'm happy with this so gonna push in ~3hrs (when I get home) if there's no other feedback
@staticmethod
def escape_markdown(content: str) -> str:
"""Escape the markdown underlines and spoilers that aren't in codeblocks."""
# By first matching everything inside codeblocks, the part that
# matches underscores and pipes won't match those within backquotes
markdown_regex = (
r"(`[^`\\]*(\\.[^`\\]*)*`)" # matches anything inside codeblocks (backquotes)
r"|(?P<markdown>[_|])" # matches `_` and `|` that weren't captured by previous part inside `markdown` group
)
indices_of_markdown_outside_codeblocks = [
m.span()[0]
for m in re.finditer(markdown_regex, content)
if m.groupdict().get('markdown')
]
escaped_content = ""
for index, char in enumerate(content):
if index in indices_of_markdown_outside_codeblocks and (index == 0 or content[index-1] != "\\"):
escaped_content += "\\" + char
else:
escaped_content += char
return escaped_content
What is the purpose of the \\ and the \\.?
For content[index-1] != "\\", include a negative lookbehind
And then the loop becomes
escaped_content = "\\".join(content[indices[i]:indices[i+1]] for i in range(len(indices)-1))
(yes, yes, I used range-len)
Except if it starts with 0 you'll need to add another \ at the beginning ๐ค
Actually you don't even need to do that
It's from an old version of the regexpy r"(`[^`]*([^`]*)*`)|(?P<markdown>[_|])"this works just as well
Since everything else is escaped, even if you have a markdown symbol at index 0, it will have no match
What is the purpose of the
([^`]*)*
Can't remember exactly how it works, but```
([^]*([^]*)*)
Why doesn't
`[^`]*`
Do that?
That's not between quotes iirc
Or even just
`.*?`
The latter should work actually yeah
My regex knowledge isn't great so I often do stuff way too convoluted
What do you mean by this?
You can specify in a regex pattern that you want the match to not follow a specific string
So you can say "give me all the markdown symbols that don't follow slashes"
Test for a match, or test for failure, without actually consuming any characters.
Also, are you trying to handle multi-line string as well? I don't use finditer much, but you might need to add the DOTALL flag
And if you're trying to handle multi-line code blocks, then the pattern becomes a bit more complex
Sopy `.*?`|(?P<markdown>(?<!\\)[_|])?
From my testing it made no difference (presumably because it's still within backquotes)
It doesn't work with this regex though
Worked before but not now
== Raw message ==
`โโ`โโ||Hel_lo||`โโ
Surrounded by backticks, but not in a codeblock
You'll need to make sure that you're ignoring proper code blocks
The snekbox module handles codeblock detection if you want to take a look
how likely is that to occur in a mailing lists?
We don't need a needlessly complex regex; it's only to make the text more readable which that wouldn't really be in the first place
This seems to work for multi-line codeblocks
If it's just for the mailing lists and there's no issue with an occasional mistake a simplified version is fine
But that should probably be documented, lest someone copies it later
You should really just use the flag for multiline strings
nvm it doesn't work
Wdym?
The wildcard won't match newlines unless you add the DOTALL flag
What didn't work?
If a line within the codeblock was empty it didn't work, but made changes which fix it
but this breaks if the end of codeblock isn't on a newline lol
I tried in Python and seems to work just fine
import re
pattern = r"`.*?`|(?P<markdown>(?<!\\)[_|])"
s = """
\`\`\`py
test_in_g
\`\`\`_in_g
"""
indices_of_markdown_outside_codeblocks = [
m.span()[0]
for m in re.finditer(pattern, s, re.DOTALL)
if m.groupdict().get('markdown')
]
print(indices_of_markdown_outside_codeblocks)```
Ignore the slashes in the string lol
It does
There's a limit for regex101, you need to try in proper python code
Right
There's no finditer option there as far as I know
This seems to be working correctly
So I've now got```py
@staticmethod
def escape_markdown(content: str) -> str:
"""Escape the markdown underlines and spoilers that aren't in codeblocks."""
# By first matching everything inside codeblocks, the part that
# matches underscores and pipes won't match those within backquotes
markdown_regex = (
r". *?" # matches anything inside codeblocks (backquotes)
r"|(?P<markdown>(?<!)[_ |])" # matches unescaped _ and | that weren't captured by previous part
)
indices_of_markdown_outside_codeblocks = [
m.span()[0]
for m in re.finditer(markdown_regex, content, re.DOTALL)
if m.groupdict().get('markdown')
]
escaped_content = ""
for index, char in enumerate(content):
if index in indices_of_markdown_outside_codeblocks:
escaped_content += "\\" + char
else:
escaped_content += char
return escaped_content```
You can get rid of the loop, even though this line is a bit ugly ^
return "".join(
char
for index,char in enumerate(content)
if index not in indices_of_markdown_outside_codeblocks
else "\\" + char
)
Hmm yeah that might work better
Though it that case I'd change indices_of_markdown_outside_codeblocks to a set
Except that's invalid syntax lol
lol, you need to move the if-else to the beginning
Does this look good?py return "".join( char if index not in indices_of_markdown_outside_codeblocks else "\\" + char for index, char in enumerate(content) )
Not quite sure where to split the newlines
I'd put the else on the next line
I was thinking there because then lines 1+3 directly show the yielded value
But if you think I should move then I will @cold island
It seems better to me, but I don't have a strong opinion about it
Why do you have a space in the character group on the 8th line?
There's also a space on the 7th line
Ehh yeah, I decided that I prefer having the if and else inline so changed
Full Function:```py
@staticmethod
def escape_markdown(content: str) -> str:
"""Escape the markdown underlines and spoilers that aren't in codeblocks."""
# By first matching everything inside codeblocks, the part that
# matches underscores and pipes won't match those within backquotes
markdown_regex = (
r".*?" # matches anything inside codeblocks (backquotes)
r"|(?P<markdown>(?<!)[_|])" # matches unescaped _ and | that weren't captured by previous part
)
indices_of_markdown_outside_codeblocks = {
m.span()[0]
for m in re.finditer(markdown_regex, content, re.DOTALL)
if m.groupdict().get('markdown')
}
return "".join(
char
if index not in indices_of_markdown_outside_codeblocks
else "\\" + char
for index, char in enumerate(content)
)```
What is the output of the same blog post I opened the issue for?
That should be a good test
m.groupdict().get('markdown') can be replaced with m.group("markdown")
m.span()[0] can be replaced with m.start()
It doesn't particularly matter, but in your case where you have a constant pattern I'd store it after compilation
Meaning markdown_regex = re.compile(...) and then markdown_regex.finditer(...)
Where would I assign?
As a constant at top of file?
Either instead of the current line or at the top of the file yeah
We do it at the top in other modules so let's go with that
with screaming snake case
Does this look good? @cold island```py
MARKDOWN_REGEX = re.compile(
r".*?" # matches anything inside codeblocks (backquotes)
r"|(?P<markdown>(?<!\)[_|])", # matches unescaped _ and | that weren't captured by previous part
re.DOTALL
)
...
@staticmethod
def escape_markdown(content: str) -> str:
"""Escape the markdown underlines and spoilers that aren't in codeblocks."""
# By first matching everything inside codeblocks, the part that
# matches underscores and pipes won't match those within codeblocks
indices_of_markdown_outside_codeblocks = {
m.start()
for m in re.finditer(MARKDOWN_REGEX, content)
if m.group('markdown')
}
return "".join(
"\\" + char
if index in indices_of_markdown_outside_codeblocks
else char
for index, char in enumerate(content)
)
You can use MARKDOWN_REGEX.finditer(content). Otherwise I think looks fine
It outputs exactly as it should ๐
@cold island @brisk brook @green oriole all pushed into bot#1822, thanks for the help ๐
why do we only have 5 projects on site homepage
ah we transferred django-simple-bulma
what should we replace it with? poll time.
!poll "What should be the 6th repository on pythondiscord.com homepage?" "King Arthur" "Pixels" "Quackstack"
๐ฆ - King Arthur
๐ง - Pixels
๐จ - Quackstack
!remind 3h check this
Your reminder will arrive on <t:1631312528:F>!
branding?
we've always locked it to python projects in prior, I'm not opposed to branding though
Nooo RIP @Code Jam Participants
Ik that's off topic mb
There's nowhere else to write it tho
has a decent few users
This aint luck, this is dedicated hard work
entry_point.sh line 6
shopt -s nocasematch```
That's not bad, that is like looking for something relatively quick and easy to help out with
that is 113 files my man
I am reviewing it right now, most of that number is just resources yaml alterations
Hey @vale ibex , when you have a moment, could you please "accept" the changes on sir-lancebot#843 so this is not showing up? Would greatly appreciate it. Thanks so much!
feel free to dismiss my review if you've done the changes
Then if another core dev looks at it before me then it's fine
Psstt.. they can't dismiss reviews
ah lol
Yeah I was gonna say
well someone can at some point if they get to it before me ๐
done
Thanks so much!
np, i was reviewing stuff anyway
Here's your reminder: check this
[Jump back to when you created the reminder](#dev-contrib message)
okay king arthur wins
PRing
wait why did tests fail
is github ratelimited or something
hmmmmm
yeah idk what's going on
this works locally
ah wait the tests do fail locally
fixed it, had to update the test data json
okay, PR is ready for review
Yeah 
@short snow Rick was asking about this one ^
I dunno django
๐
oh yeah I meant to review that but I lost wifi 
Just noticed the passes in the tests for that one
joe why not make it 9 
9 projects?
yeah
maybe in future, but for now we need to get 6, lol
Do we have that many significant projects that are accepting open source contribs?
True
Forms could be a possibility once it becomes not just staff
then there you go ๐
!remind 14h docs for k8s
Your reminder will arrive on <t:1631375433:F>!
I'm migrating internal docs from notion to GitHub pages
our run books, post-mortems and hopefully much more
nah, .aoc countdown should be fine
who is shom770 on discord?
frontogensis iirc?
Ah so @trail pilot I really like the use of discord menus for this but as a user, I would like to view the basic information about the challenge first and then if I am interested in it, I would go see the full problem description. So I think there should be two views, one which would be originally sent, something like the original of this PR and then we should go show the full problem (like the default view of the current PR state).
But that's personal preference.
Hello! Thanks for the feedback. The thing is though that I'm not really sure, as I've gotten conflicting feedback. Some people want the description and the difficulty, then miscellaneous infomration
and others want the same as you want
So I'm not really sure what to do tbh
Ah, I see, we could probably have a vote here?
@cold island I think we need to update the message content limits on site
I updated it for the embed. I recalled we already updated it in other places. It still bugs out with the latest version of the site?
yeah
is the capping done on the database, so i would need to create the tables again?
Should've been just validation
https://github.com/python-discord/site/pull/585/files hmm you did update it 
Might try running a migration when I'm more awake
how do you delete everything from a db
I'd just delete the container
not running with docker ๐
Well there's your mistake right there
for some reason, docker just makes my memory usage go brrr, so i use it only for extreme cases
delete the db with DROP DATABASE <name> lol
don't go fooling around with that in production though lmao
i vaguely remember someone dropping some dbs in production..
Yeah I don't do that in production, just seeing if that's the problem with the content limits
Alright:
React to this for Option 1, Option 1 is the image below:
React to this for Option 2, Option 2 is the image below:
!voiceverification
Voice verification
Canโt talk in voice chat? Check out #voice-verification to get access. The criteria for verifying are specified there.
#bot-commands
Hey, could sir-lance get the trashcan added to the bottom of issue autolinking?
I've done it here, its not hard, willing to implement it for lance ( since all of the stuff for it already exists)
imo the main problem statement deserves more space in the embed
this stuff isn't as important
Iโm not sure about the โbutton policyโ but it might look a bit better with a button ๐
Well
The automatic file link stuff already has a trashcan
And IMO anything that parses user msgs like should have an option to delete the response
uhh is this supposed to happen? #async-and-concurrency message
[Errno 38] Function not implemented
I'd guess the feature was removed from snekbox to protect it
Can't be certain though
I tested it locally now and it seems to work
(on main)
Hey all, can I get some opinions on this? https://github.com/python-discord/sir-lancebot/pull/859#issuecomment-915352246
sir-lancebot#859
Essentially I am at a stand still trying to figure out whether to leave the command the way it is, with sending a link, or sending the text of the README section, or as Joe suggested, writing to a file and letting Discord preview it.
Alright cool, my nitro gone so I can't test it anyways now 
ah Iย noticed my code had bugs and fixed it but someone else is actually working on it smh
Yeah, the new one has only the desc and the difficuty on the front page
then other info
๐
Joe's suggestion seems a good middle ground imo
But also link to since preview doesn't exist on mobile
hey I'm the guy who worked on the markdown escaping in python news before.
by the time Iย noticed you were working on it, Iย also worked on a fix if you wanna look at it
https://github.com/Ryu1845/bot/commit/5a6dc8840fa39cb5d6baedd166a48569f45e26e8
@static canyon
it works afaik
Thanks @static canyon !
Sure, feel free to PR it, you have my approval
Haha, that's an interesting error. It is most probably because it doesn't have the permission to create a lock.
Here's your reminder: docs for k8s
[Jump back to when you created the reminder](#dev-contrib message)
it looks like this
that's perfect
And in case people want to see more information, the dropdown is there with different pages of information
Yeah it's odd because I'm sure I tested it when the permission to make more processes was added
Yep
I might start adding buttons to other commands
like possibly buttons for tictactoe
Processes themselves work fine
at least making issues for it
what's the view button for when the title has the link?
Wdym?
Ohhh
It was on my PR
to add the link to the name along with the link button
Oh we raised the process limit?
From 1 to like 5?
think we went 6 or something in the end so that a multiprocessing pool worked
You can. I noticed the error because I tried to clean the help embed for the top-level command, which is over 2000 characters. Bots don't need nitro to post over 2000 characters embeds
@brazen charm Just out of interest, since my knowledge on async is a little limited. What is the use of specifying a loop, if it'll just get the running one anyway?
The init tasks are started before the loop is started so they'd fail with a runtime error
ahhh right, so adding it to the bot loop means they'll wait until that loop is started?
yes, it creates a task bound to that loop and then it'll be scheduled when the loop is started
That makes a lot of sense, thanks
@thorny obsidian did you do anything with the dddg issue? I can take care of it, I just haven't been paying attention and making sure you're not already sitting on something
oh nah, I still need to make it
@cold island What version of docker-compose are you running?
I don't get an issue with this compose file
Version? how do I check? the version of the compose is set in the file, isn't it?
1.25.5
Your terminal is complaining about lines 42-44, but it's valid syntax
hmm, I'm on 1.29.2
I suppose I can try updating docker
yea, but it's not a good sign that this is such a recent feature
since contribs might run into it too
If there's a simple backwards compatible solution then that might be good
could you try updating the version string in the compose to 3.9 and see if it complains?
sec
I'm hoping it'll give a nicer message saying you need to update
Are you sure there's 3.9? https://docs.docker.com/compose/compose-file/compose-versioning/
Hmm.. I guess since it's from 1.27 my version isn't even aware of it
yea, that mmakes sense
These topics describe the Docker Compose implementation of the Compose format. Docker Compose 1.27.0+ implements the format defined by the Compose Specification.
From my testing this doesn't work with multi-line codeblocks, and it also doesn't taken into account pre-escaped markdown (the latter definitely being any easy fix).
Although honestly at this point I've got a working solution so unless you can come up with something better I'll just stick to what I came up with thanks to Zig's help.
The reason I want to keep this, as it's a very nice way to make containers wait for psql to be ready, rather than doing it in code
If we can't use these, I'd need to add health checks to site and metricity, since they don't wait for postgres otherwise
I don't mind being on the bleeding edge, I'm just wondering if there's no version of this functionality in 3.8
compose file version
There is no point
lol
I don't think asking people to upgrade compose is such a bad thing anyways
How else would anyone know they even have to update lol
!vote "If you run docker-compose --version what version is output?" "<1.27.0" ">=1.27.0"
๐ฆ - <1.27.0
๐ง - >=1.27.0
(Doesn't docker windows force updates on you actually)
I didn't have any problem with multiline codeblocks can you give me your test?
You can skip them indefinitely 
Ahh
I like what chrome does
It displays a color in your address bar on the settings button, and it goes from green to blood red the longer you put off an update
Pastelink so I don't have to worry about discord formatting it: https://paste.pythondiscord.com/evibigorij.py
The issue I had is that the __eq__ within the multi-line still gets escaped
And I exist in the danger zone
lol
.src
.src src
That would be nice. I kind of wish that command only took one word for an arg
is that a yes ๐
.src gh
it is escaped in the string you sent xD
So it is ๐คฆ
I'd have to unescape it???
what's wrong with that?
Yeah, I don't see what's wrong with that
.src test
whattt. This fails
Your input was invalid: Unable to convert test whattt. This fails to valid command or Cog.
Usage:```
.source [source_item]
just confused on how it handles stuff
Because help help help help is a valid src?
I don't get why this takes the whole sentence and that doesn't
yea^
Iย mean that the string you sent has the backslashes in it
.src help ping
.src help some random
so of course they're still there afterwards
ah yeah
I mean it just uses the first arg right?
@vale ibex check the source, it has a special check for help
.src ping ping
.src ping random
@sinful knot
edit: doesn't have the dotall which is probs why
well yea, that's not a valid cog
ooga isn't a valid command
so you'd expect it not to error?
I might be missing something here, but if you give it an invalid command, then it'll error, if you give it a valid one it'll give you the source?
look in the link you sent
https://paste.pythondiscord.com/evibigorij.py
that's working as expected
That image shows the definition without it escaped, but the issue was that the version you sent didn't have the DOTALL flag
oofadf is not a valid command. That should error.
this is the bug.
yea, but it only looks at the first arg right?
it looks for subcommands
it won't factor in arguments
that is working as expected, there is no bug
but the commit Iย sent you does?
it resolved up to the last working command and returned the help for that

then why
It doesn't?
.src ping Check here for the source of the ping command
because sdf isn't a sub command
because ext is a command isn't it?
well Check isn't a subcommand of ping and that worked.
yea, but ping doesn't have sub commands
ping has no subcommands, so it doesn't check for them
They one you linked on Discord does but I copied from the one you linked on GH which doesn't @sinful knot
yeah it's fine, I'm telling you, this isn't a bug
but it's the same
huh
@cold island @green oriole re bot#1817 this regex isn't behaving as I'd expect. See https://regex101.com/r/jCW2t4/1 it doesn't match for this string, even though I'd expect it too
For some reason changing the \b to \B works
you're not seeing the most recent version for some reason?
Hmm I'm up to date now but version is still 1.25
@sinful knot you also have to use *? instead of just * for the codeblock part, or it breaks when there's more than one
No idea how long regex101 links last, so here's the cleaned up regex if it's useful ```
(?:discord(?:[.,]|dot)gg|discord(?:[.,]|dot)com(?:/|slash)invite|discordapp(?:[.,]|dot)com(?:/|slash)invite|discord(?:[.,]|dot)me|discord(?:[.,]|dot)li|discord(?:[.,]|dot)io|(?:\b([.,]|dot))gg)(?:[/]|slash)([a-zA-Z0-9-]+)
are you still using an outdated version?
that's weird what os are you on/what method for update did you use?
Ahh I think it's because the dot itself is not a word
Makes sense
So a word boundary doesn't really make sense
You should add the negative look-behind thing as well to not escape pre-escaped markdown (i.e. (?<!\\))
Ah yea, it matches on dotgg/
I'm on v2.0.0-rc.1, pydis projects start fine
A way to fix that would be a negative lookbehind for a \w
yeah, I broke docker-compose a while ago so I started using it as part of the docker cli
I'm on Windows. compose came with docker desktop, so I just tried updating that
ugh, maybe
unless the old version is still there and your path env has it hoisted
I don't understand what this does, could you explain?
re.sub(
r"(?P<code_block>`.*?`)|(?P<markdown>(?<!\\)[_|])",
lambda match: "\\" + match.groupdict()["markdown"]
if match.groupdict()["markdown"] is not None
else match.groupdict()["code_block"],
string,
flags=re.DOTALL,
)```it's used in the markdown part, to essentially say "match `_` or `|`, but not if it has a `\` before it"
Aka don't match pre-escaped markdown
Ah ok got it thx
Didn't you setup your computer like yesterday
Shh don't expose me like this
# By first matching everything within a codeblock,
# when matching markdown it won't be within a codeblock
MARKDOWN_REGEX = re.compile(
r"(?P<code_block>`.*?`)" # matches everything within a codeblock
r"|(?P<markdown>(?<!\\)[_|])", # matches unescaped `_` and `|`
re.DOTALL
)
...
def escape_markdown(content):
"""..."""
return re.sub(
MARKDOWN_REGEX,
lambda match: "\\" + markdown_group
if (markdown_group := match.group("markdown"))
else match.group("code_block"),
content
)```I guess this is the end-version that I'd PR if I go for this @sinful knot
Thoughts?
lol i used vsc all day yesterday with a pending update ๐
if I had closed vsc it would have updated
MARKDOWN_REGEX.sub(...) with no flags
Looks about right.
Iย missed the part about using names with the group method in the docs, Iย thought it was stupid doing it with groupdict xD
oh that's what the r is for
nope
regex
Considering just re-installing docker
raw
oh
ah
Thoughts on the added walrus to previous double .group lookup?
I'm a big advocate of walrus so use it pretty much wherever I can
It's kinda useless imo
it looks weird considering it's defined after being used when you read the code and it's not really more explicit
You don't gain much and since it's in a comprehension just seems confusing
Eh, match.group("markdown") or match.group("code_block") is much l'or readable imo
Not equivalent to the above expression though
Is it
Because of the slash
the or won't work with the slash though
You don't want to add a slash if markdown didn't match?
markdown has slash, code_block does not
Doesn't re.Match.group return None if there is no match though
Oh nevermind, that works
You can switch it around I guess. Check if there is a codeblock
match.group("code_block") or "\\" + match.group("markdown")
Eeeh, I feel like it should be a function with an explicit if. I find it very hard to understand as you may have guessed haha
That or works too
Does this work though? Do we always want to use code_block when it's not None?
The two statements aren't the same
We want the code block to still be in the escaped text, do we not?

What I'm saying is both code_block and markdown can be not-None
Can we just use an actual function please
How? each starts with a different character
Because it's an | (or)
Yes
Wait nvm
So only one
codeblock|markdown can only give one or the other?
Correct
if markdown_match := match.group("markdown"):
return r"\" + markdown_group
else:
return match.group("code_block")
```and everyone is happy
If it matches one part, it won't continue to the next
Anyone know how the changelog blacklist works with threads?
It'd be "\\" + markdown_group but yea
changelog blacklist?
r"\" doesn't work btw
Fair
As expected is the answer
It's called that in the config
Basically what channels are ignored from #message-change-log
Right now it won't look at the parent channel and I should totally add that
I mean, see #staff-voice
!remind 13h 
Your reminder will arrive on <t:1631435885:F>!
It ignores threads is what I'm saying
What would the function be called? process_markdown_regex or something?
# By first matching everything within a codeblock,
# when matching markdown it won't be within a codeblock
MARKDOWN_REGEX = re.compile(
r"(?P<code_block>`.*?`)" # matches everything within a codeblock
r"|(?P<markdown>(?<!\\)[_|])", # matches unescaped `_` and `|`
re.DOTALL
)
...
def escape_markdown(content):
"""..."""
return MARKDOWN_REGEX.sub(
lambda match: match.group("code_block") or "\\" + match.group("markdown"),
content
)
Seems fine, assuming it works
Oh fair lol
Yeah, that works
I'll test what Zig said and if it works I'll go with it
Otherwise I'll make it a function
I've realized I totally overlooked #message-change-log when migrating to 2.0, I shall fix that
Threads shouldn't be blacklisted though
It doesn't work
unless you mean threads within blacklisted channels
Yeah, like threads in #admins should be blacklisted
wait a sec
aka this
Which is really just a combo of what Ryu and Akarys suggested
Yeah
# By first matching everything within a code block,
# when matching markdown it won't be within a code block
MARKDOWN_REGEX = re.compile(
r"(?P<code_block>`.*?`)" # matches everything within a codeblock
r"|(?P<markdown>(?<!\\)[_|])", # matches unescaped `_` and `|`
re.DOTALL # required to support multi-line code blocks
)
...
@staticmethod
def escape_markdown(content: str) -> str:
"""Escape the markdown underlines and spoilers that aren't in codeblocks."""
return MARKDOWN_REGEX.sub(
lambda match: match.group("code_block") or "\\" + match.group("markdown"),
content
)```this look good?
You can include Ryu as co-author fwiw
OK I didn't want any co-authoring anyway

Should I push this?
If it works 
so what is message changelog
It can go in the description right?
has to be there
Yes, at the bottom
Morged, thanks y'all
username or @username ?
@gritty wind
i saw that pr but what even was it
Message change log is the dark place where edited/deleted messages get logged for moderation purposes
The blacklist excludes certain channels from making it there, such as the admins channel
this channel is not excluded
this channel is exempt
oh
wait
that diff confused me
Had to do it that way to maintain alignment
because it's voting on core devs
not voting on dev cores
ah
It's still 1.25 (โฏยฐโกยฐ๏ผโฏ๏ธต โปโโป
Time for a new computer
Don't think I did it right
bot#1822
I'd usually just copy paste the author line from a commit of this user
Yeah, you forgot the ๐ง
Wat
The email
pretty sure caps: Co-Authored-By: username <email>
For example, look at the from line here https://github.com/python-discord/bot/commit/a8338895bdc892fe7390514e196443e031fce5d0.patch
Actually I'll use mine since it doesn't have any private information
My author line is usually Matteo Bertucci <matteobertucci2004@gmail.com>
So you can add to your commit Co-authored-by: Matteo Bertucci <matteobertucci2004@gmail.com>
If you are wondering how I got this link btw, you just have to find a commit from the author you want to co author and add .patch at the end of the url
What horrible UI
I think it makes sense
I'm trying to update docker-compose to latest version
Please tell me you aren't on windows
I am
Gosh no
Could you just pip install it?
And pretend the docker desktop version doesn't exist?
There we go, it worked this time. Thanks @green oriole ๐
No probs
That worked, thank you
Sweet
This is the same as you see in git log
@vale ibex hmmm how can I start the bot with metricity but assume site is already up
How would you start the bot now and assume site is already up?
Since bot depends on web now, I don't think you can, so we're not regressing on that
for these edge cases, you can make a docker-compose override file
The issue is that I want to test the whole thing, but I can't test your bot branch with the site main version
I need to use your site branch
Ah, if you build the site image from my branch
then change the image string in the bot compose to the name of the local image, rather than the url
IE image: ghcr.io/python-discord/site:latest -> image: site_web
did you stop the site container?
Ahh I think I know, the config is set to running the bot locally
Which config?
the bot's
Nope, still not connecting
So the only change from my branch you've made is setting the site image right?
yeah
kk lemme try
kk, I've checked out my site branch and building that image
I then kill the container and do docker-compose down
checkout my bot branch and change site image to site_web
docker-compose up
site starts before metricty finishes migrations
hmmm
ah lol
line 49
I've got metricity pushing to pysite
@static canyon you might wanna add escaping to the titles
#mailing-lists message
kk that commit should sort it @cold island
nice catch, since I think had psql already migrated somehow when testing ๐ฆ
lmfao
Lmfao
still no
Is it an error within docker, or a container
I only ask as that fixed worked for me, on a fresh setup
it looks like your config.yml is trying to connect to localhost
rather than site in docker
ok great
I'll finish it tomorrow, need to now create a local image of metricity to use a different config
Also metricity logs are a bit noisy
true
yea lol
Yeah, I will, although that seems out of scope for this PR so will probs make a separate PR. I'll do it when I wake up since going to bed now ๐
!remind 9h add escaping to py-news titles
Your reminder will arrive on <t:1631433862:F>!
!src src
Display information and a GitHub link to the source code of a command, tag, or cog.
CC @patent pivot #dev-log message
!doc refreshdoc
Thx
@patent pivot how can you use something as cursed as loguru
?
loguru/_get_frame.py lines 5 to 12
def get_frame_fallback(n):
try:
raise Exception
except Exception:
frame = exc_info()[2].tb_frame.f_back
for _ in range(n):
frame = frame.f_back
return frame```
what's wrong with that
that runs on every single log method
the point of using loguru is so that loguru does that for me and I don't need to do it - it's doing it for a purpose, not for shits and giggles
is that not cursed tho?
!d sys._getframe
sys._getframe([depth])```
Return a frame object from the call stack. If optional integer *depth* is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, [`ValueError`](https://docs.python.org/3.10/library/exceptions.html#ValueError "ValueError") is raised. The default for *depth* is zero, returning the frame at the top of the call stack.
Raises an [auditing event](https://docs.python.org/3.10/library/sys.html#auditing) `sys._getframe` with no arguments.
**CPython implementation detail:** This function should be used for internal and specialized purposes only. It is not guaranteed to exist in all implementations of Python.
it can do it a different way
loguru/_get_frame.py lines 15 to 18
if hasattr(sys, "_getframe"):
get_frame = sys._getframe
else:
get_frame = get_frame_fallback```
it uses the above method if the sys provided one is not present
is there not a better way to get the frame if the method does not exist?
try/except just seems....
cursed
there isn't really a better way, no
it's not that bad
you generate an exception to grab you the frame, that makes sense in my head
but as the docstring above notes _getframe isn't present in all implementations, you are looking at a compatibility snippet, and yeah, they do get pretty weird sometimes, is it cursed? no.
it's literally only fell back on for compatibility with a variety of interpreters
it's the best way to capture a trace
it guarantees you to have a frame without needing to be in the middle of an actual exception
yeah
there is
it's _getframe
this is just for the environments where that's not implemented
but in not-cpython 
it doesn't make sense to me that the only place to get a frame is in excepts
i mean, a good few of them still implement it, it's just not guaranteed
pypy does ```py
โ ~ pypy3
Python 3.7.10 (77787b8f4c49115346d1e9cbaf48734137417738, Jun 13 2021, 02:02:23)
[PyPy 7.3.5 with GCC 11.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
import sys
sys._getframe
<built-in function _getframe>
makes sense imo, in python stacktraces are heavily tied to exceptions, the whole concept revolves around an exception being present
and _getframe is prefixed with _ because of that, it isn't a super public method
but it works for cases like this, and where it's not implemented the workaround there makes sense
eh... still not convinced, will have to sleep on it ig
i will announce at some point
but i migrated all our internal docs to residing within github, and will be trying to add more for all tasks we have - stuff like adding new prometheus alerts
in inspect.currentframe
This function relies on Python stack frame support in the interpreter, which isnโt guaranteed to exist in all implementations of Python
If the interpreter doesn't support frames, what kind of "frame object" would an exception traceback have?
The thing is, all more or less working Python implementations (CPython, PyPy, Jython, IronPython, GraalVM, Brython) have sys._getframe, so how would you even test this function?
roflmao it monkeypatches sys when testing
https://github.com/Delgan/loguru/blob/68616485f4f0decb5fced36a16040f5e05e2842f/tests/test_get_frame.py
Cython doesn't have frames iirc
in terms of things loguru will support, it's an environment
let me try
"Joe Banks responded" "Joe Banks responded" "Joe Banks responded" "Joe Banks responded" lol
@patent pivot Cython does have sys._getframe, why wouldn't it
thankyou for the query section, makes my life easier to not go google and spend hours on docs ๐
Cython runs on CPython, CPython has _getframe
This test... I sort of have questions
https://github.com/Delgan/loguru/blob/68616485f4f0decb5fced36a16040f5e05e2842f/tests/test_get_frame.py#L7-L13
tests/test_get_frame.py lines 7 to 13
def test_with_sys_getframe(monkeypatch):
def patched():
return
monkeypatch.setattr(sys, "_getframe", patched())
get_frame_module = importlib.reload(loguru._get_frame)
assert get_frame_module.get_frame == patched()```
btw look like wikiguess game didn't get change logged, might want to do that?
it really seems like testing for the sake of testing
it would also happily pass this implementation ```py
get_frame = None
and what's the point of this patched function?
On a related note, bot#1795
i thiiiink it looks like its testing that it's running on cpython?!?
i have no idea!
I understand what it's doing, but not why like that
it's monkeypatching the stdlib
yeh
I'm not confused about the monkeypatch, but why make a function that returns none and then call it right away?
Hey ! If I were to start discussing something about contributing here, would I be interrupting someone right now or is there a channel specific or this the one ?
So I was going through the issues and found one interesting and maybe one I could implement, let me just quickly grab the issue
Oh god, I didn't see the comments but it is marked as closed, does that mean its implemented already ?
Was the ok for me ?
I dont see any PR for the Hangman command so I'm not sure if it is just gone or closed as in no one will do it
I need to implement escaping into the titles of #mailing-lists posts; should I put it as part of bot#1822 or make a new issue+PR?
Hey thanks for clearing that up, I only checked the open PRs completely slipped my mind I should be looking at close PRs. Bit disappointed was looking forward to implementing this, eh. Onto the next issue !
you could put into the same PR tizzy imo since its basically fixing the escapes
jsut remember to update the pr descrition
you are fast ๐
Here's your reminder: add escaping to py-news titles
[Jump back to when you created the reminder](#dev-contrib message)
Already done :p
Here's your reminder: 
[Jump back to when you created the reminder](#dev-contrib message)
Oh no, I just realised that everytime I start the bot I get an email from metabase saying there's a new login on my account
I have over 100 emails
Lmao
i didn't notice since they were put under the promotions label in gmail for some reason ๐
Hey so I found an issue I think i will be able to contribute to ? Should I just comment in the issue, Id like to contribute and will it get assigned to me ?
Or is there any other procedure for assigning the items to yourself ?
If the issue is approved, and haven't been assigned to anyone (or stalled). Then I believe so, yes.
Okay, thanks for the info !
@sour viper if you're the user wanting to work on the anagrams game, I recommend looking into itertools.permutations
https://docs.python.org/3/library/itertools.html#itertools.permutations
That way you just need a list of valid words, random letters for the user using itertools.permutations to make sure there's at least one valid word, and then for validation that's it's a valid word just check it's in the list
Or perhaps it would be better to randomly pick a word from the list of valid words, and shuffle the letters (random choice from the permutation or something)
Looks interesting my approach was a bit straightforward Create a list of all anagrams which can be made (JSON file maybe)
Select a word which has anagrams from JSON at random and scramble the word so its letters are jumbled
Users will suggest words which are anagrams, check in JSON if they are valid anagrams if yes award points (still figuring out how to do that)
All anagrams is going to be way too big to account for though
i looked online
Just store all valid words
apparently small list
Complete List of Anagrams : Anagram : Peculiar Vocabulary : English
Not sure if this the exhaustive list
I agree with this
That's definitely not exhaustive
Doesn't even have santa and satan smh
Lol
Huh, can you point me in the direction where I could find an exhaustive list ? Or Google will be my buddy.
By anagrams you mean a word which makes another word, right?
Not just letters that can make a word
So e.g. pat --> tap
bpta can make tap but doesn't count since bpta isn't a word
Yep exactly, I googled some but all I found were examples of some anagrams nowhere near an exhaustive list
And do you want one word things?
Or can funeral --> real fun be valid?
I suppose it'd interpret as real, fun (two separate)
I was thinking of keeping it simple single word only, i saw some 2 words examples but thought implementation would be a bit complicated
I mean you can just treat it as two separate entries I guess
Looks like you're going to have to brute-force that. Which sucks but can't seem to find a good list
I mean do you really need to store all anagrams? I don't get why you do
hmm
Im not sure how Id go on about, if someone enters anagram command, i cant just list out some random letters and expect them to make words it may or may not be possible. But if I have a list of preconfirmed anagrams
Have a long word list, when the command is invoked, choose one at random and shuffle the word
then when the user answers check if the answer is in the world list
But there's no guarantee the shuffled word is an anagram
We're only counting as an anagram when the shuffled word is also a valid word
^
ahhhh right, yea forgot anagrams need to be valid words lol
is there a list of all dictionary words?
I did too originally lol
There are files out there with all words
you can geenrate anagrams through that then
But that's gonna take so long to generate them all
Yeah
cap them at x anagrams
My vote right now is just shuffle the word and give it whether it's valid or not
So bta --> bat counts
And you'd probably want it to be at least x chars
the more chars, the more potentially words
I think you could make some clever algorithm with a trie so that the decision tree is smaller
I think the start word should be like at least 5 and end word at least 3
So like great --> eat tea gear ear gate etc.
It's better to just have it allow any amount really
There's a bunch in here http://itools.subhashbose.com/wordfind/common-anagrams/
List of common Anagram words - 1533 Anagrams
By definition it needs to be all letters but then by definition it also has to be a valid start word
Not a full list though
Like it doesn't have santa and satan
@clever wraith https://Python-discord.GitHub.io/kubernetes/
Does it need to have all of them?
I think if we have a list of anagrams it should include all of them
just a bunch of known words that have valid anagrams, then use an english dict to check answers
I might make a script later for generating anagrams and just see what happens
Do let me know about it @static canyon I'd love to watch your approach on this
๐
Will do
It'll be a few hours/possibly tomorrow
!remind 8h do this if you haven't already
Your reminder will arrive on <t:1631470305:F>!
ebic
I'm going to add more documents at some point, stuff like the list of components in our monitoring stack and how they are configured (an overview of my SD genius)
my magnum opus: https://github.com/python-discord/kubernetes/blob/main/namespaces/monitoring/alerts/alertmanager/initscript.yaml
Would love to get some reviews on bot#1634 bot#1446 sir-lancebot#745
@clever wraith on smart-resources PR, I am up to date with the branch
Your reminder will arrive on <t:1631473322:F>!
๐โโ๏ธ
and this
one more, the tools page on the menu dropdown
and on no selection, shouldn't it just show all of the resources?
do it
oh i get it, he has your commits, but his commits overwrite yours
i think
cuz i see your commits in that
oh nvm
only some are there
!remind 5h look at it
Your reminder will arrive on <t:1631462969:F>!
good zebra ๐ช
Hey, could someone take a look at, api#16 ? ๐
Hey all, any tips for getting a markdown file to preview correctly?
This is for sir-lancebot#859
I'm a bit behind regarding your PR, that file preview would be the content you get back from the WTF python repository, right?
Hey @lone lava!
It looks like you tried to attach file type(s) that we do not allow (.md). We currently allow the following file types: .gif, .jpg, .jpeg, .mov, .mp4, .mpg, .png, .mp3, .wav, .ogg, .webm, .webp, .flac, .m4a.
Feel free to ask in #community-meta if you think this is a mistake.
oops i wanted to see how a rendered file looks like
brad some of the wtf example don't follow that regex so just cross check over each of those once, according to my testing which was done about 5-6 months back:
16, 25, 26, 40, 43, 55 don't follow that order
yes
Oh, okay. I see.
Yikes, yeah I'll check that out
Yessir, I'm slicing the raw text response, then creating a .md file from that
I'm not an async expert, but using open by itself, is a blocking call, isn't it?
(I just took a quick look at your PR)
Usually not blocking for long enough to be a worry
Hmmm...it likely is. But I was having trouble looking for an example or docs for a temp creation and attachment of a file in discord.py. The open call is the way I know how to create a file
I'd prefer to use StringIO instead, though. It's a file like object, you can use it with discord.File.
But I might be very well wrong.
Not sure if that's something to be worried about but we could always use aiofiles
Time to do some more research
I tried out using StringIO with Discord, it worked just fine.
Yeah that looks like it would be a straight oneliner lol
These are the ones giving me trouble:
-How not to use is operator: Doesn't work for .wtf is, but does work for operator
-+= is faster: Doesn't work for .wtf +=, but does for faster or --
Just so I'm on the same page with you:
16: โถ๏ธ is not ... is not is (not ...)
25: โถ not knot!
26: โถ Half triple-quoted strings
40: โถ Deleting a list item while iterating
43: โถ Beware of default mutable arguments!
55: โถ goto, but why?
I only had the serial number of them stored, so can't really tell but you can jsut quickly make the bot send all and speed run over each to verify them (starting and end)
Alright, the 2.0a0 PR has been updated to correct mod-log and silence
@sour viper I'll need a list of words to do the brute force on, should i just use https://github.com/python-discord/sir-lancebot/blob/c7ccfbc95bb5b73d04c24a137a2bcf6b98d77ddd/bot/resources/fun/hangman_words.txt?
That has 869 words, all at least 3 chars
By no means all words but I believe it's a filtered down top 1k words
Or should I use a list of just all words like https://github.com/dwyl/english-words
just use that and cap the size to 200 words maybe? like after 200 words just stop it or let it continue and go to sleep lol
Having issues with this working for both .txt and .md files
Indeed it does. ๐ That's why I mentioned it as one of the possible solutions, but I don't think it's worth to add a new dependency for such a small thing like that.
@static canyon can you wait for like half an hour if you are still available
I think an easy way would be just to sort the words as per letters
And just find the same words with same letters and we have our anagrams
import json
from itertools import permutations
with open("words.txt") as f:
words = set(json.load(f))
amount_words = len(words)
anagrams = {}
done = {}
# words = ['santa', 'satan']
for index, word in enumerate(sorted(list(words))):
print(f"{index+1}/{amount_words} ({word})")
if word in done:
print(f"{word} has already been done as part of {done[word]}")
break
for permutation in set(permutations(word)):
permutation = "".join(permutation)
# print(permutation)
if permutation == word:
continue
if permutation in words:
print(f"Anagram for {word}: {permutation}")
if word not in anagrams:
anagrams[word] = []
done[permutation] = word
anagrams[word].append(permutation)
print()
```this is what I have right now
I'm just letting it run
Huh that's neat
I guess what you're suggesting would be```py
anagrams = {}
for word in words:
if (sorted_letters := ''.join(sorted(word))) not in anagrams:
anagrams[sorted_letters] = []
anagrams[sorted_letters].append(word)
Which is definitely way better complexity lol
I don't know if mine would be faster ? Would it ?
Then the anagrams are just things where the len(anagrams[sorted_letters]) > 1
Yes right
So yeah, I guess that's a smarter approach
larger
Sure, let me know when it's done, interested to see how much time it takes
It's literally instant lol
Without any print statements
The part that lags is printing the dictionary xD
Woaw
super computer
>>> len(anagrams_builder)
326648
>>> len(actual_anagrams)
30022```
Out of 326k words, 30k of them are anagrams
Assuming the code works
on my laptop lol
ah slight issue
So I might've tried to print over 350k items, each on their own line
Ctrl + C
That doesn't work either lol
Call the biggest boi
Off switch
Don't just kidding


