#dev-contrib
1 messages Β· Page 130 of 1
Yea, the way to do it is to make a branch, do some changes, then go back to main and branch from there again
rather than branching from your branch
A new branch is basically a copy of your existing branch where you can add stuff like one branch can be for dev and the other can be for prod
I have a fork of the repo, and my main branch has a few changes like more things in the .gitignore, .gitmessage etc. I want to keep those in my main branch of the fork, but when I make a new branch to work on an issue / PR it pulls from my forked main. I've learned I have to force pull / over write the new branch from the upstream main once I create it
aaah. Hmmmm, for that, if I want to start a branch at a later commit I usually use a GUI since it lets me select a commit and do a "start branch from here" option
Chris might know something better
Here is the issue I ran into: creating a branch from my main: https://github.com/python-discord/sir-lancebot/pull/832
And then properly setting it up: https://github.com/python-discord/sir-lancebot/pull/833
You'd want to checkout upstream/main and make a branch
git checkout upstream/main
git checkout -b $name
Ahh instead of making a branch on my fork
I don't think I can make a new branch on the upstream though
Basically the branch you have checked out will be the forking point of your branch, if you following the tree analogy
It won't create anything on the upstream, you can push to your fork after
Checking out upstream/main means "go to the commit that the branch main on the upstream points to"
Gotcha, it just uses the upstream main as it's base "reference". Then the new branch inherits everything from there, and when I link a PR I point it to that branch of the upstream / origin?
Yeah, you will make a PR from the newly created branch
I guess the only thing I'm not following is will that new branch be on my fork (brad90four/sir-lancebot) or the upstream (python-discord/sir-lancebot)
When you create a new branch locally, it doesn't have any knowledge of which repo it is pointing to
When you first push, you link it to the remote branch
You should have heard a loud "click" just then
git push -u origin $name will link it to the branch named $name on the origin remote
Haha, nice
Damn, just when I thought I sorta knew my way around git
you never know your way around git
you can be a world expert in git and still not know
Haha, git is a complex topic. Not even Linus knows his way around it.
git fetch
git checkout upstream/main
git checkout -b <new_branch>
... # code
git add <changes>
git commit
git push -u origin <new_branch>
For my future reference, gonna bm this
I would recommend adding a git fetch at the top
So you know upstream/main is up to date
Thank you, gotta keep practicing those git muscles
In the meantime, if anyone is interested:
sir-lancebot#833
sir-lancebot#834
time for me to practise my lancebot setup muscles
see how many PRs i can thoroughly review in a day 
lol, nice
is that a force push I hear in the distance
hehehe
target: 17
jk
i have so many open issues and pr's, i cant keep track of what im doing :(
I find github notifications are good
they are too many of em :(
Since you can also see
Too good, I don't like the constant emails on things I commented on
OOooo
im guessing you can unsubscribe ?
but that would disable all mails
heh

I do, for all the ones Ive commented on. But it does it by default as far as I can tell
ah yes, the glory
I try to keep on top of my notifications lol
where do i find this-
Click the bell icon in the top right
:D
how did i not know that till now-
:sus:
isnt this assigned
aaaaa
likely because you don't have a notification from that
Does it appear when you click assigned on the left?
Not home rn 
ahh, I'd do it but then I wouldn't be counted as a reviewer lol
https://github.com/issues/assigned might be what you're looking for then
ty <3
If you keep me as the commit author and you as the co-author it should be fine
fun fact: i found a bug in the linux kernel so i wanted to open a pr fixing it, but i went through the pr and the styling process and i quickly gave up
π
π¦
since I pushed it it counts me as committing it I guess?
Β―_(γ)_/Β―
Yea, I know that worked
Huh
I'm disqualified from policy bot though
Hey @patent pivot, can you approve https://github.com/python-discord/sir-lancebot/pull/835 for Chris please?
Since the Discord.py repository has been archived, we can switch to the latest commit of 2.0a0, knowing no breaking change will occur (still pinned to the commit just in case).
This commit also sol...
He is being locked by policy bot and we need a devops to approve
I like that commit message
Approved π½

!otn a my brother from another mother ChrisJL
:ok_hand: Added my-brother-from-another-mother-π’hrisπ©π« to the names list.
lol
Thank you sir Joe
anytime
Oh actually it didn't devops approval but that works too lol
time to rewrite all the games with buttons
lol
Do we really have to, though? Threadevere most probably won't be around for too long anymore, and doesn't have any user facing command
oh
wow, i thought vsc was screwed when i saw help.py being a part of /Library/Framwork/Python3.9
π
why not?
copy pasta is hard :(
its really not π
we're planning to upgrade the bot to 2.0 at some point
when that happens @brisk belfry's cogs will be moved there
ah
most of the imports are referring to the files in the local bot repo so yeah
We just bumped lance to 2.0
but sir-threadevere isnt opening threads π
π₯³
since you found all of the bugs that I haven't yet, probably
atleast for me
there weren't too many
just check the PR π
it should make a thread in the nomination channel, correct ?
sir-lancebot#835
like for every message ?
when a nomination vote is posted yea
you got all of the timestamp issues too, right?
not all messages, no
Didn't touch anything regrading timestamps
wut
Don't think we relied on them being naive/aware
welp you probably have a broken bug in there somewhere
in lance at least
Only when a nomination vote is posted
more context?
all dates are aware now
.
oh okay, whats the command for that hehe
but I don't think as Chris says we rely on that
so I don't think where are a tonne of bugs
it's in @stable mountain, not threadbot
bot/exts/halloween/hacktober-issue-finder.py lines 55 to 58
if (ctx.message.created_at - self.cache_timer_beginner).seconds <= 60:
log.debug("using cache")
return self.cache_beginner
elif (ctx.message.created_at - self.cache_timer_normal).seconds <= 60:```
im using the py bot in my server too, nomination doesnt work
hi, I've read that d.py as a library is going to stop being developed? Would that affect this server's bots?
no
you should be able to type this and it'll work ```
@vale ibex for Helper!
Nomintated by:
react :+1: for approval, or :-1: for disapproval
bot/exts/halloween/hacktober-issue-finder.py line 31
self.cache_timer_normal = datetime.datetime(1, 1, 1)```
at least, not in the near future
We've upgraded to v2 which is stable for now
sir-lancebot#835
weird, i did that
but the api is gonna be changing, and the api wrapper is not keeping up with it, thus losing its 100% coverage
oh
it will affect the bots at some point, but not in a everything suddenly breaks way
^
bruv yeet it, im making another server and trying
:sadge:
anw, i'll do the pr of the sir-lancebot one and go to sleep
gn people :D
Phew
hm... if you're switching to dpy 2 you maybe want to update the paginator to use interactions π
paginator is the obvious one
but we'll do that separate from the actual upgrade on Python
Yeah, let's minimize the breakage if it does break :D
We aren't time stressed, we can do it step by step
So are buttons just part of the message, and you can change which buttons appear by just editing it?
Yup
You can attach them as part of the message send api request, so no extra call
And then clicking a button triggers a callback
yeah
I just merged a pr to my bot to add an interaction paginator, if anyone wants inspiration π
This is a view with two buttons
huh
if self.lock.locked():
await interaction.response.send_message(
":x: Processing another user's button press, try again later.",
ephemeral=True,
)
``` could you explain?
I didn't use a lock on mine π
Anyone can click buttons, a lock means that it only processes one at a time
The use case for this view is to send an email to a user, so I want to avoid 2 people clicking a button triggering 2 emails
ah, lock is probably not necessary for a paginator, then?
nope
π
since i just merged the pr after a successful review
like
hell yeah it works great
... There is only one page?
I guess it does work then
How did you test it worked with the buttons ?
So bulky though
its better when you aren't paginating 5 characters
Yeah, I guess it is more bulky than reactions
well yeah
I guess that's more mobile friendly
I clicked on the image π€¦
Lmao
If you'd like to test it I can invite you to the server
@cold island seems like your apology wasn't accepted
I commented on your review
I understand what it does, but the link doesn't say anything about the last argument being optional being bad
Oh, true
Thanks @brisk brook, your explanation happened to solve something I was just doing π π
Ah 
the last person to get it became a helper a week later lol
wait until it gets reviewed, I guess
By Stelercus?
@trim cradle ready for re-review.
yay
@vocal wolf I'm not authorized to merge the pull request and I'm really upset about it.
lmfao
have you tried turning it off and on again?
no
tis a shame

lmao
@timid sentinel this is what I get for trying to push commits away from my clone set up
don't say that! Microsoft might unintentionally reboot azure!

(windows and linux github actions all run on azure)
No worries no worries.
did something happen to https://www.notion.so/pythondiscord/Squashing-a-Pull-Request-191e8efa2fbb4d72840fd17ca37cf7fa ?
it now doesn't show all of the info it used to
@vale ibex you initially publicized this ^
What do you think it missing?
look at my screenshot
That screenshot looks like it looks now, just with code blocks removed
like this:
<picture should be here>
well, they aren't showing up for me π€
even changed browsers
I see two photos in the guide?

whatevs
@vale ibex So I did some thinking about the Mastermind issue and decided that I would try something else. So I thought of a different idea and created a new issue for it. If you are available, could you please take a look at sir-lancebot#836? Would much appreciate it. Tysm!
Btw I hope that this is not already on Sir Lancebot - π¬
@vale ibex gitkraken is so good for merge conflicts holy crap
I've never had such an easy time fixing them up for a squash
I know what I'm going to checkout next
I'm working on bot#1787 and have come across an issue. My API request is returning a non-expanded version of users, where I need the expanded version (examples below). How can I make it return expanded users?
Infraction search (expanded):py [{'id': 1, 'inserted_at': '2021-08-31T20:37:12.255534Z', 'expires_at': None, 'active': False, 'user': {'id': 442244135840382978, 'name': 'TizzySaurus', 'discriminator': 9615, 'roles': [476190141161930753, 476190408871772171, 476190357927886848, 637792718852063282], 'in_guild': True}, 'actor': {'id': 442244135840382978, 'name': 'TizzySaurus', 'discriminator': 9615, 'roles': [476190141161930753, 476190408871772171, 476190357927886848, 637792718852063282], 'in_guild': True}, 'type': 'note', 'reason': 'testing', 'hidden': True}]Infraction (non-expanded):py [{'id': 1, 'inserted_at': '2021-08-31T20:37:12.255534Z', 'expires_at': None, 'active': False, 'user': 442244135840382978, 'actor': 442244135840382978, 'type': 'note', 'reason': 'testing', 'hidden': True}]
@static canyon Found it
You can try
yep, true
Btw @brisk brook did you happen to test it before approving?
Which one?
Infraction by ID
No, if you need me to I'll do that tomorrow
bot_1 | 2021-08-31 21:12:14 | bot.exts.backend.error_handler | DEBUG | API responded with 404 for command infraction```I'll try `/infractions/{infr_id}/expanded` and see what happens
I mean more in the sense of, you should probably test before approving
Ah, right
Appending to the end of the route would mean /expanded after anything you already have :P
Question: If I want to assign myself an issue, but I won't have time to implement the new feature for a long time, is it ok to still assign myself the issue or should I wait until I have time and then assign myself?
Preferably the latter
Alr, thanks
Think about it this way: issues are opened for things we want to see implemented. If you're assigning yourself without intending to work on it in the near future then you're effectively stalling the feature/bug fix
Is sir-lancebot#834 in the right place? Or should this be in meta or .github?
Yeah, that makes all the sense. Thanks
i was sleeping-
@desert vessel You don't need to close the issue, what I said just means that it should probably wait a little bit. It's a great idea.
oh,
as xithrus mentioned, wasnt this solved in another pr ?
@vocal prairie here ^
No, that just adds the tag group functionality, which could be used to implement this feature.
i just noticed seb doesn't have the project leads role, isn't he the project lead for API?
sir-lancebot#618 Rebasing upstream main into my branch, I have messed up the whole commit history π What should I do now? Let it stay? And rebased it to get the new cs/python quiz questions and the rapidfuzz change
first off, don't do anything else locally. There are ways to fix it from where you are
The previous commits still exist in your local copy. but any commands you run to fix it can fuck it up and get them gone
@short snow^
umm probably, also what's the correct way to rebase to not let such things happen in future
imo git rebase -i
which is an interactive rebase
Also git reflog to check where the HEAD was at when the changes were made, then git reset (or revert?) HEAD~<number to reset to>
I usually do resets by hash and not by relative to head since it's harder to mess up
.bm doesn't seem to be working
.bm 882575523195281408

Ah, permissions_in has been removed in d.py 2.0
Go forth and review sir-lancebot#838
Well if there is one thing I'm good at, its messing up some git π
I'll have to give the git rebase -i a try, and probably start using the commit hash for the git reset
Due to my half-yearly exams, I will be going on a 1 and a half month break after the end of this week. So if anyone has got some time, it would great to get my PRs complete π Thanks!
async def cog_command_error(self, ctx: Context, error: commands.CommandError) -> None:
"""Handles errors for commands within this cog."""
...
elif isinstance(error, commands.ConversionError):
await ctx.send(f":x: A corresponding infraction for {XXXX} could not be found.")
...```does anyone know how I can get the value that failed the conversion from the error?
You should be able to str() the error to get what was passed into the error when it was raised
what actually gets passed into the raise error depends on the converter
It's the Infraction converter so what gets returned is just the 404 error
Something like Status: 404 Response: {'detail': 'Not found.'}
look like it's raising a BadArguement inside the converter
you could create the error, add a custom attr and then raise it I guess
That's what I'm doing atm
This is what I'm seeing atm ```py
class Infraction(Converter):
"""
Attempts to convert a given infraction ID into an infraction.
Alternatively, `l`, `last`, or `recent` can be passed in order to
obtain the most recent infraction by the actor.
"""
async def convert(self, ctx: Context, arg: str) -> t.Optional[dict]:
"""Attempts to convert `arg` into an infraction `dict`."""
if arg in ("l", "last", "recent"):
params = {
"actor__id": ctx.author.id,
"ordering": "-inserted_at"
}
infractions = await ctx.bot.api_client.get("bot/infractions", params=params)
if not infractions:
raise BadArgument(
"Couldn't find most recent infraction; you have never given an infraction."
)
else:
return infractions[0]
else:
return await ctx.bot.api_client.get(f"bot/infractions/{arg}")
is this the converter you're talking about?
So I'm guessing the 404 is from that final line
so you could add some logic there to raise if it returns a 404 there
api_client.get handles a 404 locally and raises a ResponseCodeError
I'll show what I'm doing in a second
class Infraction(...):
async def convert(...):
...
else:
try:
return await ctx.bot.api_client.get(f"bot/infractions/{arg}/expanded")
except ResponseCodeError as e:
if e.status == 404:
raise BadArgument(f"Failed to convert '{arg}' to an infraction.", arg)
raise e
``````py
async def cog_command_error(...):
....
elif isinstance(error, commands.BadArgument):
await ctx.send(f":x: Could not find a corresponding infraction for `{error.args[1]}`.")
...``` @vale ibex this is what I'm doing now
So i catch the error in the converter and raise a different error with arg, which is caught in cog_command_error
Which results in this behaviour
What's the desired behaviour?
I'm happy with what I've got now
Ah cool
Just not sure if there's a tidier way that you/anyone can think of
to avoid error.args[1] I wonder if you can do ```py
bad_arg_error = BadArgument(f"Failed to convert '{arg}' to an infraction.")
bad_arg_error.infr_search = arg
raise bad_arg_error
...
f":x: Could not find a corresponding infraction for {error.infr_search}."
Hmm
not saying one is better than the other
It gives a linting error in the handler saying BadArgument has no attribute 'infr_search'
hmmm, guess you can't do that then
Although I think the actual test lint passes (poetry run task lint)
Yeah, it does
So I've got the option
Although I do personally prefer just using .args[1]
Yeah, I'll keep it .args[1]
π
can someone help me with this
i have pylance installed
but there are no suggestions
you could create a subclass of the exception to properly set the attribute
I've tweaked things around a bit but am happy now so going to commit and push π
Wait, doesn't the api wrapper deal with errors in maybe_raise_for_status already
So it should be raising ResponseCodeError for 404 already afaik
It'll go to the generic "According to the API, your request is malformed." message for api errors
(or whatever is appropriate for the error code)
Not sure how helpful that is
True
The reason I mention it is since ResponseCodeError already has custom attrs
so you could add another one for the endpoint url and then get it from there
I've already done this now 
My head hurts too much to change it now lol
Just gonna push this because it works and I've spent way too many hours on this already
Sure
bot#1804 is finally up
I did not expect that to take almost 2 hours lol
Is it more common to ping people in GitHub or here to request a re-review?
re-request on github
trivia_night π esoteric_challenges π
are these hints to the next events @thorny obsidian
haha yup. Those are future events. Still in the planning stages though. I'm trying to scope out the functionality for it and that lead me to... well this issue
Oh π
@fervent sage sir-lancebot#833 is ready for you, there have been some changes since my last requested review and now
Created: <t:1483877013:R>
Voice region: europe
Features: DISCOVERABLE, ANIMATED_ICON, BANNER, ROLE_ICONS, INVITE_SPLASH, PREVIEW_ENABLED, NEWS, VIP_REGIONS, PARTNERED, VANITY_URL, PRIVATE_THREADS, MEMBER_VERIFICATION_GATE_ENABLED, RELAY_ENABLED, COMMUNITY, NEW_THREAD_PERMISSIONS, THREADS_ENABLED, SEVEN_DAY_THREAD_ARCHIVE, THREE_DAY_THREAD_ARCHIVE, WELCOME_SCREEN_ENABLED
Roles: 90
Member status:
53,398
194,213
Helpers: 124
Moderation Team: 31
Admins: 14
Owners: 3
Contributors: 40
Leads: 14
Category: 32
News: 9
Staff: 65
Stage_Voice: 1
Text: 125
Voice: 9
Question - would a .project command in sir lancebot be useful?
I know we already have !projects, but this is an assumption that most people won't really take their time to check out the webpage and actually find a project they link
The .project command I'm thinkinig of would just get a single idea from a YAML with different categories, like 'beginner', 'intermediate', and 'advanced'
It can't
It uses allowed mentions and I just checked now with a few roles to make sure
A potential downside as someone mentioned earlier would be that this would spawn questions like 'how do I know if I'm advanced?', etc
I'm wondering what your all's thoughts are because I think it's probably better to talk here before making an issue for something that may not even be needed
We turned down previous suggestion to maintain our own list of projects
So I don't think this is much different
There are great resources out there, Ned's list is one of them
If you had a way to pull from an existing list (without burdening the host), that would be something to consider
so using bs4 I'm guessing, like how the python bot uses bs4 for the Python documentation module?
If whatever that is has a public API then better. And with caching so it's only fetched once while the bot is up.
I don't know how good this is, but if it's interesting to you you can open an issue so that it can be discussed more thoroughly, preferably with the website you'd like to fetch the projects from.
Traceback (most recent call last):
File "/home/steele/.cache/pypoetry/virtualenvs/site-AnmfhEHv-py3.9/lib/python3.9/site-packages/environ/environ.py", line 273, in get_value
value = self.ENVIRON[var]
File "/usr/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from None
KeyError: 'SECRET_KEY'
Tell me the secret
just need to set a dummy secret key env var
SECRET_KEY=joeiscool
DATABASE_URL=whattheresmore
METRICITY_DB_URL=youliedtomejoe
true i lied π
we'll just hardcode the secret key and operate pythondiscord.com on a trust basis from hereon
Anyway a bunch of tests failed. I suggest that you force approve my PR and then we'll fix it in prod.
@reef tinsel
This would be the best place to ask questions/get feedback on designs π
π
ref bot#1765 for others out of the loop
Does the bot have any slash commands? (In other words, do I need to add application.commands for inviting to my server?
Ok!
Having had a look at the patreon page, I presume the 3 tiers you mention correspond to the ones that gives the cosmetic role colour?
I'd make a new one
Ok
I think putting it in the info folder makes the most sense
I guess I should add some config in config.yml-guilds-roles so that it is easy to set this up for testing in development guilds?
Yea, add the role ids in the issue into the config-default.yml
then it can be overridden to your test server IDs in the config.yml file
π
When I run docker-compose up, I get some sort of file not found error:
What might be the problem?
Traceback (most recent call last):
File "docker\api\client.py", line 214, in _retrieve_server_version
File "docker\api\daemon.py", line 181, in version
File "docker\utils\decorators.py", line 46, in inner
File "docker\api\client.py", line 237, in _get
File "requests\sessions.py", line 543, in get
File "requests\sessions.py", line 530, in request
File "requests\sessions.py", line 643, in send
File "requests\adapters.py", line 439, in send
File "urllib3\connectionpool.py", line 670, in urlopen
File "urllib3\connectionpool.py", line 392, in _make_request
File "http\client.py", line 1255, in request
File "http\client.py", line 1301, in _send_request
File "http\client.py", line 1250, in endheaders
File "http\client.py", line 1010, in _send_output
File "http\client.py", line 950, in send
File "docker\transport\npipeconn.py", line 32, in connect
File "docker\transport\npipesocket.py", line 23, in wrapped
File "docker\transport\npipesocket.py", line 72, in connect
File "docker\transport\npipesocket.py", line 52, in connect
pywintypes.error: (2, 'CreateFile', 'The system cannot find the file specified.')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "docker-compose", line 3, in <module>
File "compose\cli\main.py", line 81, in main
File "compose\cli\main.py", line 200, in perform_command
File "compose\cli\command.py", line 60, in project_from_options
File "compose\cli\command.py", line 152, in get_project
File "compose\cli\docker_client.py", line 41, in get_client
File "compose\cli\docker_client.py", line 170, in docker_client
File "docker\api\client.py", line 197, in __init__
File "docker\api\client.py", line 221, in _retrieve_server_version
docker.errors.DockerException: Error while fetching server API version: (2, 'CreateFile', 'The system cannot find the file specified.')
[15916] Failed to execute script docker-compose
docker environment is running
I don't have any experience with docker, so I don't know what you mean?
"docker" isn't running on your system and docker-compsoe is trying to interact with it basically
are you using docker desktop?
i installed the docker on this page https://docs.docker.com/desktop/windows/install/ earlier this morning
make sure docker desktop is running
so i presume yes to our question
aah, it isn't open, I guess that might be why π
you would see a docker icon on the taskbar on the right hand corner, like ‡οΈ
yea, it doesn't need to be fully open, as long as it's started and the icon in on your taskbar, it's fine
docker is telling me something about WSL, do I need WSL, or can I use docker without this?
Yea, you'll need to have wsl unless you have windows pro and can use hyper-v
hyper-v is slower anyway, so you likely want wsl
ok
the link you posted above has info on how to setup the wsl2 backend
Hyper-V is also windows pro edition only
offtopic, but why does it need wsl2 backend or hyper-v?
Because it needs to run on a linux system at some point.
Different arch for windows
It needs a running Linux kernel, yeah
Actually the getting started guide explains that in the first paragraph https://docs.docker.com/desktop/windows/wsl/
Containers are just an abstraction made around various kernel isolation systems
All of your containers are in fact running on the host kernel, just in different groups
docker desktop is just a glorified VM manager 
That's the main difference with regular VMs
once i've installed WSL, will I also need to install a version of linux, or will docker manage that for me?
You need to install any version of WSL2 and you are good to go
Just WSL, though you may find other things helpful for other projects
for docker, just wsl though
ok, so no need to install a linux
no
WSL is Linux
"Windows subsystem for linux"
im confused
I know, which is why I said no π€‘
because i on the wsl page it says something about installing a linux
WSL is linux like Akarys mentioned, you just need to install it
Installing WSL goes in two step, enabling it then installing a specific distro from the store
That's an update fie you have to install
WSL is a backend for linux, if you want access to a linux environment, then you need to install a linux distro too. But since you just want it for docker, no need to install a distro
You don't need step 2 for docker
Source: I just set up a new PC
Oh that's interesting
I guess it boots up it's own WSL distro, which makes more sense when you think about it
yup yup
It does yeah
C:\Users\hassa>wsl -l --all
Windows Subsystem for Linux Distributions:
docker-desktop (Default)
Ubuntu
docker-desktop-data
Ubuntu is ubuntu 20 from the store
When you are all testing changes, do you have to stop and reload docker? That is what I've been doing but didn't know if there was a different way
yea, or reload the cog
to make it faster you can do docker-compose up bot
or sir-lancebot if you're working on that
that will mean when you ctrl+c to stop it, the other things still run in the background
so starting it back up is faster
@vocal wolf Uhhh just to inform you as you are the triage lead, from tomorrow I am going on a break due to my half-yearly exams for a month (or a bit more). So in case some of PR gets on high priority, any1 can takeover it if I don't respond.
Should I add the roles like this:
roles:
patreon_tier_1
patreon_tier_2
patreon_tier_3
Or:
roles:
patreon:
tier_1
tier_2
tier_3
?
the former
Ok
the bots can also easily be ran without docker for faster restarts, attaching a debugger etc.
π€― Wait what? I thought that docker was what allowed the bots to "live" and respond in discord. All that I know about Docker or running bots comes from the contributing guide and a little extra googling
Docker is there to make the setup easier and reproducible, but for the bots itself it's already fairly easy through poetry
I have redis, postgres and the site running in docker and the bot has a run config in pycharm and is ran directly
Hmmmmm, I use VS Code but you are saying I just run the __main__.py to make the bot live
Run it as a module like rick mentioned
but inside the venv
I only use docker for redis when needed, otherwise run everything normally
Wow I'm over here like "Well I made a small change, let's stop Docker, then run it again to test"
The default docker compose does load all changes from your harddrive
and for changes to cogs, i would reload the cog
Though I personally do what Numerlor does
reloading the extension usually works and is faster than a normal restart too, but there are things that will persist
To summarize for my future self:
Options:
- Run Docker, make change, Stop Docker, Run Again (bad)
docker start -d snekbox redis postgres web poetry run task startfrom the root, if outside the venv
task startif inside the venvpy -m <bot/sir-lancebot>from the root, inside the venv- Set up a run task (automatically run
py -m <bot/sir-lancebot>) - If changing a cog, reload cog from the discord channel with
!c r <cog>or.c r <cog>
You shouldn't run the main file directly as it won't initialize the package
pycharm can be set up to run a module, not sure about vscode
What is the setup for that run task?
probably python -m bot
So like my new edit above?
The python extension for VSCode makes it possible, but I haven't played around with it much
What you have looks right
Sweet, going to bookmark that for myself
Maybe add a note about starting the other tasks too
docker start -d snekbox redis postgres web should do ya
or an override
if you do poetry run you don't need to be inside the venv, poetry run would run it inside the environment for you. Basically poetry run <command> runs that command inside the venv
so you can run task start if you are inside teh venv
no, remove the poetry, just task start (context: they edited the msg)
yep
Time to open an issue on site to add this to the contributing guidelines lol. Surely other people have gone through what I'm running into
site#574
Congrats @solar locust on contributor
You are now DD
is this the correct syntax for getting a role id? (saved in config.yml)
from bot.constants import Guild
patreon_tier_1_role = Guild.roles.patreon_tier_1
it would be ```py
from bot.constants import Roles
patreon_tier_1_role = Roles.patreon_tier_1
look at constants.py
ok
looking at constants.py, do I need to add my 3 roles to the Roles class?
I presume so
yup yup
constants.py is what reads the yml files
and makes the constants available to the project
2 new contribs π
maybe more, news to come soon
just waiting on some responses, have an announcement prepped
Ooo
Hey, is any of PyDis bots slated to move over to slash commands via HTTP?
no plans for it atm, no
our short term plans are to migrate to d.py 2.0 for the other interactions
and then wait a few weeks/months to see what other libs arise
ideally we don't want to re-write our bots
ok, it's fine, we are having VC discussion about if your bot is call and response, get ahead of curve, switch to slash commands over HTTP
@vale ibex site#571 will also need to be merged before the optional base url can be used w/o an error
ah, missed that, will look now
out of interest was there a need to swap the field order?
Good luck on your exams!
it wasn't necessary, but the optional filed looked weird in the admin panel when it was in the middle
yea makes sense
@brisk brook about the __init__ return annotations, there was about 20 that had been annotated and about 50 that had not been.
So I just went ahead and removed the 20 annotations
Yeah, any plans for how we should keep this consistent?
no plans as of now
Alright
hopefully people just notice other files, not sure how we should enforce it
enforce it automatically, that is
Yeah, we'll just have to remember it.
lol
I don't think there's a way to setup some CI or tool to check only that
Should we change this page? https://pythondiscord.com/pages/guides/pydis-guides/contributing/style-guide/
Coding conventions for our Open Source projects.
ehhh, I'm not too fond of having something in the style guide that we can't enforce via pre-commit or linting
since it's sort of hidden to contribs until PR
If def __init__\(.*\) -> None finds anything, workflow fails, but an entire workflow just for that is probably not worth it
I'd be up for adding mypy tbh, if it wasn't for the huge change we'd need to make to the current repo
even then I'm still on the side of adding it
and we're also removing seasons soon
the ignore could just be removed from the plugin settings to the annotation is used everywhere
Pretty sure the linting doesn't disallow this ```py
def long_function_name_that_is_taking_up_too_much_space(var_one, var_two, var_three, # didn't drop a line after the brackets
var_four, var_five, var_six,
var_seven, var_eight):
print(var_one)
Even though it's specified in the style guide
Might grow in the future?
reminded me that bot#1641 is still open
@brisk brook by this: https://github.com/python-discord/sir-lancebot/pull/802#discussion_r700807663 are you talking about https://docs.python.org/3/library/typing.html?highlight=typing final#typing.Final
Yup
I haven't seen many annotations for constants
We don't use typing.Final within Sir lance at all
I am pretty neutral on it, we don't really use strict type checking so the benefit of a failing workflow from breaking those rules are gone. But I thought I'd bring it up
Also yes I mean for all constants, it was just those lines that reminded me of it
according to my regex search in pycharm, we've never annotated constants
unless I've messed up my regex search
ye
@brisk brook another ping. For https://github.com/python-discord/sir-lancebot/pull/802#discussion_r700813542, could you elaborate on what you think should be done?
So previously we did import typing as t. So code that used Iterable would be as follows: def test(arg: t.Iterable[str]), is this not the case?
The diff was being weird on my phone, but I see now that you have indeed changed it
I'll make it as resolved
It seems that it was always t.Iterable and nothing else.
This diff didn't show up for me
So I thought you only changed the import, and not the code that used it
according to git blame it was like this ever since I created the file
github do be wack sometimes
@brisk brook final ping. For https://github.com/python-discord/sir-lancebot/pull/802#discussion_r700803591, it's only used as an annotation for self.match: Optional[Match] = None. Should it still be changed to __class_getitem__ regardless?
Even better, Optional[re.Match] should work
Alright cool. When was this deprecated? I currently am not finding anything on it.
π
This PR is getting ridiculous, there's just so many things that I'm not catching
@clever wraith oh no
wait why are we wanting to annotate tuples but haven't covered dicts?
uhhhhhh
I am thinking about this one lol
A lot of those canβt be easily modeled just with dicts
Iβd be for something like pydantic if it helps
Probably should be annotated only if it's not almost immediately realized by the program itself.
But I personally prefer dicts that are annotated, because otherwise they are kinda a PITA to work with
Pain In The Ass
or delicious pocket bread, depends on the context
I mean, good annotations can be quite delicious
This part?
only if it's not almost immediately realized by the program itself.
There are cases when dict is already nested like tuple[int, dict] in that case it might be helpful to annotate, but to be totally honest, it'd look a bit "scary" to newcommers.
TypedDicts would be nice for all the api interactions
I believe, for that matter we could use Pydantic then, (as it was mentioned earlier. )
As far as I can see it has a mypy plugin, as well.
or dataclasses and dataclass-factory, it's much smaller than pydantic AFAICT
@celest charm ```py
import random
from typing import Optional
def return_int_or_none() -> Optional[int]:
if random.randint(0, 1) == 0:
return 1
return None
def expects_int(arg: int) -> None:
return
var = return_int_or_none()
assert isinstance(var, int)
expects_int(var)```this works perfectly with the assert, but doesn't work without it
Question is, do we want to assert or just an if?
What if you add an explicit type hint to the variable
casts?
Hmm
Sopy var: t.cast[int, var] = always_returns_int_although_linter_doesnt_realise()?
no, it's a function
cast(int, var)
it doesn't actually do anything -- it just signals to the typechecker
@celest charm ```py
import random
from typing import Optional, cast
def return_int_or_none(val: str) -> Optional[int]:
if val == "return":
return 1
def expects_int(arg: int) -> None:
return
var = return_int_or_none("return") # val=="return" so will always return 1 but linter doesn't realise
cast(int, var)
expects_int(var)```so like this?
Sorry had the ping copied in that
var = return_int_or_none("return") # val=="return" so will always return `1`
expects_int(cast(int, var))
no worries, I like pings π
right, yeah
So in cases where we know it's going to be correct, use cast, and when we're not sure, use assert?
This works π
cast is useful for stuff like list[tuple[T, int]] which you can't really assert on
Right yeah
assert should also be used only in places where the condition should only be false in the presence of a bug
So potentially even```py
def expects_int(arg: cast(int, arg)) -> None:
return
expects_int(var)```?
???
Is that what you meant by this?
You can't put cast into annotations
No I mean, you can't do isinstance(x, list[tuple[T, int]]), But if you believe that it is the case, do cast(list[tuple[T, int]], x)
Right
Is this broadly speaking correct btw?
If we're not sure, throw a normal exception
Well that's what assert would do if it was wrong
assert is not for error-checking, it's for establishing some invariant. In production you can disable asserts
well, it depends on where it is used
def return_int_or_none() -> Optional[int]:
if random.randint(0, 1) == 0:
return 1
var = return_int_or_none() # we don't know if `var` is an `int` or `None`, so we `assert` to check
assert isinstance(var, int)
expects_int(var)
##
def return_int_or_none(val: str) -> Optional[int]:
if val == "return":
return 1
var = return_int_or_none("return") # we know it's an `int` so use `cast`
expects_int(cast(int, var))```
Or would the top be likepy if not isinstance(var, int): raise TypeError("we need an int") expects_int(var)?
yes
Right
well... the example is a bit contrived
asserts are usually internal checks, while the errors on the boundary of your function/class should be proper exceptions
Is it bad that I've only used assert in unit testing?
Yeah, that makes sense
I'm trying to think of something
def inv_sqrt(x: float) -> float:
if x <= 0:
raise ValueError("nope, that's not going to fly here")
sqrt = x ** 0.5
assert not isinstance(sqrt, complex)
assert sqrt > 0
return 1 / sqrt
also a bit contrived, but eh
def expects_tuple_of_list_of_int_or_str(arg: tuple[list[Union[int, str]]]) -> None:
return
var = returns_expected_or_none() # how do I validate `var` is the expected here?
expects_tuple_of_list_of_int_or_str(var)```
jesus take the wheel
why would you need to validate the return type of that thing?
I suppose it's or_none so we can just do if var is not None
in that case yes, check if it's none
sometimes the invariant is really way too complex, so you'll have to ignore some errors
And when you say "ignore some errors" do you mean add a literal # ignore: [err_type] to the end of the line?
Or do you mean "as a human, ignore it"
this
I still wonder if we should put effort into all this
are we planning to do it for sir-lancebot as well?
for role_id in role_ids:
if (role := guild.get_role(role_id)) is not None:
members += len(role.members)
else:
raise NonExistentRoleError(role_id)
return {name or role.name.title(): members} # `role` is `Role` but linter thinks it's `Optional[Role]`
```so how would I cast here?
cast(Role. role).name.title()
or
assert role is not None before that
actually, the correct error would be: "role is possibly unbound"
which is what pyright gives
cast(Role, role)(type goes first)
The error mypy gives is error: Item "None" of "Optional[Role]" has no attribute "name"
So I'd do {name or cast(Role, role).name.title(): members}
yeah
Yeah, that seems like a good solution. But is it worth to port everything to dataclasses(and use d-factory)? However, it would type annotations and testing much easier.
testing? 
We don't want to enforce dictionary type hinting since it'll get bloated very fast (large type annotations), so most dictionaries will remain the same.
I was thinking about pattern matching(might've used the wrong word), realised it's a nonsense for now. I played to much with it π
It will add more code, but it does buy us explicitness (and checking that the API actually returns what we expect)
we could remove all type annotations, and the code would become more compact
error: Value of type "Infraction" is not indexable```
```py
async def ...(..., infraction: Infraction, ...) -> ...:
...
infraction['id']
infraction['active']```
Can I fix these with a `cast` as well? mypy thinks `infraction` is of type `Infraction` but it's actually a `dict`
I think there was an issue which might fix that actually
Why is it hinted as Infraction then?
It's a dpy converter
ahh
yeah we did fix it somehow, right?
so that's to be fixed in a different place
Indeed, but it sounds like a βspring cleanupβ sized PR, and would trash all the typing annotations that have been added.
I wasn't implying we should do that
It was numerlor that fixed iirc
I meant that type annotations add more code, but they buy explicitness and static analysis
bot#106
Ah right
I need to do likepy Infraction = dictat the bottom of constants.py I think
Which in fact is already there
Hmm
It doesn't seem to be working
In case you decided so in the future, I would be a partner in this.
I will never vouch for removing all type annotations, no...
my one on bot next
It's not lol
I have no idea
Example from xkcd: latest_comic_info is hinted as Dict[str, Union[str, int]]
It's not clear at all what's in this dict, you just have to go to the API docs. It goes completely contrary to our style guide that mandates docstrings and type annotations even on functions/classes which are totally clear without them (like setup() or cog classes)
Instead, you can just do something like ```py
@dataclass
class Xkcd:
num: int
day: str
month: str
year: str
safe_title: str
img: str
and use a library or a hand-written utility function to create these from a json dict
.source xkcd
I'm not saying we should refactor the code to do that, just some rationale as to why it might make sense to write in this way
Anyways, you wouldnβt remove the typehints totally, just use a different approach. (like in fastapi)
what are you talking about?
You said using a library like that would mean removing typehints totally
Hm?
Here.
@brazen charm you PRd bot#1731 which I think is what I need here but it doesn't seem to be working
My issue is that in a command I'm typehinting an argument to the Infraction class, and then subscripting it (infraction['active'], infraction['id'] etc.).
Unfortunately mypy is raising an error for this, stating that Value of type "Infraction" is not indexable, despite us having Infraction = t.Optional[dict] in constants.py, which should cover for this. Fwiw I changed to Infraction = dict in case it was the Optional breaking it but still same issue.
The docs do state that mypy supports TYPE_CHECKING so that shouldn't be the issue either.
Please ping on response
oh, I thought by <#dev-contrib message> you said that you'd like to remove all type annotations from code
I think there's some misunderstanding between us
No, not at all. I meant implementing this dataclass-dataclass factory solution. I looked up the library.
well, I'm not sure other people would approve of that
after all, that's an extra dependency
Yes, valid point..
and sir-lancebot is a bot for adding fun features, not proving theorems at compile time or something
so it's more or less fine to write in a jesus-take-the-wheel style
Hi! I am working on bot#1765
I a getting an error while trying to get a role object for a certain role.
I am using
role = discord.Role(id = id)
However this causing an error, presumably because that's not the way to get a role object from an id?
What should I use?
ok
And if you don't have guild then you get that from self.bot.get_guild(constants.Guild.id)
You'll also likely need to make sure neither of those are None
thank you!
Since if they aren't in cache they'll both return None
if they aren't in the cache, is there any way for me to load them in?
If you 100% need them then you can do get or fetch
i.e role = guild.get_role(id) or await guild.fetch_role(id)
ok
Just don't do that when getting Users
as long as you add await self.bot.wait_until_guild_available() at the start, you should be able to get the roles just fine
i only need to get the roles - so the user problem shouldn't be a proble
since that ensures the role, member and channel caches are populated
Not sure I haven't checked with mypy, it may have problems with the type checking assignments overwriting existing vars with incompatible types
Ugghhh error: Cannot assign to a type that's the issue
mypy doesn't allow for x = type from the looks of it
Or rather, mypy doesn't understand that it's saying "interpret x as y"
@vocal wolf congrats on that monster PR
Don't know what the nicest way to go around that would be if it's something important; a big if/else on the TYPE_CHECKING would work but I don't think we really want that in the code
wdym "a big if/else on the TYPE_CHECKING"?
if typing.TYPE_CHECKING:
# assign names to return values
else:
# define classes
I'm not familiar with mypy and not that experienced with typing overall so there could be some way around that
It does work but definitely not clean
I think subclassing the converters also works but again, not nice
The initial approach I had in mind with monkeypatching dpy to understand Annotated should work but I don't think we want to change to that unless it's decided that the bot will use mypy (and there isn't a nicer way with the TYPE_CHECKING)
I'll leave these errors for last then
tldr it depends on the testing framework
I think that because pydis uses pytest to run the tests its fine
pytest actually rewrites all assert statements
Yeah that makes sense. I guess at the time I wrote that I was curious if it was a common thing to use assert outside of a testing scenario
ah, idk π€·ββοΈ
Does anyone know how to make mypy recognise log.trace as valid? It currently gives error: "Logger" has no attribute "trace" and this isn't exactly an error we can specify to ignore by adding # ignore [attr-defined] after each call
CC @celest charm since you were helping with mypy earlier
Hmm interesting idea
Assert is pretty good debugging stuff, you can completely remove them for 0 performance hit
So instead of adding sanity checks with it statements and raising errors, use asserts
Just found this article which shows different approaches, but none of them are particularly tidy https://sam.hooke.me/note/2020/03/mypy-and-verbose-logging/
Sanity checks (if I used the term correctly) is just checks you put in your code to make sure things are as you expect them. Like after a complicated operation you expect certain lists to be empty, etc. You can use asserts there which will raise an error if it isn't the case.
Possibly importing the logger, or using the one on the bot instance
Not sure whatβll happen to the names then though
Maybe you could define a custom logger class which just inherits logger, and adds grace (I think we already do this)
Anyways, none of this is probably relevant since we were considering removing trace all together
Where did we fall on that
I think it is useful, and can now be used properly with the loggers being controlled through the env var
As much as removing it would make life easy, I do think it's useful
We don't do this btw. We use logging.addLevelName and then logging.Logger.trace = _monkeypatch_trace
And that will still have the same issue anyway apparently (according to the article I linked above)
you don't.
Sadly.
and even so, even if you do set a logger class, mypy will still complain because the logging.getLogger method is typed wrongly
but there is this
!d logging.setLoggerClass
logging.setLoggerClass(klass)```
Tells the logging system to use the class *klass* when instantiating a logger. The class should define `__init__()` such that only a name argument is required, and the `__init__()` should call `Logger.__init__()`. This function is typically called before any loggers are instantiated by applications which need to use custom logger behavior. After this call, as at any other time, do not instantiate loggers directly using the subclass: continue to use the [`logging.getLogger()`](https://docs.python.org/3.10/library/logging.html#logging.getLogger "logging.getLogger") API to get your loggers.
so you can subclass logging.Logger and all logger instances will be of that class
--
(why the fuck is it klass)
because class is invalid
yeah klass or _class are quite common substitutes
Don't think this even helps here
ah right, reserved keyword π€¦ββοΈ
Can you import that logger class and always do log: MyLogger = logger.getlogger(__name__)?
yeah, that's what I do
however
mypy will still complain about that assignment statement
I mean it's a one off thing so we can just # ignore imo
arguably doing it this way and ignoring just this is better
Potentially, see bot#1773
So how exactly does it work? In terms of code
Found 1423 errors in 100 files (checked 128 source files)
"fun" is not the right word
mhm
That's what I'm doing lol
I've gotten a fair amount of things worked out
But there's still big roadblocks, like the fact we have a custom log.trace which gives an error every time it's used
This seems to be our best bet for fixing that but not sure how to use it
shadfhasdf
i sent it in my dev channel on my server lmao
so, I don't use mypy as of right now, but codewise
# modmail/__init__.py
from modmail.log import ModmailLogger
logging.TRACE = 5
logging.NOTICE = 25
logging.addLevelName(logging.TRACE, "TRACE")
logging.addLevelName(logging.NOTICE, "NOTICE")
``````py
# modmail/log.py in full
import logging
from typing import Any
class ModmailLogger(logging.Logger):
"""Custom logging class implementation."""
def trace(self, msg: Any, *args, **kwargs) -> None:
"""
Log 'msg % args' with severity 'TRACE'.
To pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.trace("Houston, we have a %s", "low-level problem", exc_info=1)
"""
self.log(logging.TRACE, msg, *args, **kwargs)
def notice(self, msg: Any, *args, **kwargs) -> None:
"""
Log 'msg % args' with severity 'NOTICE'.
To pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.notice("Houston, we have a %s", "not-quite-a-warning problem", exc_info=1)
"""
self.log(logging.NOTICE, msg, *args, **kwargs)
Those docstrings were taken directly from the library in order to keep consistency between custom levels and built in levels
In retrospec, I would probably move the stuff from init.py to modmail/log.py
A Modmail bot for Discord. Allowing safe moderator conversations with server members one server at a time.
https://github.com/discord-modmail/modmail/blob/main/modmail/__init__.py handles most of the logging stuff right now
ty
Here is a working solution that doesn't require humdereds of ignors:
import logging
import typing
logging.addLevelName(5, "trace")
class Logger(logging.Logger):
def trace(self: logging.Logger, msg: str, *args, **kwargs) -> None:
"""
Log 'msg % args' with severity 'TRACE'.
To pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.trace("Houston, we have an %s", "interesting problem", exc_info=1)
"""
if self.isEnabledFor(5):
self._log(5, msg, args, **kwargs)
if typing.TYPE_CHECKING:
def get_logger(name: str = None) -> Logger:
return logging.getLogger(name) # type: ignore
logging.getLogger = get_logger
if __name__ == '__main__':
logging.setLoggerClass(Logger)
logging.getLogger(__name__).trace("test")
That trace function is ripped straight from the bot, it isn't new code
The hack in the type_checking block is factually correct
but now you have to use a custom get_logger method?
It should require no other code changes
One sec, I'll get you a patch lol
I don't get how this works: ( see my comment )
if typing.TYPE_CHECKING:
# this method isn't the same name as getLogger
def get_logger(name: str = None) -> Logger:
return logging.getLogger(name) # type: ignore
logging.getLogger = get_logger
??
What matters to mypy here is that the annotated return of logging.getLogger is now the custom logger class
yeah
ah
i wonder if this could get into the stdlib lol
and use a typevar on the return of getLogger
This wouldn't work in another module though, right?
I think that's what logging.setLoggerClass(Logger) is for
well it works but it doesn't fool the type checker is what I mean π
Then each time you do logger: Logger = logging.getLogger(__name__), and this has the custom class so will work
wouldn't it be nicer to have a custom log_utils.get_logger func that wraps logging.getLogger?
and overrides the return type
then import that everywhere instead of logging.getLogger
and you get rid of the camel case too π
So you're suggesting logger = log_utils.get_logger(__name__) instead of logger: bot.log.Logger = logging.getLogger(__name__)?
hmm
It should in theory work in all modules, let me test
provided this is loaded before them
yeah it will work in the sense that you'll get your logger
but a type checker wouldn't see the if TYPE_CHECKING block from another module, right
I guess it also depends on which type checker is being used
mypy is the one we're thinking of adding
how does one run the site tests in the docker container?
The type checking block
sudo docker exec 5a3e85b3e32e "poetry run task lint" did not work
ah that surprises me
What's your import + getLogger in the other module?
Let me get this uploaded somewhere you can play with it
I've never really used mypy though so maybe I'm underestimating it
repl.it
Well, wait a minute. I have a __main__, __init__, and a regular python file in a module. I told mypy to run as a module, but it's saying it found 1 file
lol
Did it actually lint everything or not is the Q
If it says 1 source file it only checked that one file
Well, you're right it'll be check
How would I get it running over a module
It says -m is an option
But that seems false
mypy -m x.py I think?
-m MODULE, --module MODULE Type-check module; can repeat for more modules
That is what I used hmm
package maybe
Ah that's done it
Okay, sadly didn't work
f
Then we need one of these two
That is a nice solution
That's the price we pay for staticness
hi pls test n review https://github.com/python-discord/site/pull/575
more metrics for the Joe Banks Gobblerβ’οΈ
Looking at it I'm not sure if you can directly because dev deps aren't installed to the container; otherwise it'd be docker-compose run web test I believe
ooo something's happening
review-policies/core-developers.yml lines 102 to 103
- ".github/workflows/*"
- "Dockerfile"```
should pyproject.toml be a part of this or no?
most of the time, it would be removing or adding a dependency
because then every PR that adds a dep needs a sign off from devops
if people feel it needs an explicit devops review they can add the label
huh
does that mean that docker-compose.yml is not used when deploying any of pydis's stuff?
since presumably if it was used, it would be on that list
That's for dev
@static canyon @tough imp I found a solution that does work for all files in a module, but this is more of a curiosity than something that wouldn't get your head decapitated:
In a logging.pyi, I added:
from logged import CustomLogger
def getLogger(name: str = None) -> CustomLogger:
...
This ofc raised errors when I tried using anything else in the logging library, but to get around that, you can use (this is in __init__.py):
from Lib import logging
logging.something_not_in_stub()
and nothing will complain anymore. Other files can use the normal import logging with no problem
Again, don't suggest this
HIGHLY ILLEGAL
since all of pydis' stuff is on k8s, compose files will never be used in prod
lol β well it will work when now I fixed review requests

i dont follow
you called a function that doesnt exist and it solved the problem?

