Compare commits

...

13 Commits
3.3.0 ... 3.3.1

Author SHA1 Message Date
Michael H
c426aefd1a Version 3.3.1 (#3510)
* 331

* okay sphinx
2020-02-05 23:21:38 +01:00
Michael H
00cf395483 Handle deprecations in asyncio (#3509)
* passing loop to certain things was deprecated. additionally, `asyncio.get_event_loop()` is being deprecated

* awesome, checks are functioning as intended

* fun with fixtures

* we can just stop misuing that anyhow

* Update redbot/pytest/downloader.py

Co-Authored-By: jack1142 <6032823+jack1142@users.noreply.github.com>

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
2020-02-05 17:16:13 -05:00
Kowlin
61ed864e02 CI ports from Travis CI (#3435)
* Attempt 1, I suppose.

* Add the remaining 2 out of 3 jobs

* Spacing matters T_T

* So does formatting...

* More formatting fixing.

* First attempt at postgres services.

* Postgres attempt 2

* Update tests.yml

Flatten a python version I suppose.

* Update tests.yml

* Update tests.yml

* Update tests.yml

* Update tests.yml

* I wonder if this works lmao

* this is fun™

* let's go back

* add fail-fast

* Added publishing workflows

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
2020-02-05 16:02:05 -05:00
Lane Babuder
90b099395b Adding CentOS 8 Documentation (#3463)
IUS will not be supporting RHEL 8, so utilizing epel-release and telling the system to use standard git is the best option.
2020-02-03 16:57:09 -05:00
aikaterna
12e6f44135 [Core] No DMing the bot (#3478)
* [Core] No DMing the bot

* Return early if target user is a bot
2020-02-03 16:26:33 -05:00
PredaaA
e44fc69d14 [Core] Add a cli flag for setting a max size of message cache (#3474)
* Add an arg in cli to change message cache size

* Add an arg in cli to change message cache size

* Changelog

* Actually pass None in message_cache_size

* Update cli.py

* Add a cli arg to disable message cache.

* Add a cli arg to disable message cache.

* well go away you useless

* you actually are an int

* Check if message cache is higher than 0 when set it.

* Use sys.maxsize as max cache size.

* Update cli.py

* Add bot.max_messages property.

* typos

* 🤦

* style
2020-02-03 16:14:45 -05:00
jack1142
8454239a98 [Mod] Fix shorthelp for [p]modset dm (#3488)
* Update settings.py

* Update settings.py

* Create 3488.misc.rst

* Update settings.py
2020-02-03 16:14:19 -05:00
jack1142
64106c771a Allow to edit prefixes through redbot --edit (#3486)
* feat: allow to edit prefixes through `redbot --edit`

* enhance: allow to setup multiple prefixes

* fix: gotta break out of the loop

* fix: gotta sort prefixes in reversed order

* fix: editing prefix shouldn't save it as token

* fix: sort prefixes when using flag too

* chore(changelog): add towncrier entry

* docs: update help for `--edit` flag
2020-02-03 16:08:48 -05:00
jack1142
17234ac8fa Add -e flag to journalctl command in systemd guide so that it takes the user to the end of logs automatically. (#3483)
* Make journalctl's pager go to the end of logs automatically

* Aaaaaaaand changelog
2020-02-01 01:26:39 +01:00
Kowlin
b64802b92f Fix for the unknown days argument on hackban. (#3475) 2020-01-30 18:55:11 +01:00
jack1142
6fa02b1a8d [Docs] Trigger update on sudo add-apt-repository (#3464) 2020-01-27 18:41:57 -09:00
Michael H
7420df9598 let's fix this for dev testers (#3458) 2020-01-27 03:35:16 -05:00
Michael H
00bcd480e7 dev bump (#3455) 2020-01-26 20:39:38 -05:00
21 changed files with 303 additions and 59 deletions

1
.github/CODEOWNERS vendored
View File

@@ -62,3 +62,4 @@ redbot/setup.py @tekulvw
# Others # Others
.travis.yml @Kowlin .travis.yml @Kowlin
crowdin.yml @Kowlin crowdin.yml @Kowlin
.github/workflows/* @Kowlin

28
.github/workflows/publish_crowdin.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Publish to Crowdin
on:
push:
tags:
- "*"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.8'
- name: Install dependencies
run: |
curl https://artifacts.crowdin.com/repo/GPG-KEY-crowdin | sudo apt-key add -
echo "deb https://artifacts.crowdin.com/repo/deb/ /" | sudo tee -a /etc/apt/sources.list
sudo apt-get update -qq
sudo apt-get install -y crowdin
pip install redgettext==3.1
- name: Publish
env:
CROWDIN_API_KEY: ${{ secrets.crowdin_token}}
CROWDIN_PROJECT_ID: ${{ secrets.crowdin_identifier }}
run: |
make upload_translations

26
.github/workflows/publish_pypi.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Publish to PyPI
on:
push:
tags:
- "*"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.pypi_token }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*

73
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
name: Tests
on: [push, pull_request]
jobs:
tox:
runs-on: ubuntu-latest
strategy:
matrix:
python_version:
- "3.8"
tox_env:
- py
- style
- docs
include:
- tox_env: py
friendly_name: Tests
- tox_env: style
friendly_name: Style
- tox_env: docs
friendly_name: Docs
fail-fast: false
name: Tox - ${{ matrix.friendly_name }}
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python_version }}
- name: Install tox
run: |
python -m pip install --upgrade pip
pip install tox
- name: Tox test
env:
TOXENV: ${{ matrix.tox_env }}
run: tox
tox-postgres:
runs-on: ubuntu-latest
strategy:
matrix:
python_version:
- "3.8"
fail-fast: false
name: Tox - Postgres
services:
postgresql:
image: postgres:10
ports:
- 5432:5432
env:
POSTGRES_DB: red_db
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python_version }}
- name: Install tox
run: |
python -m pip install --upgrade pip
pip install tox
- name: Tox test
env:
TOXENV: postgres
PGDATABASE: red_db
PGUSER: postgres
PGPASSWORD: postgres
PGPORT: 5432
run: tox

View File

@@ -71,4 +71,4 @@ type the following command in the terminal, still by adding the instance name af
To view Reds log, you can acccess through journalctl: To view Reds log, you can acccess through journalctl:
:code:`sudo journalctl -u red@instancename` :code:`sudo journalctl -eu red@instancename`

View File

@@ -1,5 +1,39 @@
.. 3.3.x Changelogs .. 3.3.x Changelogs
Redbot 3.3.1 (2020-02-05)
=========================
Core Bot
--------
- Add a cli flag for setting a max size of message cache
- Allow to edit prefix from command line using ``redbot --edit``.
- Some functions have been changed to no longer use deprecated asyncio functions
Core Commands
-------------
- The short help text for dm has been made more useful
- dm no longer allows owners to have the bot attempt to DM itself
Utils
-----
- Passing the event loop explicitly in utils is deprecated (Removal in 3.4)
Mod Cog
-------
- Hackban now works properly without being provided a number of days
Documentation Changes
---------------------
- Add ``-e`` flag to ``journalctl`` command in systemd guide so that it takes the user to the end of logs automatically.
- Added section to install docs for CentOS 8
- Improve usage of apt update in docs
Redbot 3.3.0 (2020-01-26) Redbot 3.3.0 (2020-01-26)
========================= =========================

View File

@@ -67,6 +67,25 @@ Complete the rest of the installation by `installing Python 3.8 with pyenv <inst
---- ----
.. _install-centos8:
.. _install-rhel8:
~~~~~~~~~~~~~~~~~
CentOS and RHEL 8
~~~~~~~~~~~~~~~~~
.. code-block:: none
yum -y install epel-release
yum update -y
yum -y groupinstall development
yum -y install git zlib-devel bzip2 bzip2-devel readline-devel sqlite \
sqlite-devel openssl-devel xz xz-devel libffi-devel findutils java-11-openjdk
Complete the rest of the installation by `installing Python 3.8 with pyenv <install-python-pyenv>`.
----
.. _install-debian-stretch: .. _install-debian-stretch:
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
@@ -231,14 +250,14 @@ We recommend adding the ``git-core`` ppa to install Git 2.11 or greater:
.. code-block:: none .. code-block:: none
sudo apt update sudo apt update
sudo apt install software-properties-common sudo apt -y install software-properties-common
sudo add-apt-repository ppa:git-core/ppa sudo add-apt-repository -yu ppa:git-core/ppa
We recommend adding the ``deadsnakes`` ppa to install Python 3.8.1 or greater: We recommend adding the ``deadsnakes`` ppa to install Python 3.8.1 or greater:
.. code-block:: none .. code-block:: none
sudo add-apt-repository ppa:deadsnakes/ppa sudo add-apt-repository -yu ppa:deadsnakes/ppa
Now install the pre-requirements with apt: Now install the pre-requirements with apt:
@@ -262,8 +281,8 @@ We recommend adding the ``git-core`` ppa to install Git 2.11 or greater:
.. code-block:: none .. code-block:: none
sudo apt update sudo apt update
sudo apt install software-properties-common sudo apt -y install software-properties-common
sudo add-apt-repository ppa:git-core/ppa sudo add-apt-repository -yu ppa:git-core/ppa
Now, to install non-native version of python on non-LTS versions of Ubuntu, we recommend Now, to install non-native version of python on non-LTS versions of Ubuntu, we recommend
installing pyenv. To do this, first run the following commands: installing pyenv. To do this, first run the following commands:

View File

@@ -191,7 +191,7 @@ def _update_event_loop_policy():
_asyncio.set_event_loop_policy(_uvloop.EventLoopPolicy()) _asyncio.set_event_loop_policy(_uvloop.EventLoopPolicy())
__version__ = "3.3.0" __version__ = "3.3.1"
version_info = VersionInfo.from_str(__version__) version_info = VersionInfo.from_str(__version__)
# Filter fuzzywuzzy slow sequence matcher warning # Filter fuzzywuzzy slow sequence matcher warning

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# Discord Version check
import asyncio import asyncio
import functools import functools
import getpass import getpass
@@ -20,7 +18,7 @@ from typing import NoReturn
import discord import discord
# Set the event loop policies here so any subsequent `get_event_loop()` # Set the event loop policies here so any subsequent `new_event_loop()`
# calls, in particular those as a result of the following imports, # calls, in particular those as a result of the following imports,
# return the correct loop object. # return the correct loop object.
from redbot import _update_event_loop_policy, __version__ from redbot import _update_event_loop_policy, __version__
@@ -107,6 +105,7 @@ async def edit_instance(red, cli_flags):
no_prompt = cli_flags.no_prompt no_prompt = cli_flags.no_prompt
token = cli_flags.token token = cli_flags.token
owner = cli_flags.owner owner = cli_flags.owner
prefix = cli_flags.prefix
old_name = cli_flags.instance_name old_name = cli_flags.instance_name
new_name = cli_flags.edit_instance_name new_name = cli_flags.edit_instance_name
data_path = cli_flags.edit_data_path data_path = cli_flags.edit_data_path
@@ -119,14 +118,20 @@ async def edit_instance(red, cli_flags):
if new_name is None and confirm_overwrite: if new_name is None and confirm_overwrite:
print("--overwrite-existing-instance can't be used without --edit-instance-name argument") print("--overwrite-existing-instance can't be used without --edit-instance-name argument")
sys.exit(1) sys.exit(1)
if no_prompt and all(to_change is None for to_change in (token, owner, new_name, data_path)): if (
no_prompt
and all(to_change is None for to_change in (token, owner, new_name, data_path))
and not prefix
):
print( print(
"No arguments to edit were provided. Available arguments (check help for more " "No arguments to edit were provided."
"information): --edit-instance-name, --edit-data-path, --copy-data, --owner, --token" " Available arguments (check help for more information):"
" --edit-instance-name, --edit-data-path, --copy-data, --owner, --token, --prefix"
) )
sys.exit(1) sys.exit(1)
await _edit_token(red, token, no_prompt) await _edit_token(red, token, no_prompt)
await _edit_prefix(red, prefix, no_prompt)
await _edit_owner(red, owner, no_prompt) await _edit_owner(red, owner, no_prompt)
data = deepcopy(data_manager.basic_config) data = deepcopy(data_manager.basic_config)
@@ -152,6 +157,26 @@ async def _edit_token(red, token, no_prompt):
print("Token updated.\n") print("Token updated.\n")
async def _edit_prefix(red, prefix, no_prompt):
if prefix:
prefixes = sorted(prefix, reverse=True)
await red._config.prefix.set(prefixes)
elif not no_prompt and confirm("Would you like to change instance's prefixes?", default=False):
print(
"Enter the prefixes, separated by a space (please note "
"that prefixes containing a space will need to be added with [p]set prefix)"
)
while True:
prefixes = input("> ").strip().split()
if not prefixes:
print("You need to pass at least one prefix!")
continue
prefixes = sorted(prefixes, reverse=True)
await red._config.prefix.set(prefixes)
print("Prefixes updated.\n")
break
async def _edit_owner(red, owner, no_prompt): async def _edit_owner(red, owner, no_prompt):
if owner: if owner:
if not (15 <= len(str(owner)) <= 21): if not (15 <= len(str(owner)) <= 21):
@@ -271,7 +296,8 @@ def handle_edit(cli_flags: Namespace):
""" """
This one exists to not log all the things like it's a full run of the bot. This one exists to not log all the things like it's a full run of the bot.
""" """
loop = asyncio.get_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
data_manager.load_basic_configuration(cli_flags.instance_name) data_manager.load_basic_configuration(cli_flags.instance_name)
red = Red(cli_flags=cli_flags, description="Red V3", dm_help=None, fetch_offline_members=True) red = Red(cli_flags=cli_flags, description="Red V3", dm_help=None, fetch_offline_members=True)
try: try:
@@ -283,6 +309,7 @@ def handle_edit(cli_flags: Namespace):
print("Aborted!") print("Aborted!")
finally: finally:
loop.run_until_complete(asyncio.sleep(1)) loop.run_until_complete(asyncio.sleep(1))
asyncio.set_event_loop(None)
loop.stop() loop.stop()
loop.close() loop.close()
sys.exit(0) sys.exit(0)
@@ -433,7 +460,8 @@ def main():
handle_edit(cli_flags) handle_edit(cli_flags)
return return
try: try:
loop = asyncio.get_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
if cli_flags.no_instance: if cli_flags.no_instance:
print( print(
@@ -497,6 +525,7 @@ def main():
# results in a resource warning instead # results in a resource warning instead
log.info("Please wait, cleaning up a bit more") log.info("Please wait, cleaning up a bit more")
loop.run_until_complete(asyncio.sleep(2)) loop.run_until_complete(asyncio.sleep(2))
asyncio.set_event_loop(None)
loop.stop() loop.stop()
loop.close() loop.close()
exit_code = red._shutdown_mode if red is not None else 1 exit_code = red._shutdown_mode if red is not None else 1

View File

@@ -462,7 +462,7 @@ class Downloader(commands.Cog):
if not deps: if not deps:
await ctx.send_help() await ctx.send_help()
return return
repo = Repo("", "", "", "", Path.cwd(), loop=ctx.bot.loop) repo = Repo("", "", "", "", Path.cwd())
async with ctx.typing(): async with ctx.typing():
success = await repo.install_raw_requirements(deps, self.LIB_PATH) success = await repo.install_raw_requirements(deps, self.LIB_PATH)

View File

@@ -135,7 +135,6 @@ class Repo(RepoJSONMixin):
commit: str, commit: str,
folder_path: Path, folder_path: Path,
available_modules: Tuple[Installable, ...] = (), available_modules: Tuple[Installable, ...] = (),
loop: Optional[asyncio.AbstractEventLoop] = None,
): ):
self.url = url self.url = url
self.branch = branch self.branch = branch
@@ -154,8 +153,6 @@ class Repo(RepoJSONMixin):
self._repo_lock = asyncio.Lock() self._repo_lock = asyncio.Lock()
self._loop = loop if loop is not None else asyncio.get_event_loop()
@property @property
def clean_url(self) -> str: def clean_url(self) -> str:
"""Sanitized repo URL (with removed HTTP Basic Auth)""" """Sanitized repo URL (with removed HTTP Basic Auth)"""
@@ -529,7 +526,7 @@ class Repo(RepoJSONMixin):
env["LANGUAGE"] = "C" env["LANGUAGE"] = "C"
kwargs["env"] = env kwargs["env"] = env
async with self._repo_lock: async with self._repo_lock:
p: CompletedProcess = await self._loop.run_in_executor( p: CompletedProcess = await asyncio.get_running_loop().run_in_executor(
self._executor, self._executor,
functools.partial(sp_run, *args, stdout=PIPE, stderr=PIPE, **kwargs), functools.partial(sp_run, *args, stdout=PIPE, stderr=PIPE, **kwargs),
) )

View File

@@ -308,6 +308,9 @@ class KickBanMixin(MixinMeta):
await ctx.send_help() await ctx.send_help()
return return
if days is None:
days = await self.settings.guild(guild).default_days()
if not (0 <= days <= 7): if not (0 <= days <= 7):
await ctx.send(_("Invalid days. Must be between 0 and 7.")) await ctx.send(_("Invalid days. Must be between 0 and 7."))
return return
@@ -329,9 +332,6 @@ class KickBanMixin(MixinMeta):
await show_results() await show_results()
return return
if days is None:
days = await self.settings.guild(guild).default_days()
for user_id in user_ids: for user_id in user_ids:
user = guild.get_member(user_id) user = guild.get_member(user_id)
if user is not None: if user is not None:

View File

@@ -215,8 +215,7 @@ class ModSettings(MixinMeta):
@modset.command() @modset.command()
@commands.guild_only() @commands.guild_only()
async def dm(self, ctx: commands.Context, enabled: bool = None): async def dm(self, ctx: commands.Context, enabled: bool = None):
"""Toggle whether to send a message to a user when they are """Toggle whether a message should be sent to a user when they are kicked/banned.
kicked/banned.
If this option is enabled, the bot will attempt to DM the user with the guild name If this option is enabled, the bot will attempt to DM the user with the guild name
and reason as to why they were kicked/banned. and reason as to why they were kicked/banned.

View File

@@ -149,6 +149,12 @@ class RedBase(
if "command_not_found" not in kwargs: if "command_not_found" not in kwargs:
kwargs["command_not_found"] = "Command {} not found.\n{}" kwargs["command_not_found"] = "Command {} not found.\n{}"
message_cache_size = cli_flags.message_cache_size
if cli_flags.no_message_cache:
message_cache_size = None
kwargs["max_messages"] = message_cache_size
self._max_messages = message_cache_size
self._uptime = None self._uptime = None
self._checked_time_accuracy = None self._checked_time_accuracy = None
self._color = discord.Embed.Empty # This is needed or color ends up 0x000000 self._color = discord.Embed.Empty # This is needed or color ends up 0x000000
@@ -271,6 +277,10 @@ class RedBase(
def colour(self) -> NoReturn: def colour(self) -> NoReturn:
raise AttributeError("Please fetch the embed colour with `get_embed_colour`") raise AttributeError("Please fetch the embed colour with `get_embed_colour`")
@property
def max_messages(self) -> Optional[int]:
return self._max_messages
async def allowed_by_whitelist_blacklist( async def allowed_by_whitelist_blacklist(
self, self,
who: Optional[Union[discord.Member, discord.User]] = None, who: Optional[Union[discord.Member, discord.User]] = None,

View File

@@ -74,6 +74,22 @@ async def interactive_config(red, token_set, prefix_set, *, print_header=True):
return token return token
def positive_int(arg: str) -> int:
try:
x = int(arg)
except ValueError:
raise argparse.ArgumentTypeError("Message cache size has to be a number.")
if x < 1000:
raise argparse.ArgumentTypeError(
"Message cache size has to be greater than or equal to 1000."
)
if x > sys.maxsize:
raise argparse.ArgumentTypeError(
f"Message cache size has to be lower than or equal to {sys.maxsize}."
)
return x
def parse_cli_flags(args): def parse_cli_flags(args):
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Red - Discord Bot", usage="redbot <instance_name> [arguments]" description="Red - Discord Bot", usage="redbot <instance_name> [arguments]"
@@ -90,7 +106,7 @@ def parse_cli_flags(args):
action="store_true", action="store_true",
help="Edit the instance. This can be done without console interaction " help="Edit the instance. This can be done without console interaction "
"by passing --no-prompt and arguments that you want to change (available arguments: " "by passing --no-prompt and arguments that you want to change (available arguments: "
"--edit-instance-name, --edit-data-path, --copy-data, --owner, --token).", "--edit-instance-name, --edit-data-path, --copy-data, --owner, --token, --prefix).",
) )
parser.add_argument( parser.add_argument(
"--edit-instance-name", "--edit-instance-name",
@@ -212,6 +228,15 @@ def parse_cli_flags(args):
"all of the data on the host machine." "all of the data on the host machine."
), ),
) )
parser.add_argument(
"--message-cache-size",
type=positive_int,
default=1000,
help="Set the maximum number of messages to store in the internal message cache.",
)
parser.add_argument(
"--no-message-cache", action="store_true", help="Disable the internal message cache.",
)
args = parser.parse_args(args) args = parser.parse_args(args)

View File

@@ -1581,12 +1581,12 @@ class Core(commands.Cog, CoreLogic):
settings, 'appearance' tab. Then right click a user settings, 'appearance' tab. Then right click a user
and copy their id""" and copy their id"""
destination = discord.utils.get(ctx.bot.get_all_members(), id=user_id) destination = discord.utils.get(ctx.bot.get_all_members(), id=user_id)
if destination is None: if destination is None or destination.bot:
await ctx.send( await ctx.send(
_( _(
"Invalid ID or user not found. You can only " "Invalid ID, user not found, or user is a bot. "
"send messages to people I share a server " "You can only send messages to people I share "
"with." "a server with."
) )
) )
return return

View File

@@ -1,4 +1,5 @@
import asyncio import asyncio
import warnings
from asyncio import AbstractEventLoop, as_completed, Semaphore from asyncio import AbstractEventLoop, as_completed, Semaphore
from asyncio.futures import isfuture from asyncio.futures import isfuture
from itertools import chain from itertools import chain
@@ -177,14 +178,20 @@ def bounded_gather_iter(
TypeError TypeError
When invalid parameters are passed When invalid parameters are passed
""" """
if loop is None: if loop is not None:
loop = asyncio.get_event_loop() warnings.warn(
"Explicitly passing the loop will not work in Red 3.4+ and is currently ignored."
"Call this from the related event loop.",
DeprecationWarning,
)
loop = asyncio.get_running_loop()
if semaphore is None: if semaphore is None:
if not isinstance(limit, int) or limit <= 0: if not isinstance(limit, int) or limit <= 0:
raise TypeError("limit must be an int > 0") raise TypeError("limit must be an int > 0")
semaphore = Semaphore(limit, loop=loop) semaphore = Semaphore(limit)
pending = [] pending = []
@@ -195,7 +202,7 @@ def bounded_gather_iter(
cof = _sem_wrapper(semaphore, cof) cof = _sem_wrapper(semaphore, cof)
pending.append(cof) pending.append(cof)
return as_completed(pending, loop=loop) return as_completed(pending)
def bounded_gather( def bounded_gather(
@@ -228,15 +235,21 @@ def bounded_gather(
TypeError TypeError
When invalid parameters are passed When invalid parameters are passed
""" """
if loop is None: if loop is not None:
loop = asyncio.get_event_loop() warnings.warn(
"Explicitly passing the loop will not work in Red 3.4+ and is currently ignored."
"Call this from the related event loop.",
DeprecationWarning,
)
loop = asyncio.get_running_loop()
if semaphore is None: if semaphore is None:
if not isinstance(limit, int) or limit <= 0: if not isinstance(limit, int) or limit <= 0:
raise TypeError("limit must be an int > 0") raise TypeError("limit must be an int > 0")
semaphore = Semaphore(limit, loop=loop) semaphore = Semaphore(limit)
tasks = (_sem_wrapper(semaphore, task) for task in coros_or_futures) tasks = (_sem_wrapper(semaphore, task) for task in coros_or_futures)
return asyncio.gather(*tasks, loop=loop, return_exceptions=return_exceptions) return asyncio.gather(*tasks, return_exceptions=return_exceptions)

View File

@@ -5,6 +5,7 @@
import asyncio import asyncio
import contextlib import contextlib
import functools import functools
import warnings
from typing import Union, Iterable, Optional from typing import Union, Iterable, Optional
import discord import discord
@@ -200,7 +201,9 @@ def start_adding_reactions(
await message.add_reaction(emoji) await message.add_reaction(emoji)
if loop is None: if loop is None:
loop = asyncio.get_event_loop() loop = asyncio.get_running_loop()
else:
warnings.warn("Explicitly passing the loop will not work in Red 3.4+", DeprecationWarning)
return loop.create_task(task()) return loop.create_task(task())

View File

@@ -76,7 +76,6 @@ def bot_repo(event_loop):
commit="", commit="",
url="https://empty.com/something.git", url="https://empty.com/something.git",
folder_path=cwd, folder_path=cwd,
loop=event_loop,
) )
@@ -163,14 +162,7 @@ def _init_test_repo(destination: Path):
async def _session_git_repo(tmp_path_factory, event_loop): async def _session_git_repo(tmp_path_factory, event_loop):
# we will import repo only once once per session and duplicate the repo folder # we will import repo only once once per session and duplicate the repo folder
repo_path = tmp_path_factory.mktemp("session_git_repo") repo_path = tmp_path_factory.mktemp("session_git_repo")
repo = Repo( repo = Repo(name="redbot-testrepo", url="", branch="master", commit="", folder_path=repo_path)
name="redbot-testrepo",
url="",
branch="master",
commit="",
folder_path=repo_path,
loop=event_loop,
)
git_dirparams = _init_test_repo(repo_path) git_dirparams = _init_test_repo(repo_path)
fast_import = sp.Popen((*git_dirparams, "fast-import", "--quiet"), stdin=sp.PIPE) fast_import = sp.Popen((*git_dirparams, "fast-import", "--quiet"), stdin=sp.PIPE)
with TEST_REPO_EXPORT_PTH.open(mode="rb") as f: with TEST_REPO_EXPORT_PTH.open(mode="rb") as f:
@@ -193,7 +185,6 @@ async def git_repo(_session_git_repo, tmp_path, event_loop):
branch=_session_git_repo.branch, branch=_session_git_repo.branch,
commit=_session_git_repo.commit, commit=_session_git_repo.commit,
folder_path=repo_path, folder_path=repo_path,
loop=event_loop,
) )
return repo return repo
@@ -208,7 +199,6 @@ async def cloned_git_repo(_session_git_repo, tmp_path, event_loop):
branch=_session_git_repo.branch, branch=_session_git_repo.branch,
commit=_session_git_repo.commit, commit=_session_git_repo.commit,
folder_path=repo_path, folder_path=repo_path,
loop=event_loop,
) )
sp.run(("git", "clone", str(_session_git_repo.folder_path), str(repo_path)), check=True) sp.run(("git", "clone", str(_session_git_repo.folder_path), str(repo_path)), check=True)
return repo return repo
@@ -224,7 +214,6 @@ async def git_repo_with_remote(git_repo, tmp_path, event_loop):
branch=git_repo.branch, branch=git_repo.branch,
commit=git_repo.commit, commit=git_repo.commit,
folder_path=repo_path, folder_path=repo_path,
loop=event_loop,
) )
sp.run(("git", "clone", str(git_repo.folder_path), str(repo_path)), check=True) sp.run(("git", "clone", str(git_repo.folder_path), str(repo_path)), check=True)
return repo return repo

View File

@@ -371,8 +371,7 @@ def delete(
remove_datapath: Optional[bool], remove_datapath: Optional[bool],
): ):
"""Removes an instance.""" """Removes an instance."""
loop = asyncio.get_event_loop() asyncio.run(
loop.run_until_complete(
remove_instance( remove_instance(
instance, interactive, delete_data, _create_backup, drop_db, remove_datapath instance, interactive, delete_data, _create_backup, drop_db, remove_datapath
) )
@@ -391,14 +390,12 @@ def convert(instance, backend):
default_dirs = deepcopy(data_manager.basic_config_default) default_dirs = deepcopy(data_manager.basic_config_default)
default_dirs["DATA_PATH"] = str(Path(instance_data[instance]["DATA_PATH"])) default_dirs["DATA_PATH"] = str(Path(instance_data[instance]["DATA_PATH"]))
loop = asyncio.get_event_loop()
if current_backend == BackendType.MONGOV1: if current_backend == BackendType.MONGOV1:
raise RuntimeError("Please see the 3.2 release notes for upgrading a bot using mongo.") raise RuntimeError("Please see the 3.2 release notes for upgrading a bot using mongo.")
elif current_backend == BackendType.POSTGRES: # TODO: GH-3115 elif current_backend == BackendType.POSTGRES: # TODO: GH-3115
raise RuntimeError("Converting away from postgres isn't currently supported") raise RuntimeError("Converting away from postgres isn't currently supported")
else: else:
new_storage_details = loop.run_until_complete(do_migration(current_backend, target)) new_storage_details = asyncio.run(do_migration(current_backend, target))
if new_storage_details is not None: if new_storage_details is not None:
default_dirs["STORAGE_TYPE"] = target.value default_dirs["STORAGE_TYPE"] = target.value
@@ -422,8 +419,7 @@ def convert(instance, backend):
) )
def backup(instance: str, destination_folder: Union[str, Path]) -> None: def backup(instance: str, destination_folder: Union[str, Path]) -> None:
"""Backup instance's data.""" """Backup instance's data."""
loop = asyncio.get_event_loop() asyncio.run(create_backup(instance, Path(destination_folder)))
loop.run_until_complete(create_backup(instance, Path(destination_folder)))
def run_cli(): def run_cli():

View File

@@ -12,8 +12,10 @@ _update_event_loop_policy()
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def event_loop(request): def event_loop(request):
"""Create an instance of the default event loop for entire session.""" """Create an instance of the default event loop for entire session."""
loop = asyncio.get_event_loop_policy().new_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
yield loop yield loop
asyncio.set_event_loop(None)
loop.close() loop.close()