#dev-contrib

1 messages · Page 139 of 1

austere hornet
#

Yesterday

static canyon
#
>>> 'color' in english_words_set
False
>>> 'colour' in english_words_set
False```even the biggest set misses a load of words
gritty wind
#

culur

static canyon
#

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

vale ibex
gritty wind
#

We could just create a DB of words and use the OT name system

static canyon
vale ibex
#

ah cool

static canyon
#

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

vale ibex
#

oh lol then yea, I wouldn't

#

I'm guessing things like the oxford dictionary require licenses

static canyon
static canyon
vocal prairie
static canyon
static canyon
vocal prairie
#

Oh wait, what OS are you using

#

It might be using the Unix word list

static canyon
#

nltk.download() maybe

static canyon
#
>>> 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

brazen charm
#

what's wrong with storing words locally

static canyon
brazen charm
#

A big file you download once is better than downloading it on every deploy

green oriole
#

sure

brazen charm
#

and easier to filter out unwanted words

green oriole
#

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

vale ibex
#

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

cold island
#

What does the anagram command do?

brisk brook
#

It went from 2.8.0 to 2.9.1

cold island
#

Or patch at the end

brisk brook
#

Oooooh

#

lol

vale ibex
#

yea, semver is patch

#

but not everyone follows semver

cold island
#

Yeah Python calls it micro

sour viper
#

@brisk brook You available now ?

brisk brook
#

In a few minutes yeah

sour viper
#

Let me know when available

brisk brook
sour viper
#

Yep

brisk brook
#

Can you install the Live Share extension?

sour viper
#

this one ?

brisk brook
#

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

brisk brook
sour viper
#

I think its installed

brisk brook
#

Do you have access to dev-voice?

sour viper
#

No, its greyed out, I dont think so

brisk brook
#

Then we can use the code-help channels

molten perch
#

Hey! Could someone take a look at sir-lancebot#857 ?
There has been a "bit" of a change 🙂

thorny obsidian
#

I'll give some time to give a full review tonight

sour viper
#

@brisk brook Thanks a lot for your time, couldn't have done the changes without you !

late wolf
#

What ya'll doing in dev voice?

trim cradle
green oriole
#

Talking about how we want to start working more seriously on automatic configuration

sour viper
#

@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

brisk brook
#

You can't comment on my comment, but you can comment on the PR if you see at the bottom.

sleek steppe
sour viper
brisk brook
#

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?

sour viper
#

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

dim pelican
#

Blue thanks for the reviews, looks like you are on a spree today!
#1 Reviewer

brisk brook
#

That microchip I got earlier is making me committed to appear on Microsoft's radar

dim pelican
#

You too? It made me buy 10 Windows licenses back in April

clever wraith
#

It made me get windows 11 insidee

#

Insider

austere hornet
#

@vale ibex I updated that, in case you missed my earlier message. Please take another look when you have a moment. Thanks so much!

clever wraith
#

Hey @patent pivot, i have a quick question

fallen patrol
#

writing an error handler for my bot, found an issue with the typing.Literal converter which seems easy enough to fix, but well

stable mountainBOT
#

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```
fallen patrol
#

the BadLiteralArgument exception does not inherit from BadArgument

#

which means that the BadArgument handler will fail on this

fervent sage
fallen patrol
#

That may not be an issue, but yeah

#

BadUnionArgument I think is fine that it doesn't import, since its a list of BadArguments

trail pilot
#

Sorry for asking multiple times, but could anyone review sir-lancebot#860, it's been quiet for a few days now

dusky shoreBOT
green oriole
static canyon
brisk brook
static canyon
#

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)

green oriole
#

maybe me

sour viper
#

@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

static canyon
sour viper
#

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

static canyon
#

I'm so confused

#

"we only keep anagrams from the small list" -- so we use the small one? As I said above?

dim pelican
#

100x100

#

80x80

#

60x60

#

40x40

#

20x20

brisk brook
#

Oh I see now, they actually change the size of the thumbnail?

#

Interesting

dim pelican
#

Well we are creating an image and attaching it as a thumbnail

#

So that would be the size of the image created

brisk brook
#

I'd say stick with 100x100 or lower to 80x80

trail pilot
#

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

dusky shoreBOT
dim pelican
#

Okie doke. Did my restructuring work out the way you expected as well?

austere hornet
#

@vale ibex Any updates on sir-lancebot#847?

dusky shoreBOT
green oriole
#

We have so many sir lance PRs and so little reviewers haha

dim pelican
#

*Testers
Reviewing is easy, but testing is hard because you need to checkout that branch right

brisk brook
vocal wolf
brisk brook
vocal wolf
#

With the CLI you can just do gh pr checkout 879 when in some repo

green oriole
#

Heck, did we never get an announcement out for the review guide?

brisk brook
#

lol

vocal wolf
#

the announcement, that is

green oriole
#

We need to solve that

vocal wolf
#

hell we reached 2 pages of PRs on the bot repo

green oriole
#

chop chop

vocal wolf
#

there's only 1 on the second page, but still

fallen patrol
#

if someone wants an extremely easy one to review

#

extremely

dim pelican
#

Time to set up bot by following site#591

dusky shoreBOT
fallen patrol
#

sir-lancebot#878

dusky shoreBOT
fallen patrol
#

ergh this is gonna keep nagging me

#

@molten perch should I just switch that to __name__

fallen patrol
molten perch
#

You mean the extensions part?

fallen patrol
#

the whole thing

molten perch
#

I don't think so. 🙂

fallen patrol
#

@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.

green oriole
#

lol wut

patent pivot
#

lol, probably not a bug if it lets people that need to join in

vale ibex
#

Theres having it be a constant, or possibly getting it at runtime via guild id I guess

vale ibex
#

FWIW, I went with a constant

brisk brook
#

Why not add it to the config file?

vale ibex
#

That's what I meant by constant

#

as in I added it to the constants file, which is populated by the config

brisk brook
#

Ah, right. I thought you meant constant as in all-caps variable in the global scope. I'll take a look later today.

vale ibex
#

hah yea, I wasn't very clear

#

There's no rush anyway, it's on hold atm while we write a modmail plugin

patent pivot
#

not worth adding to config imo

#

it’s basically just copy, we don’t need that to be configurable

vale ibex
#

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

brisk brook
#

It is easier to change a config file than Python file though

patent pivot
#

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

vale ibex
#

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

patent pivot
#

yeah

green oriole
#

I don't see any reason you'd want to change it during testing, so I'd say a constant is fine, agreed

vale ibex
#

I've reverted and force pushed 😄

green oriole
#

In draft until we have a modmail plugin to control pings.
What's the reasoning behind that? Are appeals really that heavy?

vale ibex
#

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

vale ibex
#

sir-lancebot#880 basic Pr to avoid topic spam, such as what happened just not in pygen

dusky shoreBOT
vale ibex
#

@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

sacred fossil
#

Finally back on Linux and unbothered by college

brazen charm
#

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

sacred fossil
#

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

thorny obsidian
brisk brook
#

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

dim pelican
#

nervously looks at my absolute General Sherman of a commit tree

fallen patrol
# dusky shore

That's an interesting solution which does not seem like the proper solution, and feels like it causes more problems than it fixes.

brazen charm
dim pelican
#

I use it occasionally in gen or ot when things start to go a little sideways

brazen charm
#

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

dim pelican
#

Is the spam usage usually coming from one person or multiple people?

sacred fossil
dim pelican
#

range isn't inclusive though by default. But that is definitely a typo for Interger

sacred fossil
#

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]

green oriole
#

!remind 1h30M re-review Chris' PR

stable mountainBOT
#
Yeah okay.

Your reminder will arrive on <t:1632492575:F>!

brazen charm
# dim pelican Is the spam usage usually coming from one person or multiple people?

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

cold island
#

From my experience it helps disrupt the disrupters with something that's on topic, so I personally like it

green oriole
#

Yeah, it is also quite useful to have all the "bruh"s, "xd"s and "lmao"s after unsilencing a channel

static canyon
#

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)

vale ibex
#

yea, that sounds fine, I'd mark it as debug/info though

#

not worth a sentry report

static canyon
#

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

brazen charm
#

I don't think it does, they just implement the same abc

vale ibex
#

if you're worried about inheritance, you coudl use type(author) == User

static canyon
#

I guess type(author) is User would be better though

vale ibex
#

It may not matter, according to what Numerlor says

static canyon
#

Do we still want to pin the message if the user leaves? (In case they rejoin)

vale ibex
#

since they're not strictly inherited

static canyon
#

Yeah, looks like that is true from the source code

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

static canyon
#

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

fallen patrol
#

cc @vale ibex its possible for a member to be a user if they aren't in the cache iirc

static canyon
#

I was just thinking that but not sure

fallen patrol
#

btw, what's the current cache count 👀

#

are we still having that issue with the cache not being full

static canyon
#

I think sending the message will put the user in the member cache so it's fine

vale ibex
#

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

static canyon
#

So I'd expect a NotFound error rather than message.author being a User

vale ibex
#

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

static canyon
#

I'd have to test stuff

vale ibex
#

👌

static canyon
static canyon
#

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

static canyon
#
<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

fervent sage
static canyon
#
@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")```
fervent sage
#

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 KEKW

static canyon
#

Hmm

#

That doesn't really make sense to me

#

"the guild is more expensive to recreate though, so it isn't recreated"
But both message.author.guild.members and message.guild.members changes?

#

So it is getting recreated?

fervent sage
#

thats because theyre the same guild

static canyon
#

Right yeah

fervent sage
#

its not recreated just that _members is updated

static canyon
#

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

fervent sage
#
>>> @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
static canyon
#

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

fervent sage
#

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

static canyon
#

Exactly

fervent sage
#

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)

static canyon
#

I'm not talking about updating a guild at the moment

static canyon
fervent sage
static canyon
#

So my statement is correct?

fervent sage
#

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

static canyon
#

@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)

fervent sage
#

yes

#

sorry it took me so long i'm going a bit slow today

static canyon
#

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?

fervent sage
#

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

static canyon
#

Hmm

#

I might as well ask in the dpy server and see if anyone can tell me

sacred fossil
#

Can I request for my PR to be reviewed?

#

or it's a queue and I'll just have to wait?

dim pelican
#

You can request it, but I would recommend to be patient as there are probably 10 reviewers currently lol

#

Is it sir-lancebot#785?

dusky shoreBOT
sacred fossil
#

yup, been sitting on it for a while, managed to find time to work on it today

static canyon
fervent sage
#

yeah

#

as long as you make the logic safe of getting either object you should be fine

static canyon
#

👍

stable mountainBOT
static canyon
#

@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?

green oriole
# stable mountain

!remind 18h I hate public transports, especially when you learn one minute before the departure that your train won't stop at your station

stable mountainBOT
#
Absolutely!

Your reminder will arrive on <t:1632558225:F>!

vale ibex
brisk brook
sacred fossil
#

got it

slim widget
#

Anyone got a relatively short and self-contained task I could work on?

dim pelican
dusky shoreBOT
clever wraith
dusky shoreBOT
dim pelican
#

Hey Kron

clever wraith
#

Hola brad

sacred fossil
dim pelican
stable mountainBOT
#

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]})",
)```
static canyon
#

Oof, too many PRs for @dusky shore

#

bot#1845, bot#1836, bot#1822, bot#1806 and bot#1798

static canyon
#

bot#1831

sacred fossil
#

that's a lot of stuffs to review

slim widget
#

Looking at sir-lancebot#842 currently.

dusky shoreBOT
static canyon
#

Just little quick-fixes

#

Nothing as in-detail as color command since I don't have enough time :p

steady junco
#

Configuration and documentation for Python Discord's Kubernetes setup!
What are Kubernetes

patent pivot
#

Kubernetes is a container orchestration platform that we use to deploy our applications

steady junco
#

Deployy our applications wdym

patent pivot
#

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

steady junco
#

Ohhh

patent pivot
#

lol

clever wraith
#

Hey @last patio, site#594 has been opened in accordance with the comment you left on sir-lancebot#611

fallen patrol
#

sir-lancebot#878 very easy review if anyone is looking for one 🙂

dusky shoreBOT
fallen patrol
#

wrong reply, thanks

dim pelican
#

Sometimes I feel like my replies to comments on github sound too defensive, anyone else feel that sometimes?

green oriole
#

Your last few comments seem perfectly reasonable, it is normal to defend your implementation choices

dim pelican
#

Thanks Akarys

slim widget
#

I don't seem to be able to reply to comments in a PR, other than "quote reply" 🤔

dim pelican
#

Ahh yeah, if it is outside of a review I think you have to quote reply

slim widget
dim pelican
slim widget
#

Can I add additional comments to a review?

dim pelican
#

For sure! Keep them coming You should be able to

slim widget
#

I really hate Github 😄

dim pelican
#

Gotta start a new review to add comments?

slim widget
sour viper
#

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)```
dim pelican
sour viper
#

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

dim pelican
#

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

sour viper
#

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

dim pelican
#

Should the lists be sorted first?

sour viper
#

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

dim pelican
#

Are you checking the keys or values of the json file in the for loop?

sour viper
#

keys

dim pelican
#

And theater in that screen shot is a value in a list of the key aeehrtt right?

sour viper
#

yes right

dim pelican
#

I'd throw two debug prints in your for loop, I can't tell if the variables are working the way you think

sour viper
#

created 2 dummy files with less data

fervent sage
#

i hate arguing on github

dim pelican
#

this I don't even need to assume lol

sour viper
#

Not sure what im doing wrong

slim widget
brisk brook
cold island
#

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

brisk brook
#

Interesting, do you think non-real time back-and-forth is worse than real-time?

sour viper
dim pelican
brisk brook
#

Why the keys? The keys are the scrambled characters no?

brisk brook
#

Oooh, I see the keys are the sorted characters

green oriole
slim widget
green oriole
#

You can make mistakes when reviewing

#

And it is even easier than when programming I'd say

cold island
slim widget
# green oriole You can make mistakes when reviewing

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.

sour viper
brisk brook
#

You don't even print the count, what is it?

green oriole
#

Hmmmm not necessarily

sour viper
#

its 0

green oriole
#

Sometimes reviews can be just wrong

#

Nto saying it is a bad thing though

vale ibex
#

looks like there's some newline chars in COMMON_WORDS

green oriole
#

I'd rather have a few wrong comments than miss some stuffn

dim pelican
# sour viper

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

sour viper
#

@vale ibex for the win, it was '\n' i guess shouldve known, looking at the print statements

brisk brook
vale ibex
#

I'm gonna guess the newline chars are at the end, and the sort was pulling them to the front

#

based off those prints

sour viper
sour viper
#

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 ?

cold island
brazen charm
#

does mit apply to resources?

fervent sage
#

mit applies to anything in the repo

cold island
sour viper
#

I just realized im not going to be using that file, im using that file to create another file

#

which ill be using

brisk brook
sour viper
#

Yes this jam_cuneiform_this

slim widget
#

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 lemon_sweat

brisk brook
# cold island Both forms have their own problems. Imagine you post a magnum opus and then you ...

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

dim pelican
slim widget
# fervent sage mit applies to anything in the repo

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?

molten perch
stable mountainBOT
#

poetry.lock line 715

postgresql = ["psycopg2 (>=2.7)"]```
brazen charm
#

That just lists the extras for the package, you'd see psycopg2 as its own package if it was installed

molten perch
#

Oh, okay then. Thank you. 😄

vale ibex
#

!remind 9h review site#591

stable mountainBOT
#
Alright.

Your reminder will arrive on <t:1632548230:F>!

dusky shoreBOT
fallen patrol
#

bump sir-lancebot#878

dusky shoreBOT
fallen patrol
#

oh wait.

steady junco
#

These

fervent sage
#

html pages you get served when there's an error

cold island
fallen patrol
#

smh @patent pivot would you please update the easter egg that gives impossible to follow instructions

steady junco
#

Just that

#

So Can I fix a error there

#

But where are the error written there is just a website

stable mountainBOT
sour viper
#

@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

dusky shoreBOT
patent pivot
stable mountainBOT
stable mountainBOT
#

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()```
fallen patrol
#

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()

vale ibex
#

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

fallen patrol
#

ahhhh

#

!pep "8

stable mountainBOT
#
Argument parsing error

Expected closing ".

fallen patrol
#

Well, if it wasn't awaited, it would be in logs now

vale ibex
#

I think that's the point of .close()

#

to close it, since it doesn't need to be awaited

fallen patrol
#

ah... makes sense

brazen charm
#

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

fallen patrol
brazen charm
#

It is fine, but it looks unnecessary of I'm looking at it correctly if it creates a Coro just to close it

clever wraith
#

Hey @fallen patrol , I'll be offline for a bit but I should get to the site docs stupid

fallen patrol
#

hmm?

reef tinsel
#

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?

dusky shoreBOT
vale ibex
#

It is possible that someone will have more than one role

#

In that case, just use the highest tier they have

reef tinsel
#

ok, will include handling then!

vale ibex
#

👌

reef tinsel
#

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)
vale ibex
#

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

reef tinsel
#

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!

vale ibex
#

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
reef tinsel
#

aah yes, forgot about that!

austere hornet
#

Hey @vale ibex , could you please #changelog the new Hangman command?

clever wraith
#

Along with the .gitpod.yml please

vale ibex
#

I'm not home until tomorrow, any admin can change log it, so another might see it before I'm back 😀

static canyon
#

@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

brisk brook
#

Ah, cool

fallen patrol
#

@brisk brook I commented on 860, its actually pretty easy to remove the view when it expires

#

tldr

#

!d discord.ui.View.wait

stable mountainBOT
#

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.
trail pilot
#

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

brisk brook
#

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).

trail pilot
#

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

left flume
#

a button paginator for @dusky shore would be great

fallen patrol
# trail pilot I'm not opposed to the change, I'm just not sure what the purpose of it would be

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.

fallen patrol
left flume
fallen patrol
#

I'm for it.

left flume
#

oh okay

#

or maybe we can add it in the quote command

fallen patrol
#

But I also don't have any pull over whether it's added or not :D

left flume
#

and then on interaction it sends the quoted msg to the users dms and replies with an ephemeral message for confirmation

fallen patrol
#

any ephermal messages would require slash commands or buttons or selects or context menus

#

slash commands and context menus are currently not doable

trail pilot
#

@fallen patrol One question about wait(), where would I exactly place it? Until I want to edit it

#

for discord.ui.View.wait()

fallen patrol
#

one sec

#

somewhere after the message is sent

trail pilot
fallen patrol
#

this would mean saving the view to a variable rather than creating it and directly passing it to the message

#

somewhere in this area

stable mountainBOT
#

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```
fallen patrol
left flume
#

i see

fallen patrol
#

why is there no message

#

lmao

#

brb

left flume
fallen patrol
#

nah, nah, the help command should respond to invalid parameters

left flume
#

ohh

fallen patrol
#

like .help asdfas errors

#

but .help quote doesn't send anything

left flume
#

hmmm

fallen patrol
#

sir-lancebot#882

dusky shoreBOT
fallen patrol
dusky shoreBOT
left flume
#

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

fallen patrol
green oriole
#

@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

green oriole
#

Who knows

#

I am currently heading to his train station, Saint Charles

patent pivot
green oriole
#

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?

patent pivot
#

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

cold island
#

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

patent pivot
#

yeah

trail pilot
#

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?

dim pelican
green oriole
slim widget
#

@dim pelican, have you read my comment on the structure of the color cog?

timid sentinel
#

How would the web idea work, and why would it not be suitable for migrations/updates?

dim pelican
#

Pretty much the main command would have it's own parser to determine the mode?

slim widget
slim widget
dim pelican
#

Time to learn the dark arts

slim widget
molten perch
#

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. 😄

fallen patrol
#

Smart config and bootstrapping. I still have no idea which project is which

patent pivot
#

lol

#

smartconfig is a config system/tool, bootstrapping would be our existing config system auto-generated by an OAuth2 app

green oriole
fervent sage
#

are bots able to transfer ownership?

green oriole
#

Yes

thorny obsidian
#

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?

green oriole
#

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

thorny obsidian
#

So you're saying giving the user the config.yml file is the difficult part?

fervent sage
#

cant you just provide a link to, say, an s3 object for that

green oriole
#

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

thorny obsidian
#

I feel like I'm not on the same page. What is the target configuration here?

green oriole
#

The list of channels, emojis, webhooks and stuff that needs to be created

#

What we want the bootstrapping system to output

thorny obsidian
#

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

patent pivot
#

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

green oriole
#

So we lock ourselves into keeping config-default.yml? Hello no, please

thorny obsidian
thorny obsidian
green oriole
#

Yes, and it is pain

patent pivot
patent pivot
thorny obsidian
green oriole
#

We agreed in the core devs meeting to yeet config default because it was stupid, why are you suddenly walking back on that one?

patent pivot
#

we can probably cut down the length of config-default, we have probably been a bit generous with what should actually be configurable

timid sentinel
#

We could split it into server config, and feature config, although most feature config could probably just be constants defined in the respective file

green oriole
#

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.

patent pivot
#

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.

green oriole
#

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?

patent pivot
#

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.

green oriole
#

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.

thorny obsidian
#

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.

patent pivot
#

I don't really think there are huge differences in difficulty tbqh, it's some templating and API calls

green oriole
#

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

patent pivot
#

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.

green oriole
#

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

patent pivot
#

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

green oriole
#

Whatever Joe, whatever

#

I don't think we are listening to each other, let's just stop here

patent pivot
#

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.

fallen patrol
#

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

fallen patrol
#

When I say it's probably possible, I mean it 100% is possible. I've done everything I just listed for a different project.

green oriole
#

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

green oriole
#

config.yaml should only contain the values you want to override

#

Not everything

gritty wind
#

There's no real reason for us to have yaml in the first place tbh

fallen patrol
#

Yeah, use toml /s

gritty wind
#

Could have people put everything in one place in the env file

fallen patrol
#

The only small problem with env is .

gritty wind
#

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

fallen patrol
#

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

patent pivot
#

with bootstrapping in theory channels, roles and emotes are accounted for

fallen patrol
#

Like, even if the user doesn't have to configure them themselves, now there's a 20 var env

patent pivot
#

the bootstrapper fills in the ID values for each

fallen patrol
#

... And where does it fill them in?

patent pivot
#

well, with the current system it generates a config.yaml file

fallen patrol
#

And with what scale suggested, it'd fill them in with the env vars

patent pivot
#

down the line it would do whatever is necessary (or the solution we have down the line does that for us)

#

yeah

gritty wind
fallen patrol
#

So now there's 20 env vars, is there not?

gritty wind
#

Is that a problem?

#

My perfect system is just:

fallen patrol
gritty wind
#

Let me copy it real quick

#

Really?

patent pivot
#

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

green oriole
fallen patrol
#

As long as each env file didn't load everything ig

gritty wind
#

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"

gritty wind
green oriole
#

Like CHANNEL_DUCK_POND is the same idea as

channels:
  duck_pond: ... ```
fallen patrol
#

*with an S

patent pivot
#

config DSL when 👽

green oriole
#

Yes, obviously

fallen patrol
#

DSL?

green oriole
patent pivot
fallen patrol
#

Which is...?

gritty wind
#

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

fallen patrol
#

Your concepts are lost on me.

one central location of truth

multiple .env files

gritty wind
#

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

fallen patrol
#

And the config default file couldn't be removed as truth by being auto-generated why?

gritty wind
#

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

fallen patrol
#

Seems kind of repetitive idk

gritty wind
#

Which part is repetitive?

fallen patrol
#

Like, nearly single variable now needs os.getenv

#

I mean, it works, but, there seems like a better way

gritty wind
#

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

fallen patrol
#

Eh, the only ways I think of are more work than that lol

green oriole
gritty wind
#

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

green oriole
#

I am really not a fan of spamming os.getenv on hundreds of lines of configuration, that doesn't seem very DRY

gritty wind
#

We can actually have pydantic do like 90% of the work for us

#

Hmm I can write a draft of my idea right now

vocal prairie
green oriole
#

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..

vocal prairie
#

Anddd, I forgot to scroll down

green oriole
gritty wind
green oriole
#

Oh, so like you want to use a python file for inputting overrides?

gritty wind
#

Nah, "overrides" would be in your env, but like you really don't need to override much of anything

fallen patrol
#

i personally don't like pydantic too much since its too high level lol

green oriole
#

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

fallen patrol
#

would much rather write a configuration system and handle all of the loading myself

gritty wind
#

Right... well you could go contribute to pydantic

fallen patrol
#

but that's just me, if pydantic is easiest to make a maintainable configuration system go for it

fallen patrol
gritty wind
#

I personally disagree with your philosophy, as it sounds like reinventing the wheel, but I think we agree to disagree

fallen patrol
#

ye

vocal prairie
#

I agree with Scale, pydantic is really easy and nice to use

fallen patrol
#

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

green oriole
#

But isn't pydantic supposed to be a database thing lol

fallen patrol
#

nah

gritty wind
#

It's mostly just more feature rich dataclasses

fallen patrol
#

it has integrated env var support

#

with built in validation

vocal prairie
#

It can be used as that, but it also has something called BaseSettings specifically for settings/config systems

fallen patrol
#

^

green oriole
#

We could look into that for the bot

vocal prairie
fallen patrol
#

I just don't like pydantic because of its built in validation

gritty wind
#

It doesn't do validation :thonk:

#

Just conversion

#

Validation is all manual

brisk brook
#

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

gritty wind
#

I think we don't really want to validate

#

We just want to make the setup process easier

fallen patrol
vocal prairie
gritty wind
#

Which means we make the server initially, and if someone changes it and breaks, well, they'll know what broke

gritty wind
fallen patrol
#

It doesn't do validation thonk

vocal prairie
#

Isn't validation (in pydantic) just checking if the type matches, or does it go beyond that?

fallen patrol
#

its conversion is also validation

gritty wind
#

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

brisk brook
vocal wolf
vocal prairie
gritty wind
#

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

vocal wolf
gritty wind
#

Very cool, time to drop the tests dir lol

vocal wolf
#

lmao

#

wait both projects are done

#

nais

gritty wind
#

Are we ready to ship python?

#

v1.0.0

vocal wolf
#

should I close both the projects?

#

I don't seem the need for them to be open

#

alright both of them are closed

#

or is the current title correct?

#

oh wait I see why now

#

you saw nothing

static canyon
vocal wolf
#

yeah lol

#

I asked before actually investigating, I was being a dumb

fallen patrol
#

Hm, could someone pull up some logs for this?

static canyon
# fallen patrol Hm, could someone pull up some logs for this?
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

fallen patrol
#

882 is a dupe then

static canyon
#

mhm

clever wraith
#

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

static canyon
#

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]

static canyon
#

To me it seems more logical to only pass what's actually used

gritty wind
#

@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
green oriole
#

Interesting

#

That's almost identical to the API I imagined for smartconfig

gritty wind
#

😅

clever wraith
#

hi there people, site#594 needs reviews

dusky shoreBOT
gritty wind
#

I actually missed a bit, the env loading needs to be: dotenv.load_dotenv(file, override=True)

green oriole
static canyon
#

At least to me

#

So I'd prefer the latter

fallen patrol
gritty wind
#

What do you have in mind?

fallen patrol
#

Can use dotenv.dotenv_values to get a dictionary of all of the keys in the provided file or stream

gritty wind
#

I don't follow, what do you do after that

#

I think you missed my earlier snippet of code

gritty wind
fallen patrol
#

Well, then you don't need that loading code at all :P

gritty wind
#

You do, otherwise those files aren't in the environment

fallen patrol
gritty wind
#

I saw that, but it only supports one file

fallen patrol
#
Config:
  env_file = ''
gritty wind
#

You'd need to override the loader

#

Which is so much more work

fallen patrol
#

It's not

#

It really is not lmao

gritty wind
#

Ok, tell me how

fallen patrol
#

I'm on mobile rn

#

!remind 5m this

stable mountainBOT
#
Yep.

Your reminder will arrive on <t:1645906151:F>!

fallen patrol
#

!remind 5M this

stable mountainBOT
#
Sure thing!

Your reminder will arrive on <t:1632687260:F>!

fallen patrol
#

!remind delete 3132

stable mountainBOT
#
I got you.

That reminder has been deleted successfully!

stable mountainBOT
#

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,
    )```
fallen patrol
gritty wind
#

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

fallen patrol
# gritty wind How do you use this to load multiple env files

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

fallen patrol
#

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.

gritty wind
#

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

fallen patrol
#

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

gritty wind
#

So where does the second env file go, and how is this a better solution than loading the env stuff

fallen patrol
#

wdym where does the second env file go

#

why are you trying to load two env sources into a single class?

gritty wind
#

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)

fallen patrol
#
import dotenv

env_vars = dict()
for path in ENV_FILE_PATHS:
  env_vars.update(dotenv.dotenv_values(path)
gritty wind
#

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

fallen patrol
#

@dry folio why close seasonalbot#856?

dusky shoreBOT
gritty wind
#

The history of the PR got a bit muddled, so a new one will be created with a different approach

fallen patrol
#

ah

dry folio
#

anyone know the everyone role id? need to add it to Roles in constants.py

austere hornet
#

But I could be wrong

patent pivot
#

guild ID iirc

dry folio
dry folio
patent pivot
#

think so, one sec

austere hornet
dry folio
#

i can just check :D

patent pivot
#

did you put @ or @&

dry folio
#

what's the difference?

patent pivot
#

@ is for users only

gritty wind
#

267624335836053506

patent pivot
#

@& is for roles

gritty wind
#

Not gonna test it exactly cuz ya know

dry folio
dry folio
#

didn't send it

gritty wind
#

haha yeah

dry folio
fallen patrol
fallen patrol
#

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

stable mountainBOT
#

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.
fallen patrol
#

okay yeah its a property

dry folio
#

sir-lancebot#885 is a very quick fix that can be reviewed now :D

dusky shoreBOT
fallen patrol
#

lmao

#

of a simple change, and I have a requested change 👀

dry folio
fallen patrol
#

lint failed cri

dry folio
#

okay that's just embarassing

fallen patrol
#

defintely should be squash merged 😛

dry folio
#

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

fallen patrol
#

nice

#

it's merged

dry folio
#

lesgo

#

@hoary haven the moment you've been waiting for

hoary haven
#

oo

#

ty clappyclap

dry folio
#

.bm 891798110597177414

#

:D

hoary haven
#

@dry folio it was actually so annoying that I couldn't bookmark previously within help channels 😭 so tyvm!!

hoary haven
#

@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?

dusky shoreBOT
static canyon
hoary haven
#

okie 👍🏻

brisk brook
#

Or you can open one yourself, we appreciate contributions from everyone 💙

clever wraith
#

Please review site#594! It's a small change that can be easily reviewed

dusky shoreBOT
steady junco
#

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?

green oriole
#

We have a form to suggest topics, I don't know if it is still active
CC @vocal wolf

vocal wolf
#

it is still active, I go through it every once in a while

#

.topic

dusky shoreBOT
#
**What is the best gift you've been given?**

Suggest more topics here!

vocal wolf
#

that link in the embed will lead you to where you want to go @steady junco

green oriole
#

Oh, the link is there

static canyon
#

@clever wraith if you still want to work on sir-lancebot#861 let me know and I'll assign you

static canyon
#

If not I'll probably work on it soon™️

austere hornet
#

@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.

vale ibex
#

what OS are you viewing it on?

austere hornet
#

Android

#

I get this when I tap the link:

austere hornet
vale ibex
#

looks like android doesn't like the angle brackets for some reason

#

You'd think it would be consistent

austere hornet
#

Alright, I'll check on computer later

vale ibex
#

I've removed them now anyway

fervent sage
vale ibex
#

If it's stopping people on mobile from clicking the link, it's not worth the supression

fervent sage
#

you know there's a remove embeds button right?

vale ibex
#

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

fervent sage
#

i think so

#

since its a message property

vale ibex
#

worth trying IG

fervent sage
#

hang on @vale ibex

#

wait un hang on

vale ibex
#

lol

fervent sage
#

i was gonna test it

#

but i wouldnt get the first message anyway if i subscribed now

#

so it wouldnt matter

vale ibex
#

Just tested, it does work

austere hornet
vale ibex
#

lol, now that's definitely a Discord on android problem

austere hornet
#

Hmm

vale ibex
#

probably some conflict with markdown

austere hornet
vale ibex
#

That's probably the root cause of why angle brackets didn't work too

brazen charm
#

Try URL encoding the parentheses?

vale ibex
#

How does that look?

austere hornet
vale ibex
#

cool

#

I'll keep that in mind

austere hornet
static canyon
#

It doesn't like wikipedia pages (or any other url) with (), and causes a 404

vale ibex
#

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.

stable mountainBOT
vale ibex
#

What does that look like on mobile?

austere hornet
#

Nope

vale ibex
#

lol yup, that's the issue

austere hornet
#

🙁 🙁 🙁

#

sigh

#

Btw @vale ibex you left reviews on Hangman but I don't think you added yourself in #changelog

vale ibex
#

I reviewed most of the ones there lol

#

Didn't feel like putting my own name down

austere hornet
austere hornet
vale ibex
#

yea

austere hornet
#

Ok

vale ibex
#

I think I have sometimes in the past

steady junco
#

Can I get the Contributor role

#

For getting updates about dev announcements

static canyon
steady junco