#dev-contrib
1 messages · Page 48 of 1
if you have a running process that takes input - like, eg, an ssh session - does conemu let you close it?
_Lemme boot up my windows _
I think it's detecting win and assuming pycharm's terminal is a normal one and trying to do its fancy stuff
With a warning I think
I wonder if they found a workaround then
every terminal I've used that isn't cmd will hang if you do that
https://i.imgur.com/ymO7eeP.png after an input() in the repl
I mean, click yes ofc
just closes it normally
Works fine for me
Owww, I need to update my whole config file now
Time to go back to linux
I've written several
@molten bough
yeah, I meant one in one of our repos. if it doesn't work for our windows users and it's not fixable we may need to e.g. put in an override env var or something.
Oh, right
I'll look at the actual library used first, there might be something
okay yeah, looks like COLOREDLOGS_FIELD_STYLES and COLOREDLOGS_LEVEL_STYLES can both be set to the empty string
That'd do it
so it might be worth just documenting that
sounds reasonable, at least if anyone else has an issue with this.
does it work in pycharm on non win?
after looking into it further it looks like it doesn't do colors without emulating the terminal because the output is redirected and it doesn't do colors when sys.stdout.isatty() is false.
Should an issue be made for that with some kind of mock stdout or just leave it be because it's just with ides/editors that redirect output to their terminals?
For me, it just runs without colors by default and with colors if I select "Emulate terminal in output console" in the run configuration
For me nothing is shown
win?
Not with pycharm and not with colored logs
Nope
We talked about this before
I think
It's just been merged
I think colorama can't do the proper calls when the terminal is emulated through pycharm
F4zi have you tried emulating terminal like Ves?
in the run config on the top right
For me it's here:
Yeah same
Should help.py go under evergreen (SeasonalBot)?
Without it, it will just default to the old black-and-white, with it enabled, it shows colours
Oh i got it
Otherwise, this is a mock for the isatty I found on SO
import logging
import coloredlogs
import sys
class PseudoTTY(object):
def __init__(self, underlying):
self.__underlying = underlying
def __getattr__(self, name):
return getattr(self.__underlying, name)
def isatty(self):
return True
sys.stdout = PseudoTTY(sys.stdout)
coloredlogs.install(stream=sys.stdout, fmt="%(asctime)s | %(name)s | %(levelname)s | %(message)s")
logging.warning("Hey")
@cold moon That's probably core functionality not bound to a season (we're mostly removing seasons anyway)
Doesn't pycharm support colored logs as a feature?
That'll make coloredlogs use the colored formatter even without emulating it
Huh, where this should go then? To same directory than bot.py?
Btw, is there an event or something dispatched when a log is called?
is there a sure fire way to reproduce this? i cant get it to come out in anything but colours
run it as a script so the output goes to Python Console without emulating the terminal
No idea why the demo works but emulating terminal doesn't on win though
wait... it can also go to Run but I got confused out of your screenshot, but same behaviour
well.. pycharm issues are maybe a bit out of scope?
Yeah seems a bit out of scope for the bot directly and only affects win with not working completely, but could have a mention somewhere
(The new resources page is looking awesome!)
well.. where do you stop then? like it does not work with sublime Text either.
yes.. the new page is very nice looking
could this be a fix with colorlogs? maybe we could write a PR to them and have them merge it.
then we did not have to do any tricks or hacks or mentions
If it's still usable on Windows, just without colored logs, I don't really see an issue with the current merged PR
It's basically just reverting to what we always had in that case
I don't really see a way for us to do this cross-platform, cross-IDE
It's a side effect of the outputs being redirected, and the humanfriendly package returning False because of it in their terminal_supports_colors
It does work in conhost though
Throwing the above into sitecustomize seems to fix it nicely
Guys, I made a thing
Creating channels as listed in the config file, creating a config file and update it with the new IDs
Because I was too lazy to recreate all the channels myself
It isn't recreating the same channels, they were there only for demo purposes
I was too lazy to create channels and update my config file, so I made couple channels and added one channel ID for all fields in the config file
If a core dev here is interested in putting it on the repo or somewhere more accessible
Yeah, here it is a full sync
interesting.
what if some of the channels already exist. would it delete them all?
@green oriole
For now yes
I guess that's pretty easy to ignore
Done @crude gyro, now if the channel already exists, it just use its ID in the config
Feel free to keep working on it @green oriole.
There's been on the backburner this type of thing for quite a while: automatic setup of a test server which creates new channels that aren't found, or uses the ids of found ones, creates the appropriate emojis if they don't already exist, same with webhooks and then generating an appropriate config using the new or found values.
categories may need to be considered
yeah that's why the idea was part of a huge config rewrite
the current config setup isn't perfect and we had some ideas to improve it
using a single config file that only contains the items required, being able to use env vars for any of the values instead of requiring us to use the !ENV tag in the config file, things like this
it would involve a bit of extra documentation too to help with making sense of config values, options and ways to use the setup capabilities
at any rate, feel free to make a branch with your changes. it's probably a good way to kick things off regarding the concept
yeah you'll want to change the on_message to a command so things are structured properly
but otherwise it should transfer over to it's own extension without much issue
then you can just conditionally load the extension if it's in debug mode
i'll try spare some time with you to cleanup some of the code and help you
I made the config_verifier cog that checks channel constants so far. Would this make sense to have there (maybe renamed)? also noticed some kind of validating in Mark's help channel cog that could be moved there if feasible
yeah probably, but there's no rush
this type of thing isn't likely to be a quickly developed feature
and it's not super required so there's no need to push akarys into doing a heap all of a sudden lol
Not pushing, just that a new cog where it could fit exists
merged, maybe
fit as it is, probably not
the config setup is likely to be tweaked, so a large portion of this may not even be an extension
@brazen charm Re: unit tests. If you have questions while working on that issue, feel free to ping me. We can probably work it out together. I think some of the existing tests already have most of the ingredients you'll need while writing tests for !hush.
For SeasonalBot's .help command, should this have 1 cog per page or multiple?
Yes, I found this. May I use some parts of this code or I have to write everything my own?
There's no requirement to reinvent the wheel
ok
Python bot have perfect help, I can't anything that I can do better. So I can copy and paste this code and make small changes (some constants, check) and use this? (I'll reference this in commit)
Sure, there's no need to reimplement it just because it already exists elsewhere. I think it's a good idea to add a comment in the file stating the origin as well; that may make it more evident to a reader that it's adapted from the other repo. If someone finds a bug, we'll need to make sure that we fix it in both repos/bots.
OK, one question: Should I add help cog to same directory than seasons manager?
There is a PR open for changing the help on @stable mountain so consider looking into that
I don't think a help command belongs in the seasons subdirectly. It's a core function of the bot that should probably go in the main bot folder or a logical, new subdirectory of that bot folder with a name indicating core functionality. However, moving a file should not be hard work, so using the main bot folder for now should be fine and we can always move the file later if more people weigh in.
Ah, yes, that PR is a good point.
Is this emoji on an emoji server ? :defcondisabled:
It sure is
Okay, so we want it as an emoji directly on the dev server right?
And.. Most of them aren't on the branding repo
that could be resolved
I guess I could just upload them
I think I'll not use this PR, due changes is still requested. This would be merged to there when PR get merged.
OK, done now. PR maybe in some hours or tomorrow, depends how much time I have
How are the roles set up here? For the hush, would it be enough to override sending messages for Developers in the channel it was invoked in?
That should be enough, yeah. Every public channel has Developers permissions set-up. Staff channels probably won't have that, so it should be able to handle that to stop it from throwing an exception if someone accidentally uses it there.
When the bot gets shut off, do the cog unloads execute? If it's worth implementing some alert logic there
Alerts for what?
For the hush command, if some are left when it stops (won't get cancelled automatically)
Is there a reason not to persist them like other scheduled tasks are?
Just going off of what the issue requests
A second command, !unhush, should undo the hush immediately. This is important in case the bot restarts in the middle of the duration, since we're not persisting the duration anywhere.
I had not heard of grabify, that's a potentially pretty important commit there
@cold moon see this issue when you get a chance: https://github.com/python-discord/bot/issues/767
Hey uh - i posted my first PR under the new template system so sorry in advance if it's not perfect
@ me if you want me to make any changes and I will
Something with the new default event loop seems to be broken (for me) on win after I updated to 3.8, getting
Traceback (most recent call last):
File "C:\Users\Numerlor\.virtualenvs\bot-K_QdelnW\lib\site-packages\pycares\__init__.py", line 91, in _sock_state_cb
sock_state_cb(socket_fd, readable, writable)
File "C:\Users\Numerlor\.virtualenvs\bot-K_QdelnW\lib\site-packages\aiodns\__init__.py", line 106, in _sock_state_cb
self.loop.add_reader(fd, self._handle_event, fd, READ)
File "C:\Users\Numerlor\AppData\Local\Programs\Python\Python38\Lib\asyncio\events.py", line 501, in add_reader
raise NotImplementedError
NotImplementedError
on bot.run. Setting the asyncio event loop to SelectorEventLoop fixes it
the bot is not running on 3.8 yet
nevermind it is
hm
well
!int e ```py
import sys
print(sys.version)
In [2]: import sys
...: print(sys.version)
...:
3.8.2 (default, Feb 26 2020, 15:09:34)
[GCC 8.3.0]
it seems to be runnning for us
discord seems to be using some unix only signals now from what I understood in the notes
have you got the new dependency changes?
rebuilt the environment
where did you get the unix only signals stuff?
https://discordpy.readthedocs.io/en/latest/whats_new.html#v1-3-2 this is the version change made
ah nvm skipped on some code when I looked through it the second time
but crashes around its loop.run_forever on the default event loop
That looks like an aiodns issue
pycares is a wrapper for c-ares, which I believe is a DNS resolution library
Solution seems to be here
This might slow the bot down slightly on windows but that doesn't really matter since it's on Linux in prod
@brazen charm (in case you didn't see it)
loop = asyncio.SelectorEventLoop()
asyncio.set_event_loop(loop)
I got it working with this in the init.py, but that looks like a more proper solution
Wanted to make a draft today but that kinda slowed me down
Yeah, use the policy option so it does select a more appropriate loop otherwise
we got rid of seasonalbot-chat?
Yes
ah
Hey @tawdry vapor I was pondering a bit about the reminder systems.
I've seen 2 implementations of reminder system, and they each have their pros and cons.
- the Python Bot implementation is to use the database as a backup to reschedule tasks when the bot crashes
The pros are the reminders are called exactly on time, not at any specific interval, the cons are that some tasks realistically speaking don't need to be sheduled (e.g. 2 years) and apparently asyncio.sleep is only reliable up to 48 days.
- another implementation is the use the database as a catalog of tasks and periodically check whether to call them or not.
The pros are the less processing power, but the cons are that tasks aren't going to actually be scheduled on time.
I'm trying to decided which one / whether there's an even better way for my situation.
The main purpose is to mute a user for, in general, about 2 months, but it will also be used for a simple reminder system as well.
I'm also not sure which one is easier and simpler to implement, as I'm not exactly the best at handling time in python
Pretty sure polling will be simpler to implement. I doubt processing power really is significant unless you're dealing with enormous amounts of tasks. Feel free to benchmark this yourself. If you're concerned about the 48 day thing you can re-schedule all tasks every 48 days or even poll the database every 48 days to only schedule tasks which are shorter than 48 days.
For future reference, this is getting off topic for this channel since it's no longer about our projects but rather yours.
@patent pivot snekbox is running on 3.8, but the bot is running on 3.7
How does seasonal commands that send a message into the deprecated #seasonalbot-chat now works?
Ah okay ELA opened a PR
@green oriole @patent pivot was using internal eval (!int e) not snekbox
So, the output did show the version of @stable mountain, which is now Python 3.8.2
!e
import sys
print(sys.version)
@hardy gorge :white_check_mark: Your eval job has completed with return code 0.
001 | 3.8.0 (default, Nov 23 2019, 05:49:00)
002 | [GCC 8.3.0]
!int e
import sys
print(sys.version)
In [8]: import sys
...: print(sys.version)
...:
3.8.2 (default, Feb 26 2020, 15:09:34)
[GCC 8.3.0]
So, snekbox is on 3.8.0 and @stable mountain is on 3.8.2
Sweet.
Ah nice
Time to rebuild the venv
By the way, I thought about the dev server autoconfigurator, and I had another idea
If we want to keep the channel ordering and subcategories, the role colors, channels descriptions and everything that isn't in the config, we'd need some additional data
That's why I thought about making @stable mountain create a snapshot of the server structure containing all important information and display it on a public endpoint on the site
And the local autoconfig cog would be able to pull the snapshot, and apply it
What would you say about that?
We could also keep an history of the snapshot in case we want to switch a dev server to a previous version for some reason, because a PR was on a previous config for instance
What do you think about this solution?
hm, that does sound like a good solution if our intention was to keep it in perfect sync
it doesn't sound too hard to do either
I guess I like it.
Did you think about how you're planning to keep this snapshot in sync with the actual guild?
One of the reasons I'm asking that is because our new help channel system, if introduced, would cause frequent changes in the channel lay-out of the guild that do not necessarily have to be captured by such a snapshot.
My goal was to have a command to use to trigger the sync
But we could also trigger a sync at each bot reboot for example
I think it'd be better to sync manually whenever needed
a command sounds fine
and I don't think that we need to update that snapshot that often, either
but that should be automated
maybe on-boot
could be part of the sync cog, I guess
I think we could simply upload a new snapshot everytime a change is made to the server
yeah, but that's very incompatible with the new help channel system, @green oriole
channels will be changing order all the time
we could perhaps completely ignore channel order
and trigger on other changes
also yes, we should ignore archived channels.
Or we could also ignore the help channels
the help channels are important, so no.
that help system should work on the test server
besides, ignoring 50 specific channels sounds like maintenance
easier to just ignore channel order changes
I mean not trigger a new snapshot when a change is made to help channels
So the order will update only when another change is made?
yeah, I don't like it, why ignore all changes to help channels when we can just ignore channel order in general? why would we care about channel order on test servers?
Because we want to really reflect the real server
yes and we will still do that in all the snapshots
but there's no need to update the snapshot just because we changed channel order
Yeah, that's fair
That depends on whether or not we're interested in channel categories
Because that's the thing we're going to be changing for those help channels
They'll be moved between three different categories
I don't think capturing the current state of the help channel system is important
any channel move should not trigger a new snapshot imo
Yeah
Whether or not there are four in the in use or five incidentally during the snapshot should not matter
it makes no difference. and that channel move will be reflected in the next snapshot, triggered by a change that does matter
If it is an important reordering you could always trigger a manual snapshot
yes, although I cannot think of a situation where a channel reordering is important
We don't follow the channel ordering here in our dev test server
but, hmm, permissions will also be changing on those help channels as they move between categories...
The channel categories will be important, since the help channel system relies on the categories
yes
which isn't a channel move change, and would then trigger a new snapshot
so perhaps it's not enough to just ignore channel moves
we'd have to also ignore the repercussions of that move
I'm not convinced that we need snap shots that should be kept in sync in real time
yeah, me neither
a daily snapshot would be fine, imo
even one for every bot restart
If something affects the bot, the bot will need to be restarted anyway, otherwise the change is not relevant for the bot code/dev
so, sync on boot sounds fine to me
Which also means that just capturing the incidental state of the help channels at the moment of sync is fine
yeah exactly
The help channel system should be able to handle any start situation anyway
since the bot can always restart
Last time you removed the seasonalbot channels, the bot didn't restarted for instance
yes, but the channel was not actually removed
And I don't think we should sync permissions, since it would make testing messy
Ah, they are archived right
That would have cause breakage since seasonalbot still uses the channel constants
But we shouldn't ignore move to archived though
Okay yeah, we shouldn't make snapshots at any change
The main point is that if something in our channel set-up changes that affect the bot directly, the bot code should have been updated to reflect that anyway
It wouldn't be good for us to make changes to the guild that would break code without changing the code
Hence, an important guild change should only happen combined with a code change and, thus, a redeployment/restart
Okay make sense
@green oriole left you another review on https://github.com/python-discord/bot/pull/617
should be ready to merge soon, that one
maybe we can even merge it today with some minor changes.
Looks like flake8 doesn't work nicely with the walrus. https://paste.fuelrats.com/kedoburipo.py pyflakes has their error fixed on master https://github.com/PyCQA/pyflakes/pull/457
I knew there was an error in pycodestyle that was fixed on master but not yet pushed to PyPI
Was there an issue in pyflakes as well?
pyflakes doesn't have the walrus node so it stops the whole check with an exception
aroundfuckery haha, thanks mark
mark?
@tawdry vapor
https://tenor.com/xKcE.gif
@brazen charm pyflakes stops because of a bug in pycodestyle. If you update pycodestyle by using the master version, it will work happily
It's documented in this issue (which refers you to a pycodestyle issue): https://github.com/PyCQA/pyflakes/issues/481
It's fixed on the master of pycodestyle, but not in the version on PyPI and flake8 hasn't seen a new PyPI release in a long time either
pyflakes crashes with "pyflakes" failed during execution due to "'FlakesChecker' object has no attribute 'NAMEDEXPR'", which is separate from the lint errors pycodestyle gives and it stops the lint (can't be ignored)
@stable mountain is now running 3.8 right?
@brazen charm Yes, that's the error I had as well and it was fixed by updating pycodestyle pyflakes
It's also the error in the issue I linked "pyflakes" failed during execution due to "'FlakesChecker' object has no attribute 'NAMEDEXPR'"
getting pycodestyle doesn't seem to do anything without also getting pyflakes
(except the Exxx errors ofc)
This bug, that misleadingly prints that it has something to do with pyflakes, is fixed by updating pycodestyle to the latest version of pycodestyle on the git master
The bug that causes this error to be printed: ""pyflakes" failed during execution due to "'FlakesChecker' object has no attribute 'NAMEDEXPR'"
is fixed by updating pyflakes pycodetyle to the latest version on the master of pycodestyle pyflakes
I don't really know any other way of saying that I'm a fool
but anyway doesn't really matter, should I make an issue so it gets fixed until a release on the bot or just avoid walrus for now?
I'm not sure if we want that
So, yeah, that means no walrus for now
Even if you fix it (which I've done locally) by updating pycodestyle, flake8 will run but give linting errors for the walrus
Since flake8 thinks what there should be spacing after the :, not before the :, and it doesn't understand the := at all
it does no longer crash, though
I got around it in my advent of code repo by manually including specific noqa's for all my walrus lines
which is not nice
I'm kind of surprised it's taken this long for tools to start supporting it
So we can now use the walrus right?
No
pycodestyle breaks on it, passing wrong values to pyflakes, causing flake8 to meltdown
I'm kind of surprised it's taken this long for tools to start supporting it
@molten bough
I think there are just not enough contributing to flake8, pycodestyle, and similar tools at the moment
Yeah, you might be right
While the initial issue is fixed (but not pushed to PyPI) that cause flake8 to crash, it still doesn't allow the walrus
off
getting pycodestyle doesn't seem to do anything without also getting pyflakes
@brazen charm
yes, you're right. i was absolutely wrong. I read that issue wrong and misremembered it completely
By upgrading pyflakes to master you can fix it
Still, it has the same consequence: Installing something from GitHub master and it still doesn't fix flake8/pycodestyle not supporting it
support may come soon: https://github.com/PyCQA/pycodestyle/issues/911
pyflakes fixes the error, pycodestyle the lint errors so it'd work if both were from github but yeah not really best to rely on the master
Yeah, I should read instead of being stubborn
If that release of pycodestyle goes through and pyflakes also does a release, we will get our support
There's currently also no support for positional-argument only syntax in pycodestyel
It's the open issue mentioned in that release issue
rip #seasonalbot-chat
For the best IMO
where would be the best place to implement this? don't want to pollute __init__.py
It was added to bot as a new cog, which should be fine: https://github.com/python-discord/bot/blob/master/bot/cogs/config_verifier.py
Well, on bot we can use the YAML, which doesn't exist with seasonalbot
It does probably make sense to port over the wait_until_guild_available helper though, so we can make sure the channel cache is populated
Can I now work with https://github.com/python-discord/bot/issues/562 ? Due moving to Py3.8 is done now.
Yes
Hmm, there is no PATCH methods for deleted messages, should I just delete it and recreate a new one when we need to reschedule them?
The other PR has been already merged, I can't edit it anymore
How to make my fork master branch up-to-date with python-discord's one?
Sync a fork of a repository to keep it up-to-date with the upstream repository.
Add the pydis repo as a remote (most of the time upstream)
Then git pull upstream/master
how is git pull upstream/master different from git merge upstream/master?
It does fetch it before
ooh, saves me 1 command
Yep!
@rocky bloom For future reference, please split your changes into multiple commits. An "addressing reviews" type of commit with a bunch of unrelated changes is not good commit practice.
sorry :/
Why I'm getting sys:1: RuntimeWarning: coroutine 'APIClient._create_session' was never awaited (I'm writing tests)?
Because somewhere a coroutine object is created by calling a coroutine, but it's not called anywhere.
Can you show me the code that's causing it?
class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):
"""Tests Moderation utils."""
def setUp(self):
self.bot = MockBot()
self.member = MockMember(id=1234)
self.ctx = MockContext(bot=self.bot, author=self.member)
self.bot.api_client.get = AsyncMock()
async def test_user_has_active_infraction(self):
"""Test does `has_active_infraction` return correct result."""
self.bot.api_client.get.return_value = [{
"id": 1,
"inserted_at": "2018-11-22T07:24:06.132307Z",
"expires_at": "5018-11-20T15:52:00Z",
"active": True,
"user": 1234,
"actor": 1234,
"type": "ban",
"reason": "Test",
"hidden": False
}]
self.assertTrue(await has_active_infraction(self.ctx, self.member, "ban"))
self.bot.api_client.get.return_value = []
self.assertFalse(await has_active_infraction(self.ctx, self.member, "ban"))
My current code
Do you have the same warning on other tests or only on this one?
For every test that I run individually
Also multiple warnings:
/Users/user/PycharmProjects/bot-mod-utils-tests/bot/bot.py:24: DeprecationWarning: The object should be created from async function
resolver=aiohttp.AsyncResolver(),
/Users/user/.local/share/virtualenvs/bot-mod-utils-tests-lo6WvmsC/lib/python3.8/site-packages/aiohttp/connector.py:727: DeprecationWarning: The object should be created from async function
super().__init__(keepalive_timeout=keepalive_timeout,
/Users/user/PycharmProjects/bot-mod-utils-tests/bot/api.py:53: DeprecationWarning: The loop argument is deprecated since Python 3.8, and scheduled for removal in Python 3.10.
self._ready = asyncio.Event(loop=loop)
I have the first two ones, the last one is new since the migration
You can ignore those for now, they're being worked on. They are deprecation warnings.
some are outside of our control (upstream needs to update)
Yeah, but should I ignore this sys:1: RuntimeWarning: coroutine 'APIClient._create_session' was never awaited too?
You patched APIClient somewhere?
All my code is in this chat
No, that one should not be ignored; can you paste your full file in the paste server? I'd like to run it myself. I think I know what's happening, but debugging at a distance is always a bit more complicated that being able to experiment a bit yourself.
Why?
No, no it doesn’t
We should find out where this function is called instead I think
As far as I understand, this function shouldn’t be called at all during tests, since everything should be mocked
@cold moon I can't reproduce the problem locally; your test runs fine on my end
✔ ~/pydis/repositories/bot [master|⚑ 3]
15:49 $ pipenv run test
Loading .env environment variables…
2020-03-03 16:02:27 | bot.constants | INFO | Found `config.yml` file, loading constants from it.
2020-03-03 16:02:28 | deepdiff.diff | INFO | jsonpickle is not installed. The to_json_pickle and from_json_pickle functions will not work.If you dont need those functions, there is nothing to do.
/home/sebastiaan/pydis/repositories/bot/bot/bot.py:24: DeprecationWarning: The object should be created from async function
resolver=aiohttp.AsyncResolver(),
/home/sebastiaan/.local/share/virtualenvs/bot-I8fh9oki/lib/python3.8/site-packages/aiohttp/connector.py:727: DeprecationWarning: The object should be created from async function
super().__init__(keepalive_timeout=keepalive_timeout,
/home/sebastiaan/pydis/repositories/bot/bot/api.py:53: DeprecationWarning: The loop argument is deprecated since Python 3.8, and scheduled for removal in Python 3.10.
self._ready = asyncio.Event(loop=loop)
..................................................................................................................................................................sssssssssssssss..........................................................................
----------------------------------------------------------------------
Ran 237 tests in 6.065s
OK (skipped=15)
That's the full output
It does skip for me too
That's normal
I think it is normal
Gotcha
Those are tests that are not yet implemented
hmm
I get it now
I'll investigate what's up
It's not something that happens with your test
It happens when I run a test file in isolation; it does not matter which
So, you're not doing anything wrong and I'm going to go on a wild goose chase
I think I know what it is
May this problem when I don't have config.yml file? I have .env but not config for this.
It shouldn’t
It's the self.recreate() call in the __init__ of the actual APIClient it seems
I'm not sure yet why it runs
Ojh
Oh
I know
hm
This is going to be a nice issue
@cold moon Don't worry about it for now. I'm going to look into it when I have time. I know what the issue is, but I'm not sure what the way to resolve it is yet
Thanks for bringing it up
ok, I'll continue writing tests
Can I give you one piece of advice upfront?
What?
In the test you have above, you actually test two things; the second test will never run if the first fails.
It's better to make sure that the tests are truly independent of each other
Oh, so different tests?
Also, if a part of the implementation changes, then the first call could influence the second call, because you use mutable mock objects
Yes or use self.subTest, depending on the level of independence you need to guarantee
I’m curious, what do you think the issue is?
The "issue" is that we changed how we create a session. I create an instance of Bot in tests.helpers to be able to create a realistic MockBot with strict spec_set attribute restrictions. However, the __init__ method of our Bot creates an instance of the actual APIClient, which in turn in its __init__ calls the recreate method that does this:
def recreate(self) -> None:
"""Schedule the aiohttp session to be created if it's been closed."""
if self.session is None or self.session.closed:
# Don't schedule a task if one is already in progress.
if self._creation_task is None or self._creation_task.done():
self._creation_task = self.loop.create_task(self._create_session())
So, it then creates a coroutine object to be scheduled in the last line, but that one never goes anywhere.
that's when the warning will happen
When a coroutine object is deallocated, it will check if it has been awaited; if not, it will give you that RuntimeWarning
Ah, so the issue is the opposite
Okay, this is literally the most dirty trick ever, but it does guarantee that we'll actually have an object for the spec_set with all the attributes.
The "issue" is that discord.py sets a lot of attributes dynamically, which means that you'll need an actual instance to get it right
with unittest.mock.patch("bot.bot.api.APIClient"):
bot_instance = Bot(command_prefix=unittest.mock.MagicMock())
Anyway, I'll need to test that and figure out if there's a better option
Bruh, how should I test send_private_embed?
test if it behaves correctly in all situations
if you set side_effects for user.send you can trigger exceptions when it's called in the function
That will allow you to test the except clause
OK, thanks
But for notify_infraction, is there any way to get embed from this for analyzing?
Mock send_private_embed and look at its call_args
Can anyone help me? I need currently go to music school, but for one of my tests, I need test cases. I made one myself:
test_cases = [
{
"args": (self.user, "ban", "2020-02-26 09:20 (23 hours and 59 minutes)"),
"expected_output": {
"title": "Please review our rules over at https://pythondiscord.com/pages/rules",
"colour": Colours.soft_red,
"author_name": "Infraction information",
"author_url": "https://pythondiscord.com/pages/rules",
"url": "https://pythondiscord.com/pages/rules",
"footer": "To appeal this infraction, send an e-mail to appeals@pythondiscord.com",
"icon": Icons.token_removed,
"description": textwrap.dedent("""
**Type:** Ban
**Expires:** 2020-02-26 09:20 (23 hours and 59 minutes)
**Reason:** No reason provided.
""")
}
}
]
This is for notify_infraction in moderation utils. Can anyone make different cases for test?
nobody's rushing you to do it
ok
If we're going to have this amount of specificity on the test then it would be a better idea to also mock the URLs and email addresses so we don't have to change the tests every time one of them changes
Is there a way to force a pipenv venv to go from one Python version to another? Or is it better to just trash the venv and make a fresh one
I feel like it's the latter but I couldn't remember
Trash it
Fair enough
it's too much work to try to move it tbh
and some libs will need recompiling on linux
Yeah I remember trying it before and it was a dumpster fire
But I wasn't sure if something had changed since then
You may also need to rebuild the docker image
There's no real reason to attempt to migrate your venv (if it's even possible), unless you want to save time on that endless locking. (Thanks phone, it almost 'corrected' that to licking.)
That is true
Having to re-learn so much so I can contribute to the repos again
Attempting to teach myself unittesting and mock and what have you
We have some link at the bottom of the readme
The real python tutorials are really good
Yeah
Mostly done with the base commands in https://github.com/python-discord/bot/pull/812 if anyone could take a quick gander if that's how it was envisioned
With the current implementation there doesn't seem to be a way to make the silence be indefinite
..... he says only just now looking at the converter
Sorry
Did you look at the command help? To know if it should be clearer there
Yeah it's a smidge unclear. I'd specify that adding "forever" as the duration will make the channel silenced until it is !unsilence'd
Or something like that
Something to better elaborate that forever is the keyword
You'll also want to expand on what the defaults are
I don't think we really need a forever
Current channel will be silenced unless one is specified
I could see someone forgetting
-coughmecough-
I know it's mentioned in the issue but I don't see a scenario where we'd want to indefinitely silence a channel
And if we really really needed to, there'd be nothing stopping us from putting it at like 99 hours or something
there is a 15 min limit on timed
Ah gotcha
That should also be in the help
I also wonder if we shouldn't just use the Duration class for that. Or at least inherit from it
I'm just thinking out loud mainly
I haven't tested it
No reason to drag datetime into it and would need to restrict it for the minutes, but maybe a subclass could be useful if keeping check on the timeouts is wanted ( instead of going through time.monotonic or something); asked about that on the issue
(the record keeping)
https://github.com/python-discord/seasonalbot/pull/361#discussion_r387451579 who should have ability to refresh genres?
You can impose a cooldown per user, and let any mod/dev to do it anytime
I can't find Greedy anywhere.
You can read about it here @cold moon - https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html#greedy
I haven't tested with str however, since by default they are strings, so it may not work when you want the last one to be an int. Do give it a try!
In the worst case you can create a new Converter that raise error when it's an int, but that'll be a lot more work than parsing the arguments manually ( split() and get the last argument )
@gusty sonnet I can't user Greedy. dpy docs:
To help aid with some parsing ambiguities, str, None and Greedy are forbidden as parameters for the Greedy converter.
Yep so you need a custom Converter.
Then I suggest trying to parse manually then
@gusty sonnet it's not impossible, you just need to quote it.
if you don't want to quote it, make the genre a consume-rest argument and the amount an Optional
it's not really easy to process arguments like this otherwise, and you're left with some ugly manual processing
So, I should use *args, split them, check does last item isdigit, if is, storage and remove it and then join others back to one?
no, that's part of the ugly manually processing way
async def games(self, ctx, amount: typing.Optional[int] = 5, *, genre: str = None):
...
!games visual novel # will work
!games 10 visual novel # will also work
note: i have not looked at your code yet
Ok, thanks
seems you have genre as optional also
so you'd just give it a default i think in the above example
edited to be default None
Yes, this works now. I'll fix others too now and then I'll push
I have one problem with fuzzywuzzy: I get TypeError: expected string or bytes-like object.
My code:
possibilities = "`, `".join(process.extractBests(genre, self.genres, scorer=fuzz.ratio, score_cutoff=90))
(I used code from Python !help command command matcher)
i don't mind that you've used string templating, but why the usage of string.Template explicitly over the newer str.format templates?
Also the style of multiline strings you've got is inconsistent to typical project style.
Example, you currently have:
GAMES_LIST_BODY = Template(
textwrap.dedent("""
fields cover.image_id, first_release_date, total_rating, name, storyline, url, platforms.name, status,
involved_companies.company.name, summary, age_ratings.category, age_ratings.rating, total_rating_count;
${sort} ${limit} ${offset} ${genre} ${additional}
""")
)
body = GAMES_LIST_BODY.substitute(params)
What I'd typically expect is:
GAMES_LIST_BODY = (
"fields cover.image_id, first_release_date, total_rating, name, storyline, url, platforms.name, status, "
"involved_companies.company.name, summary, age_ratings.category, age_ratings.rating, total_rating_count; "
"{sort} {limit} {offset} {genre} {additional}"
)
body = GAMES_LIST_BODY.format(**params)
as this is using standard inbuilt methods, there's then no need to import string and textwrap
Ok
KeyError: 'Rg' 
self.genres[genre] seems pretty fragile
I use except KeyError
you're retrieving all genres from the beginning right?
and then it's just cached
you're defining self.genres outside of init also, which isn't really optimal
it's not clear it exists as an instance variable until you dig further into the code, when it should be clear within __init__
OK, I'll move this to init
you don't need to move the value assignment, just be sure to add a self.genres = None or something
however i also don't know what types are in this structure
is self.genres containing a Dict[str, int]
like ```py
{"rpg": 5}
or is it something else
Yes, this is str,int
then it might be worth adding that in the definition in init as a good form of self-documentation, so we know how to interact with it
yeah does it raise only when you typo
Ah, I don't need fuzzywuzzy. I solved this:
possibilities = "', '".join(difflib.get_close_matches(genre, self.genres, cutoff=0.4))
ok. this is only for the suggested close matches right?
As a QoL, if there is only one close match I'd consider using that, and so .game hack works just as fine, and won't require users to type the full .game hack-and-slash for it to work
using that
using what
I can add Hack as a alias of hack-and-slash
lets not add a million aliases lol
okay
shira just really likes partial matches by the sounds of it
I'll now replace string.Template to .format() and then I push
I dont really want to .game hack # Not found do you mean hack-and-slash .game slash # Not found do you mean hack-and-slash .game hack-and # Not found do you mean hack-and-slashAnd looks like difflib.get_close_matches(genre, self.genres, cutoff=0.4) returns an Iterable, so you can probably check its length ( cast to tuple / list if need be )
If there is only one match, might as well help the user
right, i understand now. sorry, the wording was ambiguous so had no idea what to apply "that" to
Yeah sorry, I was referring to the only one close match
yeah makes sense
id still only do that if the score is high enough though, as you'd end up with some weird results otherwise
OK, I'll add this too.
if it feels involved, you can leave it for another issue ticket for later improvements
this ticket looks like it's gone through a fair bit of reviewing, so i'm sure you'll likely just want to get to a state of mergeable
I'm mostly testing for functionalities now, I believe it is mergeable as soon as the issues are addressed, mainly the one where you cannot search for Visual novel
Yes, without quotes lol
I'm currently stuck with one conflict: When I want this suggest like hack and slash when you use hack, I can't use auto getting games with fixed genre, due my offcut is too small for 1 item. What should I do?
Do I remove auto refetching with correct genre now?
(And quick question: How much contributions is required to get Contributor role? 😅)
contributor role has multiple pre-requisites, not just the amount of code contributed.
regarding your string matching questions, that'll be something you have to ask shira, as it's their review that has requested it
INFRACTION_EMBED_DEFAULT.copy().description.format(**{
"type": "Warning",
"expires": "N/A",
"reason": "Test reason"
})
How should I modify this for getting embed?
To answer your question @cold moon let's take a look at get_close_matches() first
In reality, this is just calling SequenceMatcher().ratio() on each of the words in your sequence, let's test to see if it is actually doing that
!e ```py
import difflib
string = "Simulator, Tactical, Quiz/trivia, Fighting, Strategy, Adventure, Role-playing, Rpg, Shooter, Music, Indie, Turn-based-strategy, Tbs, Pinball, Puzzle, Real-time-strategy, Rts, Hack-and-slash, Visual novel, Platform, Racing, Sport, Arcade, Point-and-click"
genres = string.split(', ')
def get_top(query: str, number: int = 4) -> list:
return sorted(
((round(difflib.SequenceMatcher(None, query, genre).ratio(), 2), genre) for genre in genres),
reverse=True
)[:number]
print('hack', *get_top('hack'), sep='\n')
print('hack-and', *get_top('hack-and'), sep='\n')```
@gusty sonnet :white_check_mark: Your eval job has completed with return code 0.
001 | hack
002 | (0.4, 'Racing')
003 | (0.33, 'Tactical')
004 | (0.33, 'Hack-and-slash')
005 | (0.32, 'Point-and-click')
006 | hack-and
007 | (0.64, 'Hack-and-slash')
008 | (0.43, 'Racing')
009 | (0.38, 'Tactical')
010 | (0.35, 'Point-and-click')
Now let's try with get_close_matches()
!e ```py
import difflib
string = "Simulator, Tactical, Quiz/trivia, Fighting, Strategy, Adventure, Role-playing, Rpg, Shooter, Music, Indie, Turn-based-strategy, Tbs, Pinball, Puzzle, Real-time-strategy, Rts, Hack-and-slash, Visual novel, Platform, Racing, Sport, Arcade, Point-and-click"
genres = string.split(', ')
print('hack', difflib.get_close_matches('hack', genres), sep='\n')
print('hack-and', difflib.get_close_matches('hack-and', genres), sep='\n')
@gusty sonnet :white_check_mark: Your eval job has completed with return code 0.
001 | hack
002 | []
003 | hack-and
004 | ['Hack-and-slash']
This is pretty consistent with our finding, how do I know that, because in get_close_matches()
It has a kwarg cutoff default to 0.6
So anything with ratio above 0.6 will pass
Which is consistent with what we found above
Now, then, how do we apply this to hack and hack-and-slash case
OK, so I should to do this with SequenceMatcher?
The short answer is, you split the hack-and-slash
The long answer is, yes, if you do not want a custom algorithm, you should get around SequenceMatcher
It is the core of fuzzywuzzy as well
One idea come to my mind, is to get the max ratio of the word vs each words
Here's a very crude example of what I am thinking of
!e ```py
import difflib
import re
regex_non_alphabet = re.compile(r"[^a-z0-9]", re.IGNORECASE)
string = "Simulator, Tactical, Quiz/trivia, Fighting, Strategy, Adventure, Role-playing, Rpg, Shooter, Music, Indie, Turn-based-strategy, Tbs, Pinball, Puzzle, Real-time-strategy, Rts, Hack-and-slash, Visual novel, Platform, Racing, Sport, Arcade, Point-and-click"
genres = string.split(', ')
def get_top(query: str, number: int = 4) -> list:
results = []
for genre in genres:
ratios = [difflib.SequenceMatcher(None, query, genre).ratio()]
for word in regex_non_alphabet.split(genre):
ratios.append(difflib.SequenceMatcher(None, query, word).ratio())
results.append((round(max(ratios), 2), genre))
return sorted(results, reverse=True)[:number]
print('hack', *get_top('hack'), sep='\n')
print('hack-and', *get_top('hack-and'), sep='\n')
@gusty sonnet :white_check_mark: Your eval job has completed with return code 0.
001 | hack
002 | (0.75, 'Hack-and-slash')
003 | (0.44, 'Point-and-click')
004 | (0.4, 'Racing')
005 | (0.33, 'Tactical')
006 | hack-and
007 | (0.64, 'Hack-and-slash')
008 | (0.55, 'Point-and-click')
009 | (0.43, 'Racing')
010 | (0.38, 'Tactical')
Of course this will have its downfall
I suggest playing around with this snippet, use different query and see what fits the bill for you
OK, thanks
Maybe I should do this auto call when 1 of them have at least 0.60 ratio. When all is lower, just show possibilities
That's also one way to do it, just ask yourself, when you do .games hack and all scores are below 0.6 , what do you want it to happen
Add more test cases and try it until it feels good for you
If you are interested in it, @stable mountain has an algorithm to deal with tag name searching, it is very similar to what you are doing, but it is a custom algorithm
When all is lower than 0.6, this would just show possibilities.
Otherwise I think your current code is very close to be mergeable and so other stuff can be added later
It is totally fine to simply reply to my conversation as "I will add an issue about this for now" is fine, I mainly want to raise the issue of spaces in genres
I think this may currently best, due then I can move on Python's unit tests. I'll create issue about this after PR get merged, due I don't want ghost issue (issue for code that is really not in repo).
That is totally fine!
Any feedback https://paste.pythondiscord.com/huwujequpa.py Is these test cases enough for mod utils notify_infraction?
3 of 6 mod utils unit tests is done.
Can anyone help me with https://paste.pythondiscord.com/imawuwaqot.py ? I'm little stuck:
AssertionError: <AsyncMock name='mock.bot.api_client.post[15 chars]504'> != [{'id': 1234, 'avatar': 'test', 'name': '[66 chars]rue}]
It uses post, not get
Oh, thanks. This works now
Why are you awaiting post_user yourself?
What?
result = await post_user(*args)
With what should I replace this?
This test is for post_infraction. It should not be asserting the return value of post_user - that should have its own test(s).
- Replaced code which used the "os" module to use "pathlib".
- Using pathlib.read_text() method instead of using context manager to open a file and then reading it.
- the get_tags() method and _get_tag() methods are not async anymore.
- Storing all the file names in self._cache which is populated with the get_tags() method.```
is this commit message good?
Are there any others issues you guys have with the reddit command? If so add em here(I think we got all of them listed)
https://github.com/python-discord/seasonalbot/issues/348
You misspelled "instead"
Also, that's the body of the commit message. What's the summary?
where does the summary go?
It looks like you threw in too many unrelated changes into one commit, so it will be difficult to make a summary which covers it all.
I am using pycharm's version control panel for the first time
The first line is the summary, then a blank line, then the body.
What can be a good summary for this 🤔
That's what I mean - you have too many unrelated changes.
OK, now only 1 function left (hardest): post_infraction...
And if you want to learn more about commit messages, read this https://chris.beams.io/posts/git-commit/
thanks
is this good @tawdry vapor ?
Use "pathlib" instead of "os" module and context manager
The pathlib module simplifies opening and reading files(using Path().read_text()), hence the os module and the context manager are no longer used.```
Yes. Though it's not necessary to get so specific by mentioning read_text.
okay
Please help with https://paste.pythondiscord.com/itecejarim.py . Last case failing:
AssertionError: None != [{'id': 2, 'inserted_at': '2018-11-22T07:[154 chars]rue}]
I need fresh look
Not sure if in the issue or here... but @hardy gorge https://github.com/python-discord/bot/issues/553 mentions outdated 3.7 (and a missing word in the note ... please make sure to get ...)
Can anyone look into code? I just can't find where is this that raise exception and return None
@cold moon reset_mock doesn't reset the return value or side effects unless you explicitly tell it to
.reset_mock(side_effect=True)
That matters cause you're only conditionally setting the side effect rather than doing it for all subtests. So the side effect ends up being carried over to the next subtest.
You could reset the side effect, or you could just set the side effect always. If you give it a value of None it's effectively resetting it anyway.
Also, there's no reason to use such accurate data for the test cases. The expected_output could be "foo" and the test would be just as effective.
With the passed value expected in a result of a test, is it fine for it to just be in the string... or something like this?
("abc", f'{"abc"} is not a valid minutes duration.'),
("10d", f'{"10d"} is not a valid minutes duration.'),
Sorry, I don't understand. Can you clarify passed value expected in a result of a test?
the converter I'm testing raises a BadArgument with the passed argument being present in the error message
e.g. !command invalid_value results in BadArgument("invalid_value is invalid")
You're trying to assert the value of the error message?
I believe msg is the output message to display when an assertion fails (similar to how all other assertions use it)
If you need to filter by the error's message contents, you need to use the regex assertion
And since you can use regex, you can just include the value at the start rather than writing out the entire message.
was going off of the other tests in converters but yeah from the docs it doesn't look like the msg has much purpose beyond existing
Huh, finally is this done... tests for mod utils is done
Huh, this is not done yet...
How many coverage do you have?
Coverage report show 100%
So.. should be go?
What's confusing you, @cold moon?
We're not using an actual get method but a patched one that's part of the APIClientMock. It means that we should be able to assert if we called the get method with the appropriate payload (the user id and infraction type provided as arguments to the function) since that is essential for the implementation of this feature. Accidentally removing the user__id part, for instance, would mean that each time this function is run, we request the entire infractions database.
So, asserting that we're actually providing the right arguments to the get method here means that such a mistake can never make it's way into the actual code base in production.
You need to test that every functions got the right arguments, in order to make sure that we don’t accidentally broke a feature
Oh, now I understand
The fact that these functions are mocked make them always return the right value during testing, but what if we didn’t supplied the right arguments?
I'm not sure about every function, but this one is quite essential (and we're mocking it anyway, so it should be as simple as a reset and assert each iteration).
I tried to assert every functions in the snekbox tests, as even if a little function is broken, all the feature goes down with it
I think we should keep the level of testing reasonable; if that's a reasonable level for those functions, then it's obviously okay
However, take this utility function, it has two TRACE-level logging statements; I wouldn't test those as they are non-essential (we gain no assertion power from including them) and requiring us to test them would only serve to demotivate the developers. Mind you, if they were to be broken, the tests would fail anyway, since we'd get an uncaught exception in the test suite.
So, we don't really have to assert their contents or the call more verbosely than that
Yeah, I didn’t asserted the log either, it wouldn’t really make sense to do so
It sometimes makes sense. Say if you have an except SomeException clause with a warning/error/critical-level log, then it would be beneficial to use assertLogs to make sure we include the relevant information in the logging message.
@gusty sonnet from my testing on my dev server, which si slower than the production environment, I always get a one second delay, did it ever happened here that they were a 5 seconds delay? It seems like a lot, since the delay is actually caused by code execution delay
Adding the padding made the tests fail haha
Well, that's because the utility function returns a string
I think we should actually refactor humanize_delta in that case, do we?
Anyway, why don't we just add a rounding kwarg to humaze_delta instead?
Yes, I corrected it
There are several fairly easy methods of rounding a datetime to a unit
I mean, the same issue is happening in the reminder cog, that directly use the humanize_delta function, so we would have to duplicate the rounding code here
Instead of rounding the output, why not directly blowing up the issue at the source
I'm not sure what you mean
Are you suggesting to not change humanize_delta and instead take care of rounding at every place that calls it?
No, the opposite
I'd say adding an optional kwarg to humanize_delta with a unit to round to is far more easy to implement, maintain, and test
Right
That's what we're all suggesting then
Anyway, why don't we just add a rounding kwarg to humaze_delta instead?
@hardy gorge
The issue is because the way humanize_delta works, I remember finding it out when I was working on the reminder cog
I mean, do you want to add a rounding mechanic to humanize_delta or change the way it works?
My suggestion would be to do two thing:
- Define a help function that takes a datetime and rounds it to the provided unit
- Add an optional kwarg to humanize_delta that uses that helper function if a unit was provided
That means we can use humanize_delta with any precision we want, but still be able to round if we don't care about small fluctuations
Okay
Should seasonalbot get ’weather’ command, that fetch weather information by location?
No
Is it actually going to remain by that name?
Fair
I think the name is fine even after the deseasonification. It will still be changing our icon and banner according to what season it is, it just won't be selectively making available features.
By the way, everyone kept the @Lovefest role, it might be worth removing it
They won’t die
Maybe they'll feel a bit of love
I don't really have an opinion on changing the name of seasonalbot other than that a lot of people know it by that name and there may be external links that point to it. Changing the name seems a lot of work and may break external links (if they exist), without a lot of benefit.
it was seasonalbot before the season loading
so i see no major reason to change either
I noticed a stagnant PR so I decided to quickly apply review suggestions to get it merged. If I could get some reviews on it so it can be closed, it would be appreciated:
https://github.com/python-discord/bot/pull/643

did you want to re-review the roles pagination one ela
you requested changes, but they've been addressed
Geez dad
you don't have to though if you're busy, as i did it
i just didn't want to dismiss your review without asking first
feels rude
lol
there's a mistake lol
and yeah the fuzzy matching is annoying
we've got multiple implementations of it at this point
and i just didn't want to build one right now that's properly robust and dependable to use project-wide
I don’t think a zen of python command has to be missile defense caliber, this was supposed to be a quick thing
yep
which is kinda why i felt it's just not worth halting the pr over it
i still love the aaaaaaaaa example tho
the perfect result returns
haha
i think that kinda falls under explicit is better than implicit, if you take the original intention away 😄
Explicitly ping scragly for human parsing of the zen of python
that's probably the one "rule" i break most often
i have implicit behaviours for shitloads of stuff
the second one would probably be the only having one way to do something
i have multiple ways to do something based on the situation
¯_(ツ)_/¯
usually simple things allow for simple apis
but then i have a ton of more complex ways to do the same thing as you can control it's behaviour more
haha nice
this is interesting
i guess that's like pathlib's Path
you can arg it or / it or entire string it
what's the /// turn into 
strange situation
best_match = ""
match_index = 0
best_ratio = 0
It means that none of the matches was better than the initialization
makes sense
appeals@pythondiscord.com Maybe should this moved to constant in bot/cogs/moderation/utils.py?
why
it's not hard to just slip in another BadArgument for that one i think
ill do that now
ok
I wonder if just setting the default best_ratio to -1 works
that would give us another quasi-random result, just like the nonsense searches do
Nah, it's just a simple comparion later on best_ratio < new_ratio or something
It's not used for anything else
I think the original thing thought that at least one line was going to match above 0
Or, if we really want to have fun then just init the string to something funny
There are an infinite number of inputs that give this result by the way
Just try it with any symbol not contained in any line
+zen $$$ also works
+ is my dev prefix
i was just going to ```py
if best_match == "":
raise BadArgument("I didn't get a match! Please try again with a different search term.")
ah
saves thinking
that works
Please help with https://paste.pythondiscord.com/ejuniqahib.py . result is AsyncMock, but should bool
When you do not set a return value (or side-effect) for the ctx.send AsyncMock, it will return another AsyncMock after being awaited. (unittest.mock mock classes always return a "child mock" of their own type after being called/called+awaited.)
As you do:
if send_raise:
self.ctx.send.side_effect = send_raise
You only set something is send_raise is truthy
or is that not what's happening?
I don't have the code of the thing you're testing handy
Right, it's close, but not the send method
The coroutine you're testing will never call+await ctx.send since that happens in another coroutine you've mocked
However, since send_private_embed is mocked, await send_private_embed(user, embed) will return a new AsyncMock, which will then be returned by the notify_infraction coroutine
But how should I get value? Bool
what do you want await send_private_embed(user, embed) to return?
You should make sure you set that on send_private_embed_mock
(The mock created by the patch is passed to the method as an argument)
ok
How did I do what
did you litrelly edit the file?
?
I mean how did you commit on a PR which you have not opened
When you open a PR you allow commits from maintainers
That’s why we ask everyone to check the box
Ooo right
https://paste.pythondiscord.com/mawakoyapa.py Can anyone help me again?
AssertionError: None != [{'id': 1, 'inserted_at': '2018-11-22T07:[148 chars]lse}]
Can you paste the full traceback as well?
ok
Here is full. There is some more errors https://paste.pythondiscord.com/abuhimowuz.py
Sorry about asking so much. Just after 3 hours of work, my own code is sometimes so confusing...
I'll get back to you later; I have an appointment in five minutes
Ok
One thing that I can't quite make out is which test case is failling because the arguments you pass to subTest do not indentify that properly. They all have more or less the values.
Last error is about last case: this have datetime
2nd is 3rd case
And 1st is 2nd case
Hmm, okay
The last error you're getting is because when the previous test case raises an exception, it will not reset the mock
Since an AssertionError will break out of the subTest context manager
So, the mock is not reset, will raise an exception (side_effect is still there), which causes the actual coroutine to return None
https://github.com/python-discord/bot/issues/321 Okay, I've got a logistics question on this one. This is for automatically removing someone from the watch list if they're perma banned.
Currently we have the unwatch command, however I don't believe that just calling that command from inside a ban command would be appropriate, as it does have messages sent to the context channel and that doesn't seem like it would be useful if done in a public channel. Would it make sense then to make a separate helper function within the infractions file specifically to remove the person from the list? It doesn't feel very DRY but I'm not coming up with a decent idea off the top of my head
I don't see why you can't refactor the unwatching logic into its own method that has the ability to redirect & customize the output to a different location
So you mean just modify the command itself and tweak it to accommodate what we need it to do?
Makes sense. I'm always wary of modifying things that currently work, I guess
No, move the API interaction to its own method that the command calls
I think the real complication is making sure that an unwatch only happens for permbans, not tempbans.
If someone on bb was tempbanned, I don't think the logical step is to unwatch them.
I was considering literally just dropping the function/method call into the ban command
Since the ban and tempban are separate
We used to have an event listener, but it obviously does not discriminate as Discord has no notion of tempbanning.
Right, but it's less of an issue since they're separate commands
I can't really think of any specific reason we'd want the unwatch command to worry about where the response message is sent. The only instance where that would/should matter is for this ban autoremove
The unwatch command doesn't, the helper would
Oh that would be... the post_infraction() one?
Sorry, having to refresh myself on everything
Oh no, I get you
The helper function that we would be doing for this
We do not have more things that trigger on permban only right? It's trivial to dispatch an event for it ourselves, which allows you to just use a listener wherever needed and keep all the logic at the relevant place. I just don't think it's worth it for one listener.
Just the modlog
I don't think this needs to be any more complicated than adding an "is_auto_unwatch" flag or something to control the behavior
That's about what I figured
wait, is this channel for discord.py, or just general python project discussions?
And it needs to go in 3 places, ban, shadowban, and editing an infraction to be permanent
Last one will likely be trickier
Per the channel topic, this is for the discussions of this organization's projects
oh, my bad. wrong channel
No worries
Not really, there's already a conditional block for editing it to a permanent infraction
I don't think this needs to be any more complicated than adding an "is_auto_unwatch" flag or something to control the behavior
No I don't think so either. I was just musing about how simple it is to dispatch an event with bot.dispatch(something, *args, **kwargs) and have an on_something event listener registered. That should be all that's needed. Not worth introducing something non-standard, though.
It would certainly be cooler
True, would be neat
wait so are all u guys part of one project?
Yep yep, anyone can work on the repos
What is the repos?
You can also find the link in the channel topic
@woeful thorn Do we have an example of a command that has a flag like what we were discussing?
I'm never sure how that'd work discord commands
The command doesn't need the flag
You're calling the helper you're creating, not the command
Right got it. Sorry, I always feel like a bother
Ohhhh okay, it just actually clicked this time. It's similar to how we have the ban command but we also have the apply_ban() method
Okay, that's clicking now
The combined work of dozens of people over years
Why does that feel low
That sounds right
16855 on seasonalbot
How're you counting that
Huh, that has more than I thought
I ran tokei, I'm gonna get some more specific stats now
okay lines of python code
bot: 14122
python-challenges: 217
seasonalbot: 7644
site: 8368
snekbox: 432
Okay, so I wasn't THAT far off on my original guess
calculated with ```bash
for dir in /bin/ls; do;
echo $dir: $(tokei -t=Python $dir -o json | jq ".inner.Python.code")
done
It's about what I'd expected
Imagine if we did it with discord.js
I know that I rewrote the js bot of 15k lines into a nice, maintainable 5k in python with a load more features lol
how experienced r u guys with python
pretty experienced
How many years?
11 years myself
jfc
8 years here
I do not belong here
yeah tokei is awesome, can't remember when I got it but I've used it forever
@modest otter We all started somewhere
I was
oh
That was my first project I was actually happy with
Same actually, I picked up python and discord.py at the same time
I didn't start with a discord bot, but you can basically ignore my path
it was totally the wrong way to go
haha
Luckily I was exposed to discord.js and the discord API so it wasn't that hard
yeah. Barely have any experience with python, yet Im trying to create a bot by myself. Only asking for help from Python members
total commit counts
bot: 2579
branding: 125
seasonalbot: 1142
site: 1629
site.wiki: 44
snekbox: 321
Lurking the server definitely helped back then, so I have around 1.5 year of experience in python
whew
that's a lot of commits
I expected site to have more than bot though for some reason
And there's absolutely nothing wrong with getting help
5,840 in total
I'd have expected that as well gdude with Django rewrite but apparently not ¯_(ツ)_/¯
What should head command name? https://github.com/python-discord/seasonalbot/pull/364#pullrequestreview-369915678
The space cog
If i was you , i would seperate the commands
@clever wraith Separate them how?
No, we want them as subcommands
There's no need to have that many top-class commands for features that are very related
It would make the help command too noisy too
personal choices
Yes, I also don't really see a reason for why they should have separate top-level commands. They're all quering nasa, they're part of the same kind of functionality, and part of the same cog.
They all do similar things.
It will reduce duplicate code too
It also does not really make sense to me from a user-perspective: .pictureoftheday or .potd doesn't communicate what kind of picture of the day or where it's coming from
Something like .nasa potd/.nasa pictureoftheday does
or .space <subcommand>
Ah, I need to check something about the implementation of this command
It sometimes happen that the daily image is a video, if it is the picture I’m thinking about
And downloading and re-uploading a full video wouldn’t be very great for the network
Okay, it isn’t re-uploading, that’s fine
also its called .apod astronomy picture of the day
btw
That doesn't really make a lot of difference. The point stands that the four commands are highly related and grouping them makes sense.
By the way, any news on this issue? https://github.com/python-discord/bot/issues/769
Abstract It would be nice to have a channel tracking some of the official python mailing lists, such as python-dev@python.org. Specification A background task will make the bot fetch from an email ...
Might be also worth updating https://github.com/python-discord/bot/issues/553 now that the bot migrated to 3.8
Wasnt there an older mailing list issue?
Nope
I brought the idea up a few times, but never wrote an issue
And I couldn't find one on the repo
F***
Thanks you github search for your incompetence
I swear, mailing list didn't showed it up
Time to edit I guess
It's been discussed a lot and we had a conversation about it in the staff meeting
I'll some details from that conversation to the latest issue
I don't really mind which one we keep
Will we have this in the future?
https://discordapp.com/channels/267624335836053506/354619224620138496/607277850818641928
Probably not. We don't have regular seasonalbot events anymore. I'll keep it in the back of my mind for the Seasonal Bot-based event we're plannig for October, but it something that takes time and coordiantion to organize.
The last time we tried it no one showed up until after it had officially finished.
they weren't very successful. we didn't see more than maybe one or two people drop by during the hours we made ourselves available.
I consider it a failed event.
we'll still do ad-hoc voip stuff, though.
I think it would be cool to do some live pair programming during the event we're planning for October
It'll probably fit the theme
Still a long time to go, though
for those of you who are using PyCharm for projects with lots of unit tests, here's a cool plugin:
https://plugins.jetbrains.com/plugin/10874-git-bisect-run
Say you have a failing unit test. You run the test in PyCharm and then select that test and open the bisect window. In here, you select a revision (a commit on your branch) where you know that unit test was working, and you select a revision where the unit test is failing.
now pycharm will start bisecting.
basically it will use a logarithmic selection strategy to run that unit test on commits in the history between the good and the bad revision until it is able to narrow it down and find out exactly which commit introduced the bug.
and it does this without any intervention from you
That's pretty badass
you just go get a cup of coffee, and when you return, pycharm says "okay, this is the commit that fucked up your unit test"
and since it's logarithmic, it's very fast, even if there are thousands of commits to look through
this is of course possible through the cli as well with git bisect
and if you don't have a unit test, it's possible to test manually as well
for example, say you have a bot command that's broken. you do git bisect start . Next, you check out a commit where the problem is happening and do git bisect bad . Then you get a commit where the problem does not occur and do git bisect good . Now git starts selecting commits and checking them out for you, and you test your command, do git bisect good if the function works and bad if it fails
after a while, git will tell you which commit is responsible. takes a bit longer, but still beats trying to figure it out by just digging through history.
Git bisect, also known as "who broke my fucking tests?" - super handy, amused I never thought to look for a plugin
Wonder why the plugin doesn't have that description on it, maybe more people would use it
