#dev-contrib
1 messages · Page 139 of 1
>>> 'color' in english_words_set
False
>>> 'colour' in english_words_set
False```even the biggest set misses a load of words
culur
I couldn't really find what they were referring to to be honest. I found nltk but couldn't find the package they were referring to
We could just create a DB of words and use the OT name system
That's what I'm using currently
ah cool
But there's a load of "false" words
Like most of these (this is top of file)
I ended up removing like 5k invalid words over 2ish days but when you consider there's >350k words it wasn't feasible for me to continue
oh lol then yea, I wouldn't
I'm guessing things like the oxford dictionary require licenses
I mean https://www.oxfordlearnersdictionaries.com/wordlists/oxford3000-5000 has a download
Oxford 3000 and 5000: the most important and useful words to learn in English | OxfordLearnersDictionaries.com
But that's even less words than this (which has 25k and still misses loads of words)
ntlk.corpus.words.words() I believe
That gives error though
Pain
Basically saying resource not found
Hmm, that's what the docs say to use. Weird
Oh wait, what OS are you using
It might be using the Unix word list
nltk.download() maybe
Yeah, this was it. Now seems to work```py
from nltk.corpus import words
print(len(words.words()))
236736```
>>> from nltk.corpus import words
>>> print(len(words.words()))
236736
>>> type(words.words())
<class 'list'>: # added colon to fix rest of syntax highlighting
>>> x = [word for word in words.words() if word.isalpha() and word.islower()]
>>> len(x)
211536
>>> y = [word for word in x if len(word) > 3]
>>> len(y)
210147```some stats from `nltk.corpus.words.words()`. Seems possible
@vocal prairie @vale ibex @green oriole @trail pilot ^ thoughts on using this instead of storing the words?
We still need to filter racial slurs etc. from it though
what's wrong with storing words locally
Big file and currently it's 350k words, most of which aren't actually words. At the very least this means only having to monitor 210k words
A big file you download once is better than downloading it on every deploy
sure
and easier to filter out unwanted words
we can download at build time, but I don't really mind
I don't think we necessarily have to filter all of them
Like, what are the odds we have a racial slur out of the 300k words
It sounds like a lot of work to review all of those words, and I'm not sure that's worth doing
Could we could extract a list, pass it through a profanity filter and then store it in the repo?
I see nltk is Apache 2 licensed
What does the anagram command do?
It went from 2.8.0 to 2.9.1
It's major.minor.micro isn't it?
Or patch at the end
Yeah Python calls it micro
@brisk brook You available now ?
In a few minutes yeah
Let me know when available
Alright, do you use Visual Studio Code btw?
Yep
Can you install the Live Share extension?
this one ?
That will allow me to connect to your code and make comments or correct things. Which gets easier than giving you instructions on how to navigate to what I am thinking about
You just need the left one, we can sit in a voice channel here
I think its installed
Do you have access to dev-voice?
No, its greyed out, I dont think so
Then we can use the code-help channels
Hey! Could someone take a look at sir-lancebot#857 ?
There has been a "bit" of a change 🙂
I'll give some time to give a full review tonight
@brisk brook Thanks a lot for your time, couldn't have done the changes without you !
What ya'll doing in dev voice?
st00f
Talking about how we want to start working more seriously on automatic configuration
@brisk brook There's no comment button here but the file was generated from a large list of words, @static canyon Helped create the json file
You can't comment on my comment, but you can comment on the PR if you see at the bottom.
You might not be logged in if you can’t comment at all
Oh got it
I was logged in didnt see the editor at the bottom as Blue mentioned
I am not sure what we should do about it, I'd find it more fun to have less words but ones I have a chance to guess y'know?
we tried that way, we created a json file from most known words, but it didnt cover all cases
it would miss out most of the words, e.g. listen silent and santa satan, these were the common ones we tried searching in the created json but didnt find them
Blue thanks for the reviews, looks like you are on a spree today!
#1 Reviewer
That microchip I got earlier is making me committed to appear on Microsoft's radar
You too? It made me buy 10 Windows licenses back in April
!rule 1
@vale ibex I updated that, in case you missed my earlier message. Please take another look when you have a moment. Thanks so much!
Hey @patent pivot, i have a quick question
writing an error handler for my bot, found an issue with the typing.Literal converter which seems easy enough to fix, but well
discord/ext/commands/errors.py lines 737 to 743
class BadLiteralArgument(UserInputError):
"""Exception raised when a :data:`typing.Literal` converter fails for all
its associated values.
This inherits from :exc:`UserInputError`
.. versionadded:: 2.0```
the BadLiteralArgument exception does not inherit from BadArgument
which means that the BadArgument handler will fail on this

That may not be an issue, but yeah
BadUnionArgument I think is fine that it doesn't import, since its a list of BadArguments
Sorry for asking multiple times, but could anyone review sir-lancebot#860, it's been quiet for a few days now
you should ask him your question directly, so he can answer when he is online
@brisk brook if you don't want to store stuff in a file for the anagrams command, this is the best alternative that I can find: #dev-contrib message
I have zero issues with the words being stored in a file. My critique is that the words are not well known so the game is impossible.
As well as the huge file and the fact that you know that there's been some inappropriate words means we cannot look through it for good words.
The thing is was a case of "have loads of words people don't know" or "miss loads of words people do know". We opted for the prior, so that words people do know would be shown
And someone (can't remember who) did say we don't really need to worry about filtering through the list too much, we can just remove as-and-when we notice a bad word (this does potentially mean more maintenance though)
maybe me
@static canyon I think i have an idea but im not sure ill be able to implement it
So we had a list of common words right, why dont we cross reference it with the values in anagrams.json file, so if a common word is answer only then we keep the word
Isn't that the same as just using the small list?
No the json we currently have is made from the big list it covers all possibilities (if the origin file had all words) Our issue was we were missing out right answers as the small list didn't have any words to create anagrams
So we only keep the anagrams from the small list and it would be most common words and answers would be covered
I'm so confused
"we only keep anagrams from the small list" -- so we use the small one? As I said above?
Hey all, any opinions on the embedded image size? https://github.com/python-discord/sir-lancebot/pull/842#discussion_r714463712
100x100
80x80
60x60
40x40
20x20
Well we are creating an image and attaching it as a thumbnail
So that would be the size of the image created
I'd say stick with 100x100 or lower to 80x80
This is I think the third time I’ve asked, so I’m sorry if it’s been a bit repetitive - but would anyone mind testing out sir-lancebot#860 and leaving a review or just leave a review about anything in general, what works bst
Okie doke. Did my restructuring work out the way you expected as well?
@vale ibex Any updates on sir-lancebot#847?
We have so many sir lance PRs and so little reviewers haha
*Testers
Reviewing is easy, but testing is hard because you need to checkout that branch right
I made a comment yesterday when I tested it. We changed MAPPING_OF_KYU to be the integers but written as hex. So the added int(..., 16) is unnecessary.
I'll make that as a suggestion on GitHub so that you can commit it and I'll give it another try
Testing shouldn't be necessarily difficult, checking out the branch with any GitHub GUI or CLI should be relatively simply
Well yes and no, GitHub Desktop makes it basically too easy to checkout PRs.
But it is much easier for me to review than test because I can review on my phone or laptop when I have nothing better to do (like on the buss :p)
With the CLI you can just do gh pr checkout 879 when in some repo
Testing is part of the review process
Heck, did we never get an announcement out for the review guide?
lol
I don't know about it lol
the announcement, that is
We need to solve that
hell we reached 2 pages of PRs on the bot repo
chop chop
there's only 1 on the second page, but still
Time to set up bot by following site#591
sir-lancebot#878
ergh this is gonna keep nagging me
@molten perch should I just switch that to __name__
(in this pr that you just reviewed.)
You mean the extensions part?
the whole thing
I don't think so. 🙂
Fixed
@vale ibex of the pr you just created, I feel like the appeals server should not be a hardcoded invite link.
That is all
I'm aware it's still a draft pr, but felt major enough to point out now
Ah, er
Lmao
The logic of the bot in the server is a bit interesting. Crashed my app.
lol wut
lol, probably not a bug if it lets people that need to join in
You caught me just after I went to bed 😀 what would you suggest instead?
Theres having it be a constant, or possibly getting it at runtime via guild id I guess
FWIW, I went with a constant
Why not add it to the config file?
That's what I meant by constant
as in I added it to the constants file, which is populated by the config
Ah, right. I thought you meant constant as in all-caps variable in the global scope. I'll take a look later today.
hah yea, I wasn't very clear
There's no rush anyway, it's on hold atm while we write a modmail plugin
not worth adding to config imo
it’s basically just copy, we don’t need that to be configurable
My thoughts were just protecting us against if the invite code changes
but even that would still need a code change now, just in a different file
It is easier to change a config file than Python file though
right but that just won’t happen
as long as it’s a permanent invite, it won’t go anywhere
I’m strongly against making things like this that we know aren’t going to change configurable
it just adds more to the beast that is the config file which is already way too long
True, that is a good point
and even while it's technically easier to update a config file it's so trivial there's hardly a difference
yeah
I don't see any reason you'd want to change it during testing, so I'd say a constant is fine, agreed
I've reverted and force pushed 😄
In draft until we have a modmail plugin to control pings.
What's the reasoning behind that? Are appeals really that heavy?
Yea, there a so many
and with removing the need to email, we expect it to be higher
actually, I should think about making a second category that the appeals plugin uses if the fist one is full
sir-lancebot#880 basic Pr to avoid topic spam, such as what happened just not in pygen
@green oriole added a way to refresh topics
it's not such a basic PR anymore lol
I went with the usual reaction for refresh as a button was huge
Finally back on Linux and unbothered by college
does the command produce actual conversations in channels like #python-discussion ? From what I've seen it's either skipped entirely or a couple people respond to it with one message and go on. The ability to get a new topic without reinvoking the command is good, but I think disabling it in some channels should also be considered
Is there an acceptable amount of commits for a minor "patch"? I'm kinda worried about polluting the commit tree with minor touch-up-ish commits
It helps get things back on the subject of python from what I've seen. In pygen it's less about the actual convo and more about providing a new jumping off point and moving on from whatever was previously off topic.
What channels would you want to disable it in?
What do you mean? If the change is very small we may opt to Squash Merge the PR, but other than that you shouldn't need to worry about that.
Squashing locally and force-pushing messes with reviews so I'd advice against it.
Though it is of course not the end of the world, but I wouldn't recommend doing it
nervously looks at my absolute General Sherman of a commit tree
That's an interesting solution which does not seem like the proper solution, and feels like it causes more problems than it fixes.
Mostly pygen, I haven't seen it used much in other channels I look into. From a quick look at the usages in there, it didn't look like the command did much for what it is for, and there were a couple of uses when there was an actual on topic conversation going on
I use it occasionally in gen or ot when things start to go a little sideways
Usually it looks like the user who ran the command responds and it ends there; if the conversation needs to move on from something then it can wait for a bit for someone with a message unrelated to the old topic to come in in or if it's being disruptive I think a mod is more fitting instead of throwing topics around
I see. Thank you~
Is the spam usage usually coming from one person or multiple people?
Also, I'm looking at sir-lancebot's env var ref (https://pythondiscord.com/pages/guides/pydis-guides/contributing/sir-lancebot/env-var-reference/>) and this particular line bugs me MONTH_OVERRIDE Interger in range [0, 12], overrides current month w.r.t. seasonal decoratorsAm I supposed to interpret that as "Number between 0 and 12 inclusive"? Because that would be 13 months/year in math notation
range isn't inclusive though by default. But that is definitely a typo for Interger
Oh, right, range(). Still though, some clarification would be nice personally since I'm kinda spoiled by math notation by number intervals ie. (-8, 4]
!remind 1h30M re-review Chris' PR
Your reminder will arrive on <t:1632492575:F>!
The spammy usage would usually be from a single person, but then there's the usages with normal conversations going around which are just disruptive and whether it's actually doing more than a normal message (or none at all) from the user would do. Of course I don't watch the channel and the command usages too closely to judge this myself properly however imo it is worth looking into
From my experience it helps disrupt the disrupters with something that's on topic, so I personally like it
Yeah, it is also quite useful to have all the "bruh"s, "xd"s and "lmao"s after unsilencing a channel
For bot#1839, do we just want to add an isinstance check before the await handle_role_change with a log.warning? Something likepy if isinstance(author:=message.author, discord.User): log.warning(f"{author} ({author.id}) is no longer in the server so not handling role change.") return await handle_role_change(author, author.add_roles)
Aight
Do we want to also close the help channel?
Eh I suppose they could rejoin actually if they left voluntarily
And there's no shortage
Ah wait I don't think that if will work
Yeah, cause Member subclasses User. Just need to do it the other way round
I don't think it does, they just implement the same abc
if you're worried about inheritance, you coudl use type(author) == User
At the moment I'm doing not isinstance(author := message.author, discord.Member)
I guess type(author) is User would be better though
It may not matter, according to what Numerlor says
Do we still want to pin the message if the user leaves? (In case they rejoin)
since they're not strictly inherited
Will check this
Yeah, looks like that is true from the source code
CC @vale ibex
not imo
I think we leave the rest of the the process the same
should probably have the same check on removing the role too (if it isn't there already)
maybe move this check into the handle role change util
hmm
You said no (meaning change) but then said to keep the same? @vale ibex
And if we're going to "keep the same" there's no point wasting an API call trying to DM someone we know isn't in the server
hm... this could also be a cache error
cc @vale ibex its possible for a member to be a user if they aren't in the cache iirc
I was just thinking that but not sure
btw, what's the current cache count 👀
are we still having that issue with the cache not being full
I think sending the message will put the user in the member cache so it's fine
This isn't a caching issue, as it's started by a user sending a message
the issue is if they leave the guild in the period between sending a message and this line being hit
which caused this particular sentry error to hit
At this point we could just do it and except the NotFound error tbh
It's interesting though, because the user sent the message in the guild, meaning they were a Member at the time message was sent
So I'd expect a NotFound error rather than message.author being a User
yea, which ever one is the relevant error lol
iirc when a member leaves, that causes the member cache to update
which is why the member object became a user obj
I'd have to test stuff
👌
This is correct by the way, thanks
<class 'discord.member.Member'>
False
```that's seemingly not the case.
The first line is type of message.author, second is whether the message.author in message.guild.members
(And I do have the members intents)
So I'm not in the server, but message.author is still a discord.Member
Which seems to infer this is what's happening here?
<class 'discord.member.Member'>: # type(message.author)
3 # len(message.guild.members)
{USER} has left the server # on_member_remove event
<class 'discord.member.Member'>: # type(message.author)
2 # len(message.guild.members)```
So seemingly guild.members gets updated, but not message.author?
From further tests with len(message.author.guild.members) the guild attribute of message.author is updating, but the type of message.author isn't
how are you checking this, are you printing, waiting for leave, and print again?
yeah
@bot.event
async def on_message(message):
print(type(message.author))
print(len(message.author.guild.members))
await asyncio.sleep(10) # gives me 10 seconds to leave the server
print(type(message.author))
print(len(message.author.guild.members))
@bot.event
async def on_member_remove(member):
print(f"{member} has left the server")```
the message is immutable iirc
or at least, the class instance is created on each message and isn't updated halfway through
the guild is more expensive to recreate though, so it isnt recreated
that and the fact that discord objects are one massive circular data structure so at some point you gotta stop making new objects 
Hmm
That doesn't really make sense to me
"the guild is more expensive to recreate though, so it isn't recreated"
But bothmessage.author.guild.membersandmessage.guild.memberschanges?
So it is getting recreated?
thats because theyre the same guild
Right yeah
its not recreated just that _members is updated
hmm
But surely this code represents what happens in @stable mountain
The cause of message.author being a discord.User CANNOT be because the user left the server after sending the message? Since message.author DOESN'T get updated
>>> @c.event
... async def on_message(m):
... print(id(m.author))
...
>>> c.run("token")
139760620427200
139760602405440
139760602406336
139760602405824
139760620426816
```if this helps illustrate what i mean, im not good at talking today :P
That's not what my above code does though
That creates a new message.author for each new message. The point of my code is it's the same message, but the author has left
yeah and my point is that a new member is created per message, and it's attributes aren't changed halfway through a message handler/command
Exactly
^^^
the guild is updated, but you're not physically going
message.guild = a_new_guild
you're just doing
message.guild._members.pop(member_id_to_be_removed)
I'm not talking about updating a guild at the moment
Determining whether this is true or not is the sole purpose of this code
after the message has been created the message's attributes are never directly updated since a new Member object is created for each message event to prevent exactly that kind of weird behaviour where an object's attribute updates mid-way through performing operations on it, hence why I was demonstrating that the object has a new id on each message
So my statement is correct?
i think so but i dont think my brain is parsing english correctly rn
What I can say is back when me and laundmo were developing for a server probably 18 months ago we had the same issue, spent days trying to find it, and never could find a solution or even a good reason
@vale ibex (or whoever opened the issue) believes that bot#1839 was caused by the user leaving the server (due to being banned) just after the message being sent, but before message.author.add_roles() was executed.
From my understand of what you have just said, this isn't possible because message.author doesn't get updated once it's created. It's either always a discord.Member or always a discord.User.
This means that the believed cause of the error, CANNOT be what is suspected, and it was caused by something else (e.g. a cache issue)
Nw lol
I mean is it possible the user was banned before the message finished being created? And so dpy tried to set the message as Member, failed, and fell-back to User?
It maybe be possible, but you'd need to look at the internal logic the whole way through the process to find anything
thats what made it so annoying for me and laundmo, there was so much stuff to look through and not enough instances of this weird thing happening to be useful to us finding it
Can I request for my PR to be reviewed?
or it's a queue and I'll just have to wait?
You can request it, but I would recommend to be patient as there are probably 10 reviewers currently lol
Is it sir-lancebot#785?
yup, been sitting on it for a while, managed to find time to work on it today
I mean presumably it doesn't matter what the cause is, you just need to check isinstance(message.author, discord.User):? Since we know the type won't change
yeah
as long as you make the logic safe of getting either object you should be fine
👍
Here's your reminder: re-review Chris' PR
[Jump back to when you created the reminder](#dev-contrib message)
@vale ibex Sorry for all the pings, but let me summarize and ask a final question:
Summary: The issue is likely caused by either a cache issue or the user leaving the server BEFORE the discord.Message gets created (NOT before the message.author.add_roles() call, since message.author doesn't update when the user leaves the guild).
Question: Since we aren't aware of what exactly causes this, do we want to do a log.warning to generate a sentry? Perhaps some point in the future we'll be able to figure out what's going on?
!remind 18h I hate public transports, especially when you learn one minute before the departure that your train won't stop at your station
Your reminder will arrive on <t:1632558225:F>!
Yea sounds like a decent reason to use a warning, it'll give us a traceback in sentry then too, we can always lower it if needed in future.
Oh yeah feel free to send a reminder if it has been a while.
got it
Did you see my comment? 👀
Anyone got a relatively short and self-contained task I could work on?
Want to review / test sir-lancebot#842? Its a fun one and it works pretty well I think
I'll take a look.
Review sir-lancebot#849?
Hey Kron
Hola brad
Just got some snacks, lemme crack open GH..
Blue's last comment on your PR is something I'm running into on the WTF python command too. This isn't linking correctly: https://github.com/python-discord/sir-lancebot/blob/3adc085d37e8c668a5736c5b54404702e88e108a/bot/exts/utilities/wtf_python.py#L135-L139
bot/exts/utilities/wtf_python.py lines 135 to 139
embed = Embed(
title=f"WTF Python Search Result For {query}",
colour=constants.Colours.dark_green,
description=f"[Go to Repository Section]({self.headers[match]})",
)```
I'm needing reviews on bot#1845, bot#1836, bot#1822, bot#1806 and bot#1798 if you can help out (yes I have a lot of PRs opened; there's also bot#1831 but that's a slightly more in-depth review)
Oof, too many PRs for @dusky shore
bot#1845, bot#1836, bot#1822, bot#1806 and bot#1798
bot#1831
that's a lot of stuffs to review
Looking at sir-lancebot#842 currently.
They're all really small PRs though (other than 1831)
Just little quick-fixes
Nothing as in-detail as color command since I don't have enough time :p
Configuration and documentation for Python Discord's Kubernetes setup!
What are Kubernetes
Kubernetes is a container orchestration platform that we use to deploy our applications
Deployy our applications wdym
When we write new code on git we have a deployment flow that packages that code up into a docker image, then our Kubernetes cluster spawns an instance of it
Ohhh
lol
Hey @last patio, site#594 has been opened in accordance with the comment you left on sir-lancebot#611
sir-lancebot#878 very easy review if anyone is looking for one 🙂
comment left :D
Sometimes I feel like my replies to comments on github sound too defensive, anyone else feel that sometimes?
Your last few comments seem perfectly reasonable, it is normal to defend your implementation choices
Thanks Akarys
I don't seem to be able to reply to comments in a PR, other than "quote reply" 🤔
Ahh yeah, if it is outside of a review I think you have to quote reply
Weird. Has that always been the case?
I think so, but then again I haven't been active for github for long
Can I add additional comments to a review?
For sure! Keep them coming You should be able to
I really hate Github 😄
Gotta start a new review to add comments?
Erm, I don't even know tbh. If you want a comment that can be replied to, I'm guessing it has to reference a particular line of the code and be part of a review? 🤔
Hey so I was trying to find a way to clean the anagrams.json file, could anyone help me out a bit here
# anagram.json file contains all the anagrams
with open(Path("anagram.json"), "r") as f:
ANAGRAMS_ALL = json.load(f)
print(len(ANAGRAMS_ALL))
# text file contains all the common words
with open(Path("google-10000-english-no-swears.txt"), "r") as z:
COMMON_WORDS = z.readlines()
def sortString(str):
return ''.join(sorted(str))
count = 0
for i in COMMON_WORDS:
if sortString(i) in ANAGRAMS_ALL:
print("WAS IN")
count += 1
print(type(COMMON_WORDS[0]))
print(sortString("theater"))
print(sortString("theater") in ANAGRAMS_ALL)
print(count)```
Beats me too, I'm good with comments anywhere though so feel free to use my PR as a testing place lol
Alright 👍
So ANAGRAMS_ALL contains all anagrams, if trying to find out the list of common words which could be used for anagrams which would be easier to populate and find
ANAGRAMS_ALL is a dict with keys, which are sorted letters of words
Could this be something you can run once and create a new file out of? Then just add that new file as the main reference for the command
yes
so i wanted to check how many common words are present in the ANAGRAMS_ALL , e.g. theater is present in both files , it would be present as a key in anagrams.json file, which it is but when i run the script the count is showing 0, im not sure why thats happening
anagrams.json
Should the lists be sorted first?
im sorting the letters via the function sortString
print(sortString("theater") in ANAGRAMS_ALL) this when checked it says true but for some reason its not triggering in for loop
Are you checking the keys or values of the json file in the for loop?
keys
And theater in that screen shot is a value in a list of the key aeehrtt right?
yes right
That's the only way yes
I'd throw two debug prints in your for loop, I can't tell if the variables are working the way you think
created 2 dummy files with less data
i just assume the other person knows better than me lol
i hate arguing on github
I don't even need to assume lol
Not sure what im doing wrong

I don't follow what you're trying to extract here?
If you have concrete reasons for your approach you believe the other party hasn't considered, it's completely natural to bring them up.
Otherwise yeah, I've had my fair share of arguments in internet forums and this kind of non-real time correspondence has always been a miserable experience haha
Interesting, do you think non-real time back-and-forth is worse than real-time?
I have a list of words (COMMON words) which im trying to find if they are keys in a dictionary(ANAGRAMS_ALL)
for i in COMMON_WORDS:
print(f"{i = }, {sortString(i) = }")
if sortString(i) in ANAGRAMS_ALL.keys():
count += 1
Why the keys? The keys are the scrambled characters no?
Oooh, I see the keys are the sorted characters
lol, at least 20% of the comments are wrong though
Yeah, it's like a canonical representation for a set of words that are anagrams of each other.
You can make mistakes when reviewing
And it is even easier than when programming I'd say
If you're disagreeing on something then yes. You and the other person(s) will quickly over analyze the other's statements, and people will try to convey as much information as possible all at once which like Brad said might sound defensive.
I never had this problem on github so far, but it's definitely possible
Yeah, to be honest, the person who wrote the code probably knows it best. But if a reviewer is finding it hard to understand, the code may not be structured well for comprehension, which is itself a problem.
You don't even print the count, what is it?
Hmmmm not necessarily
its 0
looks like there's some newline chars in COMMON_WORDS
I'd rather have a few wrong comments than miss some stuffn
Throw those "=" inside the {} for the f-string, and also what Chris said, you are creating COMMON_WORDS from readlines() which might include those \n characters
@vale ibex for the win, it was '\n' i guess shouldve known, looking at the print statements
I've always been under the impression that real-time chats quickly devolve and that when you have these forms of delayed (or ratelimited) discussions you need to write out good arguments.
I'm gonna guess the newline chars are at the end, and the sort was pulling them to the front
based off those prints
Yeah something like that
Now the count is 2, which is write for the small copy
@brisk brook If I work this out correctly i think i should have a file with common words which are swear free
Im using the file from this repo the license is MIT, but they said to check if we are not using file for commercial purposes, this wont be a problem right ?
Both forms have their own problems. Imagine you post a magnum opus and then you stew on what you posted for an hour before the other party replies, coming up with the ultimate comebacks, only to realize the other party is doing the exact same thing.
does mit apply to resources?
mit applies to anything in the repo
We're not commercial, but the statement doesn't sound very MIT-ish
I just realized im not going to be using that file, im using that file to create another file
which ill be using
This won't be a problem no, because we aren't including it in our repo (which is when we need to check compatibility afaik). You're just matching it against your file
Yes this 
Btw @dim pelican, if you disagree with any of my comments/suggestions, please do say so! There's nothing worse than feeling like you have to incorporate someone else's bad ideas into your code out of politeness 
Ehhh, yeah that's true. For reference y'know that Project Winter game server I moderate? Well there's a suggestions channel and a channel for discussion.
Before we had that discussion channel you'd discuss suggestions directly in the suggestions channel but even then because of the slowmode it would be pretty chill (sometimes going to general-chat if the discussion picked up).
Now we've introduced a discussion channel, and it has happened several times where we need to deeply moderate and cool down the channel.
That said I have had bad heated discussions in forums as well
All good! There's nothing in the comments that is unreasonable or a bad idea
MIT does require including the original copyright notice, when substantial portions of the code are used, however. I'm never really sure how this works when you have a lot of (substantial) bits of code from different MIT licensed projects. Like, where do you attribute them in your project?
Hey! Could someone help me with poetry?
It seems like that the dependency "psycopg2" is installed as a package extra in the poetry environment of the api (https://github.com/python-discord/api/blob/main/poetry.lock#L715) However, when I try to import it, it throws an error that the module is not found.
poetry.lock line 715
postgresql = ["psycopg2 (>=2.7)"]```
That just lists the extras for the package, you'd see psycopg2 as its own package if it was installed
Oh, okay then. Thank you. 😄
!remind 9h review site#591
Your reminder will arrive on <t:1632548230:F>!
poetry install -E postgresql
bump sir-lancebot#878
oh wait.
https://github.com/python-discord/error-pages What are error pages
These
html pages you get served when there's an error
smh @patent pivot would you please update the easter egg that gives impossible to follow instructions
They are html pages ?
Just that
So Can I fix a error there
But where are the error written there is just a website
Here's your reminder: review site#591
[Jump back to when you created the reminder](#dev-contrib message)
rock solid kronifer thank u
@brisk brook I have updated the anagram.json file now, the sir-lancebot#874 PR is disapproved as of now, could you please take a look
I saw this and did consider it, I don't think it's critical, please save pings for important stuff, otherwise just drop a message here or in #community-meta and ping if I miss it
Here's your reminder: I hate public transports, especially when you learn one minute before the departure that your train won't stop at your station
[Jump back to when you created the reminder](#dev-contrib message)
bot/exts/backend/error_handler.py lines 254 to 259
await self.get_help_command(ctx)
self.bot.stats.incr("errors.bad_union_argument")
elif isinstance(e, errors.ArgumentParsingError):
embed = self._get_error_embed("Argument parsing error", str(e))
await ctx.send(embed=embed)
self.get_help_command(ctx).close()```
missing await, may I make a pr?
self.get_help_command(ctx) is a coroutine, which means that it will be made, but never ran.
simple solution here is to turn it into (await self.get_help_command(ctx)).close()
self.get_help_command returns a coro, it isn't a coro itself
I think the .close() is calling the .close() method on the coro itself
Expected closing ".
Well, if it wasn't awaited, it would be in logs now
ah... makes sense
If it creates the Coro it probably isn't necessary; I added it when the Coro was created at the start of the func. But I don't think it's really worth changing in a standalone pr
Yeah, it's fine how it is. I thought it was a unawaited coroutine
It is fine, but it looks unnecessary of I'm looking at it correctly if it creates a Coro just to close it
Hey @fallen patrol , I'll be offline for a bit but I should get to the site docs stupid
hmm?
Hi! I am working on bot#1765 and am currently doing the monthly post. Should I include handling if someone has multiple roles to assume the highest, or can I be sure that they will never have 2 roles at once and my lists will be accurate?
It is possible that someone will have more than one role
In that case, just use the highest tier they have
ok, will include handling then!
👌
using this to filter down, I feel like there is a better way to do this though?
tier_1_members: list[discord.Member] = guild.get_role(constants.Roles.patreon_tier_1).members
tier_2_members: list[discord.Member] = guild.get_role(constants.Roles.patreon_tier_2).members
tier_3_members: list[discord.Member] = guild.get_role(constants.Roles.patreon_tier_3).members
actual_tier_1_members: list[discord.Member] = []
actual_tier_2_members: list[discord.Member] = []
actual_tier_3_members: list[discord.Member] = tier_3_members
for member in tier_1_members:
if not member in [*tier_2_members, *tier_3_members]:
actual_tier_1_members.append(member)
for member in tier_2_members:
if not member in tier_3_members:
actual_tier_2_members.append(member)
if you used sets you could do ```py
actual_tier_1_members = tier_1_members - tier_2_members - tier_3_members
actual_tier_2_members = tier_2_members - tier_3_members
like this?
tier_1_members: set[discord.Member] = guild.get_role(constants.Roles.patreon_tier_1).members
tier_2_members: set[discord.Member] = guild.get_role(constants.Roles.patreon_tier_2).members
tier_3_members: set[discord.Member] = guild.get_role(constants.Roles.patreon_tier_3).members
actual_tier_1_members: set[discord.Member] = tier_1_members - tier_2_members - tier_3_members
actual_tier_2_members: set[discord.Member] = tier_2_members - tier_3_members
actual_tier_3_members: set[discord.Member] = tier_3_members
that definitelt seems much better!
The type hints wouldn't do the conversion for you
tier_1_members = set(guild.get_role(constants.Roles.patreon_tier_1).members)
tier_2_members = set(guild.get_role(constants.Roles.patreon_tier_2).members)
actual_tier_3_members = set(guild.get_role(constants.Roles.patreon_tier_3).members)
actual_tier_1_members = tier_1_members - tier_2_members - actual_tier_3_members
actual_tier_2_members = tier_2_members - actual_tier_3_members
aah yes, forgot about that!
Hey @vale ibex , could you please #changelog the new Hangman command?
Along with the .gitpod.yml please
I'm not home until tomorrow, any admin can change log it, so another might see it before I'm back 😀
Oh ok
@brisk brook btw the difference between "Add to PATH" and installing the "py launcher" is the prior gives access to python, whilst the latter gives access to py.
The two of these are mostly the same but vary slightly e.g. py has version handling (e.g. py -3.6-64 -m pip install numpy to install numpy on the 64-bit python 3.6 installation)
Answering here since on phone cause going to bed now
Ah, cool
@brisk brook I commented on 860, its actually pretty easy to remove the view when it expires
tldr
!d discord.ui.View.wait
await wait()```
Waits until the view has finished interacting.
A view is considered finished when [`stop()`](https://discordpy.readthedocs.io/en/master/api.html#discord.ui.View.stop "discord.ui.View.stop") is called or it times out.
The view doesn’t expire for a while?
It works after a few minutes
I don’t get why we want to wait for it to expire
Sorry, I’m just confused
Because the user won’t be looking at it anywyas
By default the view expires after 3 minutes (I assume 3 minutes after it was last used).
The idea is that we'll edit the message to have disabled buttons (they show up greyed out in the client).
Hm
I doubt anyone would still be using that message after 3 minutes though
I'm not opposed to the change, I'm just not sure what the purpose of it would be
a button paginator for @dusky shore would be great
It's highly worth removing them. Internally buttons and their names are referred to with a custom ID, which fwiw, should be manually set instead of setting the library decide--this will be useful in the end and I can explain why later.
When the bot receives an interaction over the gateway, it only receives the message and the button ID. this means that we'd be getting a lot of old requests if a user used an old button. It's not worth the possible extra requests by leaving them active.
For the custom ids, these determine which button is which. I personally recommend giving every button or select its own ID, since the api itself requires them. If they aren't provided discord py does a very rudimentary random generate which can easily cause future problems if we have enough selects. It's best to give all a custom ID. IMO, this should be name spaced, eg "challenges_select"
I will copy that to the issue.
Been talked about before, I agree, but the buttons were too big iirc
would that mean that its not gonna be added anywhere?
I'm for it.
But I also don't have any pull over whether it's added or not :D
and then on interaction it sends the quoted msg to the users dms and replies with an ephemeral message for confirmation
any ephermal messages would require slash commands or buttons or selects or context menus
slash commands and context menus are currently not doable
@fallen patrol One question about wait(), where would I exactly place it? Until I want to edit it
for discord.ui.View.wait()
got it
this would mean saving the view to a variable rather than creating it and directly passing it to the message
somewhere in this area
bot/exts/utilities/challenges.py lines 319 to 325
original_message = await ctx.send(
embed=kata_embed,
view=self.create_view(dropdown, f'https://codewars.com/kata/{first_kata_id}')
)
dropdown.original_message = original_message```
i was talking about buttons..
ah, I'm not familiar with the quote command 😅
i see
sorry, my bad, the command was supposed to be bookmark 😅
nah, nah, the help command should respond to invalid parameters
ohh
hmmm
sir-lancebot#882
sir-lancebot#883
thanks man
also the button with an ephemeral message on interaction, for the bookmark command
i cant make an issue rn so its up to you if you wanna make an issue for this as well
sure, go ahead with making an issue 😄
@patent pivot i don't think a web app for bootstrapping is the right solution. With that you won't be able to migrate your existing server, and you'd have to someone have access to the current configuration schema. That's why I think bootstrapping should be a cog on the bot. Have you listened to the recording of the discussion between scale and myself?
The OAuth system, despite being cool, has some major flaws imo
migration isn't something I accounted for, no, but for new contribs migration shouldn't be a major problem, this is targeting people new to dev
Well, a web page is more effort and has drawbacks such as not being able to migrate or easily parse the configuration if we ever change the configuration system. How about we do a pros and cons of config cog vs OAuth website?
either way I'm going to do a site either as a personal or pydis project, because I think it'd be interesting to do, if someone else wants to look at the cog approach I'm open to that
also I don't think it's more effort necessarily
a few API calls and some jinja
as I said, web bootstrap is a weekend project, cog probably isn't
I'm not sure that dealing with migrations is time well spent
What are migrations? a new channel?
A person who already has a server can open one themselves
I'd much rather first see something that just sets up the server for you with a matching config
yeah
For the color command: cc @dim pelican and @elder belfry -- I'm wondering if you all grab from a certain link or what not, if so, maybe you could use a view to have the link where you grab the information from?
We do all of the conversions with our own conversion functions, except for the Hex -> RGB where we use the PIL ImageColor.getcolor
Ah alright
I agree that this doesn't need to be in the MVP, but why paint ourselves in a corner by using a system that can't evolves later on?
@dim pelican, have you read my comment on the structure of the color cog?
How would the web idea work, and why would it not be suitable for migrations/updates?
Yeah I've been keeping an eye on the comments! Just taking a little break from coding to recover from the code jam
Pretty much the main command would have it's own parser to determine the mode?
Alright 👍 No rush, I'm just bored and looking for something to do 😄
Yep. Although I think you could do it with regex, if you want to.
Time to learn the dark arts

Hey! If someone has some free time and is interested in SQLAlchemy, I would love to have some feedback on api#17
I need as many reviews as possible to filter out possible errors. 😄
Smart config and bootstrapping. I still have no idea which project is which
lol
smartconfig is a config system/tool, bootstrapping would be our existing config system auto-generated by an OAuth2 app
The idea of the web portal is to have a bot generate the server based on the configuration in main, add the user and transfer the ownership. The problem is the web portal doesn't have any idea of what configuration file the user currently has, or what the target configuration really is, because it is running online.
are bots able to transfer ownership?
Yes
I'm a bit confused. The user doesn't have a configuration file, this is creating a server from scratch, right? Then it'll provide the config.yml for the user or something along those terms. Wouldn't the target configuration be the configuration it has loaded in?
Yes
Which is quite simple to get if the configuration system is a cog, but you'd have to do some fancy parsing if it is on a website
So you're saying giving the user the config.yml file is the difficult part?
cant you just provide a link to, say, an s3 object for that
I am saying getting the target configuration can be complex
While we still have the config default nightmare it is simple, just look at what it is on the git remote and parse it
I feel like I'm not on the same page. What is the target configuration here?
The list of channels, emojis, webhooks and stuff that needs to be created
What we want the bootstrapping system to output
Wouldn't that just be pre-defining it based on the default-config.yml? Like, looking at our test server template and creating something from that
my plan is basically take config-default.yml, specifically the bits that need to be configured (channels, emotes, webhooks) and then using jinja to template it, the macros then fire an API request to create a channel/emote/whatever and insert the relevant ID, then the app force joins the user to the server, transfers ownership and allows a config.yml with all ID constants pre-filled
So we lock ourselves into keeping config-default.yml? Hello no, please
that sounds nice. What would it look like for a user? Go to a webpage and click a button? Something else?
what's the issue there? Isn't that how we've been doing it for awhile now?
Yes, and it is pain
we've already discussed ways to make that better, like just looking we probably don't need every colour we use in our config file, that can go in a constants file
yep, visit a web app and it requests the guild join scope, bot makes the guild, sets things up and then joins you to it, transfers ownership and then leaves
what about the default-config.yml is a pain specifically? It's large and cumbersome, but honestly so is python bot.
We agreed in the core devs meeting to yeet config default because it was stupid, why are you suddenly walking back on that one?
we can probably cut down the length of config-default, we have probably been a bit generous with what should actually be configurable
We could split it into server config, and feature config, although most feature config could probably just be constants defined in the respective file
We are duplicating the information, each config attribute is both in config default and constants.py. We wanted to use a tool with an API similar to smartconfig (don't care if we use a different one) to stop doing that.
I'm not walking back on it? I'm just putting forward a solution to the current issue that people find it tricky to set up the bot. If I do this work and it's outdated in a month or even a week, I don't care. We haven't made any solid progress towards config replacements and this is a project that immediately can alleviate some setup pain.
I'm not saying config-default is the way to go, but while it is the system we use we can implement tooling to make it less painful.
What I am saying is why you want to spend time and effort on a project that will either have to be taken down after changing the configuration system or will make us never change it?
I'm spending time on something to try and help new contributors, I have the time and I don't mind building a system which goes out of date, that's the nature of most tooling.
That's why I am suggesting a configuration cog from the start. Also it would be applicable to sir lance too. This is even less effort, you don't have to worry about the OAuth stuff and all.
So, my outside perspective as someone who isn't a core dev and spent a hell of a time getting Python bot set up is that this magic configuration and bootstrapping system has been in the works for a while now. At this point, having something good enough and actually done and usable is better than a magic, perfect, ideal system that frankly doesn't look like it'll happen taking into consideration the track record so far.
I don't really think there are huge differences in difficulty tbqh, it's some templating and API calls
Well, I won't dictate you how to spend your time, if you tell me you won't hesitate to drop that project if we need to when changing the configuration system, then I don't really care
I just think that we've had enough feedback which indicates that the setup is a larger problem than the length of the config file, it's a laborious task to copy IDs, after that it's not bad to configure.
I am not saying the opposite, and I'd be 200% for workibg on a bootstrapping system right now
I simply think the chosen solution isn't the right one, it isn't future-proof
Nothing is 100% futureproof, whatever happens if we switch away from discord.py / change config / whatever there will always be something we need to rebuild, OAuth2 bootstrap is just something simple to help new contributors
Whatever Joe, whatever
I don't think we are listening to each other, let's just stop here
I'm open to discussion, I'm not trying to have this block any sort of changes to the config system, if it helps then this can be considered more of a personal third party project to alleviate complexities of setup in the short term while we build better first party support in the long term.
Honestly it's probably possible to make a reverse config-default.yaml file
Rather than being read by the bot, it could be automatically generated. This would serve as a bouncing off point to make a custom configuration, since now a user would just need to copy the default file to a new file.
This also removes the bot's dependency on the default configuration file, which is now there just for users who contribute.
It would never be read by the bot, but would be generated with a pre-commit hook
This is what I'm responding to, my above messages are not related to the projects of the names bootstrap and smartconfig, but rather yeeting config-default.yaml
When I say it's probably possible, I mean it 100% is possible. I've done everything I just listed for a different project.
If we yeet config default as a way of storing default configuration, I'd like to avoid suggesting to copy config default to make your own config anymore
This really isn't a good thing when changes are done to the default config
What do you mean?
There's no real reason for us to have yaml in the first place tbh
Yeah, use toml /s
Could have people put everything in one place in the env file
The only small problem with env is .
We really don't need the structure
Espically with bootstrapping, which will leave you with like a couple variables you need to configure at worst
But uh
Wouldn't bootstrapping still leave you with all of the role and emojis to configure?
And channels
So now there's 20+ environment variables
with bootstrapping in theory channels, roles and emotes are accounted for
Like, even if the user doesn't have to configure them themselves, now there's a 20 var env
the bootstrapper fills in the ID values for each
... And where does it fill them in?
well, with the current system it generates a config.yaml file
And with what scale suggested, it'd fill them in with the env vars
down the line it would do whatever is necessary (or the solution we have down the line does that for us)
yeah
I mean, you don't actually have to have it all in one env file. You can have multiple env files
So now there's 20 env vars, is there not?
Ah yes, multiple configuration files of the same type, never sounds like a good idea
I mean I don't see why that is bad though in this use case
if we have an env that's very clearly for channels and discord data and then one for bot config it's still just as usable
Wouldn't we use the variable names to make a form of structure either way?
As long as each env file didn't load everything ig
So constants.py would look like:
token = os.getenv("TOKEN")
guild_id = os.getenv("GUILD_ID", "pydis guild ID here as default")
non_changeable_setting = "value"```
guild.env:
GUILD_ID = "128913823212"
.env:
TOKEN = "2798eyeduih2"
You can still have it in the py file, and you probably should
Like CHANNEL_DUCK_POND is the same idea as
channels:
duck_pond: ... ```
*with an S
config DSL when 👽
Yes, obviously
DSL?
Honestly not that bad of an idea haha
domain-specific language
Which is...?
My idea is mostly eliminating the yaml file for the purpose of eliminating the yaml file. The yaml files just have us duplicating everything in two files that we have to manage.
The env variable approach just means we have one central location of truth
The structure is also very unapproachable for people that aren't familiar with it. Env vars (of which you'll only have to do 2, 3, etc) are just simpler
We have empirical evidence for that here
Your concepts are lost on me.
one central location of truth
multiple .env files
I mean the env files aren't location of truths
They are literally just generated files, one with 2 variables which are technically duplicated in name, while the other is auto generated
And the config default file couldn't be removed as truth by being auto-generated why?
I don't follow? I am advocating for removing the default config in favor of py file configs like I gave an example of above
this
Seems kind of repetitive idk
Which part is repetitive?
Like, nearly single variable now needs os.getenv
I mean, it works, but, there seems like a better way
I mean, that's not actually true. We can pretty easily have it applied by default to every variable like metricity does
But do you have other suggestions
Eh, the only ways I think of are more work than that lol
The goal of smartconfig was to yeet config default and only have one config file for overrides. I was discussing yesterday the possibility of supporting env vars, so maybe we can work together on that one?
I'm not sure if that's the plan we're gonna go with yet, but yeah I'd be happy to work on it
I am really not a fan of spamming os.getenv on hundreds of lines of configuration, that doesn't seem very DRY
We can actually have pydantic do like 90% of the work for us
Hmm I can write a draft of my idea right now
I like that. So would there be no config-default?
But if you ask me having a sense of structure through a yaml file (even if it is only one level deep, like just channels.duck_pond) would be easier to navigate. You can add whitspaces, you can add comments, you can add anchor tags..
Anddd, I forgot to scroll down
That's what I want for smartconfig. Don't know if we are gonna use that for pydis.
I mean, I'm saying we move this to the py file, because no one needs to override it, and navigating py code is much easier (my IDE does it for me)
Oh, so like you want to use a python file for inputting overrides?
Nah, "overrides" would be in your env, but like you really don't need to override much of anything
i personally don't like pydantic too much since its too high level lol
Depends on whenever you count discord channels and such. Also urls and stuff like that has to be overridden for the local env to work
would much rather write a configuration system and handle all of the loading myself
Right... well you could go contribute to pydantic
but that's just me, if pydantic is easiest to make a maintainable configuration system go for it
no, its the whole concept of pydantic. Contributing would not help
I personally disagree with your philosophy, as it sounds like reinventing the wheel, but I think we agree to disagree
ye
I agree with Scale, pydantic is really easy and nice to use
pydantic is great at what it does but if you want to go lower level and have bounds more customisation, your own system is where its at
But isn't pydantic supposed to be a database thing lol
nah
It's mostly just more feature rich dataclasses
It can be used as that, but it also has something called BaseSettings specifically for settings/config systems
^
We could look into that for the bot
Data validation and settings management using python 3.6 type hinting
I just don't like pydantic because of its built in validation
Well that's kind of the same thing, it converts and if the conversion fails then it also fails validation
In you guys' case you want to like validate channels, which becomes trickier
I think we don't really want to validate
We just want to make the setup process easier
it does, this is how to turn it off https://pydantic-docs.helpmanual.io/usage/models/#creating-models-without-validation
Data validation and settings management using python 3.6 type hinting
^ Don't we just want the value to error (in the code, not the config) it's wrong?
Which means we make the server initially, and if someone changes it and breaks, well, they'll know what broke
I mean, I clearly mention that. I said it does conversion lol
It doesn't do validation
Isn't validation (in pydantic) just checking if the type matches, or does it go beyond that?
its conversion is also validation
I personally see validation as confirming that the data is off the right format, and expected value
Eh, sure I guess. I really don't think conversion falls under the umbrella as much as other thing
I'm thinking validators specficially
It goes a bit further, being able to turn JSON dicts into models and similar
Alright I'm closing our oldest PR on @stable mountain. Opened March of 2020. https://github.com/python-discord/bot/pull/836
Ah, ok. That sounds like something we can use (for snowflakes and the such).
I mean, that part requires manual validation
The reason to use pydantic would be getting automatic conversions, and structure
We were considering it for metricity for instance, since we wanted to be able to convert guild_id env var to an int
Which pydantic would just do
@gritty wind just noticed this makes the unit testing project 100%
Very cool, time to drop the tests dir lol
should I close both the projects?
I don't seem the need for them to be open
alright both of them are closed
@vale ibex is this supposed to be titled "add get and fetch util"? https://github.com/python-discord/bot/pull/1837
or is the current title correct?
oh wait I see why now
you saw nothing
The actual python function is get_or_fetch_member so that's why
Hm, could someone pull up some logs for this?
I made an issue about it here: https://github.com/python-discord/seasonalbot/issues/882
2021-09-26 19:15:15
ValueError: dictionary update sequence element #0 has length 3; 2 is required
2021-09-26 19:15:15
raise HelpQueryNotFound(f'Query "{query}" not found.', dict(result))
2021-09-26 19:15:15
File "/bot/bot/exts/core/help.py", line 164, in _handle_not_found
2021-09-26 19:15:15
self._handle_not_found(query)
2021-09-26 19:15:15
File "/bot/bot/exts/core/help.py", line 151, in _get_query
2021-09-26 19:15:15
self.query = self._get_query(query_str)
2021-09-26 19:15:15
File "/bot/bot/exts/core/help.py", line 97, in __init__
2021-09-26 19:15:15
session = cls(ctx, *command, **options)
2021-09-26 19:15:15
File "/bot/bot/exts/core/help.py", line 452, in start
2021-09-26 19:15:15
await HelpSession.start(ctx, *commands)
2021-09-26 19:15:15
File "/bot/bot/exts/core/help.py", line 511, in new_help
2021-09-26 19:15:15
ret = await coro(*args, **kwargs)
2021-09-26 19:15:15
File "/usr/local/lib/python3.9/site-packages/discord/ext/commands/core.py", line 167, in wrapped
2021-09-26 19:15:15
Traceback (most recent call last):
2021-09-26 19:15:15
09/26/21 19:15:15 - bot.exts.core.error_handler ERROR: Unhandled command error: dictionary update sequence element #0 has length 3; 2 is required
2021-09-26 19:12:25
AttributeError: 'NoneType' object has no attribute 'id'
I believe there's already an issue open for it
sir-lancebot#863 @fallen patrol
882 is a dupe then
mhm
hey @vale ibex , the gitpod.yml pr was merged a bit early, i need to open one quickly to add something shortly
itll just be some git commands
or i could just give the commands to run in the contributing guide
actually yeah that makes more sense
For sir-lancebot#863, do we want to just copy what @stable mountain does or do we want to only pass the keys to the error since that's all that ever gets used? Aka {choice[0]: choice[1] for choice in result} or [choice[0] for choice in result]
To me it seems more logical to only pass what's actually used
@patent pivot @green oriole I did a thing
import pydantic
ENV_FILE_PATHS = [
"server.env",
".env"
]
env_vars = {}
try:
import dotenv
for file in ENV_FILE_PATHS:
dotenv.load_dotenv(file, override=True)
except ModuleNotFoundError:
pass
class SomeGeneralSettings(pydantic.BaseSettings):
x: int
class ServerSettings(pydantic.BaseSettings):
id: int
class Config:
env_prefix = "guild_"
What this'll do is it'll try to read both the server.env and .env files (in that order, so .env would override server.env). Pydantic handles it from there. I'm not sure about the env_prefix thing, what it'll do is instead of a variable being called something like bot_commands in the env file, it would be guild_bot_commands. For the one in the example, it'll be guild_id.
If it can't find a source for a variable it does this:
Traceback (most recent call last):
File "C:\GitHub\Python Prototyping\main.py", line 24, in <module>
print(Settings())
File "pydantic\env_settings.py", line 36, in pydantic.env_settings.BaseSettings.__init__
File "pydantic\main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Settings
x
field required (type=value_error.missing)
Admittedly not the most beautiful, though we could add a wrapper around the import constants which formats this
Or actually just whenever we're initing the classes
try:
SomeGeneralSettings()
except pydantic.error_wrappers.ValidationError as e:
print(f"Failed to start the bot due to a missing environment variable: {e.model.__name__} - {' '.join(e.errors()[0]['loc'])}")
Failed to start the bot due to a missing environment variable: SomeGeneralSettings - x
😅
^ bump
hi there people, site#594 needs reviews
I actually missed a bit, the env loading needs to be: dotenv.load_dotenv(file, override=True)
I think we want the former? Honestly, whichever works is fine
I mean it seems weird to pass data we know we aren't going to use
At least to me
So I'd prefer the latter
Tbh I don't see a reason to load the env file into the environment
What do you have in mind?
Can use dotenv.dotenv_values to get a dictionary of all of the keys in the provided file or stream
I don't follow, what do you do after that
I think you missed my earlier snippet of code
Pydantic pulls from the environment variables
Well, then you don't need that loading code at all :P
You do, otherwise those files aren't in the environment
Data validation and settings management using python 3.6 type hinting
I saw that, but it only supports one file
Config:
env_file = ''
Ok, tell me how
Your reminder will arrive on <t:1645906151:F>!
!remind 5M this
Your reminder will arrive on <t:1632687260:F>!
!remind delete 3132
That reminder has been deleted successfully!
modmail/config.py lines 81 to 94
@classmethod
def customise_sources(
cls,
init_settings: SettingsSourceCallable,
env_settings: SettingsSourceCallable,
file_secret_settings: SettingsSourceCallable,
) -> Tuple[SettingsSourceCallable, ...]:
return (
env_settings,
init_settings,
file_secret_settings,
toml_user_config_source,
toml_default_config_source,
)```
Data validation and settings management using python 3.6 type hinting
How do you use this to load multiple env files
I'm just seeing a lot of boilerplate in your code
not sure what you want me looking at
the customise_sources class method of a config class on a BaseSettings or BaseModel derived class is used to define the attributes in the order of the callables. If an attribute is not provided in the first class it looks at the next callable and so on and so forth
linked here
As explained earlier, pydantic ships with multiples built-in settings sources. However, you may occationally need to add your own custom sources, customise_sources makes this very easy:
Each callable should take an instance of the settings class as its sole argument and return a dict.
I'm struggling to see what i can take from this, and I'm struggling to see how it's better than loading stuff into the environment
Can you give a code example
the order here is env_settings, settings passed to the class upon creation, docker secrets, the user provided toml, the default toml file
so in its most basic form:
def other_env_settings(settings: BaseSettings) -> dict[str, Any]:
"""Loads env settings from .guild.env"""
...
class GuildSettings(BaseSettings):
...
class Config:
env_file = '.env'
@classmethod
def customise_sources(
cls,
init_settings: SettingsSourceCallable,
env_settings: SettingsSourceCallable,
file_secret_settings: SettingsSourceCallable,
) -> Tuple[SettingsSourceCallable, ...]:
return (
other_env_settings
env_settings,
init_settings,
file_secret_settings,
)
this script it not complete, it will not run as is
So where does the second env file go, and how is this a better solution than loading the env stuff
wdym where does the second env file go
why are you trying to load two env sources into a single class?
I've explained this at the top
What this'll do is it'll try to read both the server.env and .env files (in that order, so .env would override server.env)
import dotenv
env_vars = dict()
for path in ENV_FILE_PATHS:
env_vars.update(dotenv.dotenv_values(path)
Okay, listen, at this point I'm going to ask you to stop. You've changed your suggested approach thrice, and at the end settled on my approach changed slightly.
At this point, all I have to say is this feedback is really not the sort of feedback that helps project progress, it's nitpicking.
Unless I'm missing something, I don't think your proposed solution is cleaner, more obvious, or more precise
@dry folio why close seasonalbot#856?
The history of the PR got a bit muddled, so a new one will be created with a different approach
ah
anyone know the everyone role id? need to add it to Roles in constants.py
Hmm, I don't think there is one
But I could be wrong
guild ID iirc
there is
everyone id is the guild id?
think so, one sec
Oh ok
@ is for users only
267624335836053506
@& is for roles
Not gonna test it exactly cuz ya know
ohhh
well i tested it in my input box
didn't send it
haha yeah
thanks!
tldr the everyone role is guild.roles[0] which is the guild id
ahhh okay
can't remember if that is a property or a method actually
but its the first item in whatever guild.roles returns
!d discord.Guild.roles
property roles: List[discord.role.Role]```
Returns a [`list`](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.9)") of the guild’s roles in hierarchy order.
The first element of this list will be the lowest role in the hierarchy.
okay yeah its a property
sir-lancebot#885 is a very quick fix that can be reviewed now :D
reviewed :)
resolved :)
lint failed 
okay that's just embarassing
defintely should be squash merged 😛
lol true
feels great to be back, i've finally sorted out my schedule
haven't contributed anything or programmed in general since school started 3 weeks ago lmao
.bm
@dry folio it was actually so annoying that I couldn't bookmark previously within help channels 😭 so tyvm!!
lol no probs
@static canyon for bot#1836 the one typo i remember seeing you've already handled it. do you have a deadline for when you want to merge the PR? or will it be open for another week or so?
It'll be merged whenever it gets the reviews.
If you find something after it's merged that's not an issue; feel free to ping me here and I can do a quick-fix PR
okie 👍🏻
Or you can open one yourself, we appreciate contributions from everyone 💙
Please review site#594! It's a small change that can be easily reviewed
Am I allowed to add some new topics to Sir Lancebot
1.What feature do you love the most in Python?
2. Have you worked with a Python team and why?
We have a form to suggest topics, I don't know if it is still active
CC @vocal wolf
that link in the embed will lead you to where you want to go @steady junco
Oh, the link is there
Oh cool let's see
@clever wraith if you still want to work on sir-lancebot#861 let me know and I'll assign you
If not I'll probably work on it soon™️
@vale ibex The link you posted in #changelog is broken. I don't think you need the <> surrounding the link. That's what's breaking it I think.
it works fine?
angle brackets are to supress embeds
what OS are you viewing it on?
Phone
Android
I get this when I tap the link:
Oh
looks like android doesn't like the angle brackets for some reason
You'd think it would be consistent
Yeah lol
Alright, I'll check on computer later
I've removed them now anyway
no i wouldnt its discord lol
If it's stopping people on mobile from clicking the link, it's not worth the supression
you know there's a remove embeds button right?
Does that propagate to servers subbed to the announcement channel?
I didn't think it did, which is why I've always gone for angle brackets rather than deleting embeds
worth trying IG
lol
i was gonna test it
but i wouldnt get the first message anyway if i subscribed now
so it wouldnt matter
Just tested, it does work
Ok. I just saw you removed the <> signs, but now the end parenthese is not "in the link" so to speak. Screenshot in a sec
Hmm
probably some conflict with markdown
Yeah 🙁
That's probably the root cause of why angle brackets didn't work too
Try URL encoding the parentheses?
Hangman is a paper and pencil guessing game for two or more players. One player thinks of a word, phrase or sentence and the other(s) tries to guess it by suggesting letters within a certain number of guesses.
How does that look?
That works ok for me
This has been an issue with android for at least a year
It doesn't like wikipedia pages (or any other url) with (), and causes a 404
Oh damn
!embed wikipedia hangman
Hangman is a paper and pencil guessing game for two or more players. One player thinks of a word, phrase or sentence and the other(s) tries to guess it by suggesting letters within a certain number of guesses.
What does that look like on mobile?
lol yup, that's the issue
🙁 🙁 🙁
sigh
Btw @vale ibex you left reviews on Hangman but I don't think you added yourself in #changelog
Makes sense ig
By "there" you mean in #changelog , right?
yea
Ok
I think I have sometimes in the past
The Contributors role is only given to users who have helped considerably with our open source projects (more info in #roles). If you just want to get dev-announcements, you can "follow" the channel since it's a discord announcement channel

Ok

