From 3a8da1f82bb935bbc41569e9e87b2b58b95e4100 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Sat, 22 Dec 2018 09:19:25 +1100 Subject: [PATCH 01/11] [Cleanup] Fix cleanup after Resolves #2343. Signed-off-by: Toby Harradine --- redbot/cogs/cleanup/cleanup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/redbot/cogs/cleanup/cleanup.py b/redbot/cogs/cleanup/cleanup.py index 67fcaefa7..d4b1acf6b 100644 --- a/redbot/cogs/cleanup/cleanup.py +++ b/redbot/cogs/cleanup/cleanup.py @@ -230,7 +230,6 @@ class Cleanup(commands.Cog): to_delete = await self.get_messages_for_deletion( channel=channel, number=None, after=after, delete_pinned=delete_pinned ) - to_delete.append(ctx.message) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, len(to_delete), channel.name From 2bd05a5a04eaf07796848158f793200b555be1d7 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Sat, 29 Dec 2018 10:51:31 +1100 Subject: [PATCH 02/11] Fix JSON to Mongo migration (#2346) Signed-off-by: Toby Harradine --- redbot/setup.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/redbot/setup.py b/redbot/setup.py index 10cca6362..3f93c6da4 100644 --- a/redbot/setup.py +++ b/redbot/setup.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python - +#!/usr/bin/env python3 import argparse import asyncio import json @@ -177,26 +176,21 @@ def basic_setup(): async def json_to_mongo(current_data_dir: Path, storage_details: dict): from redbot.core.drivers.red_mongo import Mongo - core_data_file = list(current_data_dir.glob("core/settings.json"))[0] - m = Mongo("Core", "0", **storage_details) + core_data_file = current_data_dir / "core" / "settings.json" + driver = Mongo(cog_name="Core", identifier="0", **storage_details) with core_data_file.open(mode="r") as f: core_data = json.loads(f.read()) - collection = m.get_collection() - await collection.update_one( - {"_id": m.unique_cog_identifier}, update={"$set": core_data["0"]}, upsert=True - ) + data = core_data.get("0", {}) + for key, value in data.items(): + await driver.set(key, value=value) for p in current_data_dir.glob("cogs/**/settings.json"): + cog_name = p.parent.stem with p.open(mode="r") as f: - cog_data = json.loads(f.read()) - cog_i = None - for ident in list(cog_data.keys()): - cog_i = str(hash(ident)) - cog_m = Mongo(p.parent.stem, cog_i, **storage_details) - cog_c = cog_m.get_collection() - for ident in list(cog_data.keys()): - await cog_c.update_one( - {"_id": cog_m.unique_cog_identifier}, update={"$set": cog_data[cog_i]}, upsert=True - ) + cog_data = json.load(f) + for identifier, data in cog_data.items(): + driver = Mongo(cog_name, identifier, **storage_details) + for key, value in data.items(): + await driver.set(key, value=value) async def mongo_to_json(current_data_dir: Path, storage_details: dict): From aa854cf1f9413c537750301bc429a302d18b5d85 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Sun, 30 Dec 2018 02:54:32 +1100 Subject: [PATCH 03/11] [CustomCom] Insert space before newline separating CC previews (#2350) Resolves #2295. Signed-off-by: Toby Harradine --- redbot/cogs/customcom/customcom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redbot/cogs/customcom/customcom.py b/redbot/cogs/customcom/customcom.py index 59990d342..14ff10cc0 100644 --- a/redbot/cogs/customcom/customcom.py +++ b/redbot/cogs/customcom/customcom.py @@ -351,7 +351,6 @@ class CustomCommands(commands.Cog): result = responses else: continue - # Replace newlines with spaces # Cut preview to 52 characters max if len(result) > 52: result = result[:49] + "..." @@ -362,7 +361,8 @@ class CustomCommands(commands.Cog): results.append((f"{ctx.clean_prefix}{command}", result)) if await ctx.embed_requested(): - content = "\n".join(map("**{0[0]}** {0[1]}".format, results)) + # We need a space before the newline incase the CC preview ends in link (GH-2295) + content = " \n".join(map("**{0[0]}** {0[1]}".format, results)) pages = list(pagify(content, page_length=1024)) embed_pages = [] for idx, page in enumerate(pages, start=1): From dde5582669cecf1b17e31f4a137eb53d0afc3d06 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Sun, 6 Jan 2019 11:02:58 +1100 Subject: [PATCH 04/11] [CogManager] Removal of implicit paths and general cleanup (#2345) - Removed memory-sided `CogManager._paths` attribute, as it has no practical use. - `[p]removepath` now removes the actual path displayed with the index specified in `[p]paths`. - New method for retreiving a deduplicated list of user-defined paths as `Path` objects - General cleanup so we don't have to do so much head-scratching next time an issue arises here Signed-off-by: Toby Harradine --- redbot/core/bot.py | 2 +- redbot/core/cog_manager.py | 106 ++++++++++++++++++------------------- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/redbot/core/bot.py b/redbot/core/bot.py index a26fd90f2..e0778f53c 100644 --- a/redbot/core/bot.py +++ b/redbot/core/bot.py @@ -111,7 +111,7 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): self.main_dir = bot_dir - self.cog_mgr = CogManager(paths=(str(self.main_dir / "cogs"),)) + self.cog_mgr = CogManager() super().__init__(*args, formatter=Help(), **kwargs) diff --git a/redbot/core/cog_manager.py b/redbot/core/cog_manager.py index f63cc42ed..08ea72a24 100644 --- a/redbot/core/cog_manager.py +++ b/redbot/core/cog_manager.py @@ -3,7 +3,7 @@ import pkgutil from importlib import import_module, invalidate_caches from importlib.machinery import ModuleSpec from pathlib import Path -from typing import Tuple, Union, List, Optional +from typing import Union, List, Optional import redbot.cogs from redbot.core.utils import deduplicate_iterables @@ -25,8 +25,6 @@ class NoSuchCog(ImportError): Different from ImportError because some ImportErrors can happen inside cogs. """ - pass - class CogManager: """Directory manager for Red's cogs. @@ -39,30 +37,27 @@ class CogManager: CORE_PATH = Path(redbot.cogs.__path__[0]) - def __init__(self, paths: Tuple[str] = ()): + def __init__(self): self.conf = Config.get_conf(self, 2938473984732, True) tmp_cog_install_path = cog_data_path(self) / "cogs" tmp_cog_install_path.mkdir(parents=True, exist_ok=True) self.conf.register_global(paths=[], install_path=str(tmp_cog_install_path)) - self._paths = [Path(p) for p in paths] - async def paths(self) -> Tuple[Path, ...]: - """Get all currently valid path directories. + async def paths(self) -> List[Path]: + """Get all currently valid path directories, in order of priority Returns ------- - `tuple` of `pathlib.Path` - All valid cog paths. + List[pathlib.Path] + A list of paths where cog packages can be found. The + install path is highest priority, followed by the + user-defined paths, and the core path has the lowest + priority. """ - conf_paths = [Path(p) for p in await self.conf.paths()] - other_paths = self._paths - - all_paths = deduplicate_iterables(conf_paths, other_paths, [self.CORE_PATH]) - - if self.install_path not in all_paths: - all_paths.insert(0, await self.install_path()) - return tuple(p.resolve() for p in all_paths if p.is_dir()) + return deduplicate_iterables( + [await self.install_path()], await self.user_defined_paths(), [self.CORE_PATH] + ) async def install_path(self) -> Path: """Get the install path for 3rd party cogs. @@ -73,8 +68,20 @@ class CogManager: The path to the directory where 3rd party cogs are stored. """ - p = Path(await self.conf.install_path()) - return p.resolve() + return Path(await self.conf.install_path()).resolve() + + async def user_defined_paths(self) -> List[Path]: + """Get a list of user-defined cog paths. + + All paths will be absolute and unique, in order of priority. + + Returns + ------- + List[pathlib.Path] + A list of user-defined paths. + + """ + return list(map(Path, deduplicate_iterables(await self.conf.paths()))) async def set_install_path(self, path: Path) -> Path: """Set the install path for 3rd party cogs. @@ -125,11 +132,10 @@ class CogManager: path = Path(path) return path - async def add_path(self, path: Union[Path, str]): + async def add_path(self, path: Union[Path, str]) -> None: """Add a cog path to current list. - This will ignore duplicates. Does have a side effect of removing all - invalid paths from the saved path list. + This will ignore duplicates. Parameters ---------- @@ -156,11 +162,12 @@ class CogManager: if path == self.CORE_PATH: raise ValueError("Cannot add the core path as an additional path.") - async with self.conf.paths() as paths: - if not any(Path(p) == path for p in paths): - paths.append(str(path)) + current_paths = await self.user_defined_paths() + if path not in current_paths: + current_paths.append(path) + await self.set_paths(current_paths) - async def remove_path(self, path: Union[Path, str]) -> Tuple[Path, ...]: + async def remove_path(self, path: Union[Path, str]) -> None: """Remove a path from the current paths list. Parameters @@ -168,20 +175,12 @@ class CogManager: path : `pathlib.Path` or `str` Path to remove. - Returns - ------- - `tuple` of `pathlib.Path` - Tuple of new valid paths. - """ path = self._ensure_path_obj(path).resolve() + paths = await self.user_defined_paths() - paths = [Path(p) for p in await self.conf.paths()] - if path in paths: - paths.remove(path) - await self.set_paths(paths) - - return tuple(paths) + paths.remove(path) + await self.set_paths(paths) async def set_paths(self, paths_: List[Path]): """Set the current paths list. @@ -192,7 +191,7 @@ class CogManager: List of paths to set. """ - str_paths = [str(p) for p in paths_] + str_paths = list(map(str, paths_)) await self.conf.paths.set(str_paths) async def _find_ext_cog(self, name: str) -> ModuleSpec: @@ -213,9 +212,9 @@ class CogManager: ------ NoSuchCog When no cog with the requested name was found. + """ - resolved_paths = await self.paths() - real_paths = [str(p) for p in resolved_paths if p != self.CORE_PATH] + real_paths = list(map(str, [await self.install_path()] + await self.user_defined_paths())) for finder, module_name, _ in pkgutil.iter_modules(real_paths): if name == module_name: @@ -287,10 +286,8 @@ class CogManager: return await self._find_core_cog(name) async def available_modules(self) -> List[str]: - """Finds the names of all available modules to load. - """ - paths = (await self.install_path(),) + await self.paths() - paths = [str(p) for p in paths] + """Finds the names of all available modules to load.""" + paths = list(map(str, await self.paths())) ret = [] for finder, module_name, _ in pkgutil.iter_modules(paths): @@ -314,13 +311,6 @@ _ = Translator("CogManagerUI", __file__) class CogManagerUI(commands.Cog): """Commands to interface with Red's cog manager.""" - @staticmethod - async def visible_paths(ctx): - install_path = await ctx.bot.cog_mgr.install_path() - cog_paths = await ctx.bot.cog_mgr.paths() - cog_paths = [p for p in cog_paths if p != install_path] - return cog_paths - @commands.command() @checks.is_owner() async def paths(self, ctx: commands.Context): @@ -330,8 +320,7 @@ class CogManagerUI(commands.Cog): cog_mgr = ctx.bot.cog_mgr install_path = await cog_mgr.install_path() core_path = cog_mgr.CORE_PATH - cog_paths = await cog_mgr.paths() - cog_paths = [p for p in cog_paths if p not in (install_path, core_path)] + cog_paths = await cog_mgr.user_defined_paths() msg = _("Install Path: {install_path}\nCore Path: {core_path}\n\n").format( install_path=install_path, core_path=core_path @@ -369,7 +358,11 @@ class CogManagerUI(commands.Cog): from !paths """ path_number -= 1 - cog_paths = await self.visible_paths(ctx) + if path_number < 0: + await ctx.send(_("Path numbers must be positive.")) + return + + cog_paths = await ctx.bot.cog_mgr.user_defined_paths() try: to_remove = cog_paths.pop(path_number) except IndexError: @@ -388,8 +381,11 @@ class CogManagerUI(commands.Cog): # Doing this because in the paths command they're 1 indexed from_ -= 1 to -= 1 + if from_ < 0 or to < 0: + await ctx.send(_("Path numbers must be positive.")) + return - all_paths = await self.visible_paths(ctx) + all_paths = await ctx.bot.cog_mgr.user_defined_paths() try: to_move = all_paths.pop(from_) except IndexError: From aac1460240bc4b8bf50cb9d48e77152252fca56d Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Thu, 10 Jan 2019 11:33:38 +1100 Subject: [PATCH 05/11] [Utils] Exit menu silently when message is deleted (#2344) Signed-off-by: Toby Harradine --- redbot/core/utils/menus.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/redbot/core/utils/menus.py b/redbot/core/utils/menus.py index 3bc72f677..b60929e09 100644 --- a/redbot/core/utils/menus.py +++ b/redbot/core/utils/menus.py @@ -73,10 +73,13 @@ async def menu( # noinspection PyAsyncCall start_adding_reactions(message, controls.keys(), ctx.bot.loop) else: - if isinstance(current_page, discord.Embed): - await message.edit(embed=current_page) - else: - await message.edit(content=current_page) + try: + if isinstance(current_page, discord.Embed): + await message.edit(embed=current_page) + else: + await message.edit(content=current_page) + except discord.NotFound: + return try: react, user = await ctx.bot.wait_for( @@ -90,9 +93,12 @@ async def menu( except discord.Forbidden: # cannot remove all reactions for key in controls.keys(): await message.remove_reaction(key, ctx.bot.user) - return None - - return await controls[react.emoji](ctx, pages, controls, message, page, timeout, react.emoji) + except discord.NotFound: + return + else: + return await controls[react.emoji]( + ctx, pages, controls, message, page, timeout, react.emoji + ) async def next_page( @@ -106,10 +112,8 @@ async def next_page( ): perms = message.channel.permissions_for(ctx.me) if perms.manage_messages: # Can manage messages, so remove react - try: + with contextlib.suppress(discord.NotFound): await message.remove_reaction(emoji, ctx.author) - except discord.NotFound: - pass if page == len(pages) - 1: page = 0 # Loop around to the first item else: @@ -128,10 +132,8 @@ async def prev_page( ): perms = message.channel.permissions_for(ctx.me) if perms.manage_messages: # Can manage messages, so remove react - try: + with contextlib.suppress(discord.NotFound): await message.remove_reaction(emoji, ctx.author) - except discord.NotFound: - pass if page == 0: page = len(pages) - 1 # Loop around to the last item else: @@ -148,9 +150,8 @@ async def close_menu( timeout: float, emoji: str, ): - if message: + with contextlib.suppress(discord.NotFound): await message.delete() - return None def start_adding_reactions( @@ -161,7 +162,7 @@ def start_adding_reactions( """Start adding reactions to a message. This is a non-blocking operation - calling this will schedule the - reactions being added, but will the calling code will continue to + reactions being added, but the calling code will continue to execute asynchronously. There is no need to await this function. This is particularly useful if you wish to start waiting for a @@ -169,7 +170,7 @@ def start_adding_reactions( this is exactly what `menu` uses to do that. This spawns a `asyncio.Task` object and schedules it on ``loop``. - If ``loop`` omitted, the loop will be retreived with + If ``loop`` omitted, the loop will be retrieved with `asyncio.get_event_loop`. Parameters From 8eb8848898a4cead19a91c51463a48c763e0ec9c Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Thu, 10 Jan 2019 11:35:37 +1100 Subject: [PATCH 06/11] [Mod] Context-based voice checks (#2351) - Removed `redbot.cogs.mod.checks` module - Moved logic for formatting a user-friendly list of permissions to `redbot.core.utils.chat_formatting` - `[p]voice(un)ban` and `[p](un)mute voice` now check permissions in the user's voice channel Resolves #2296. Signed-off-by: Toby Harradine --- redbot/cogs/mod/checks.py | 66 --------- redbot/cogs/mod/mod.py | 202 ++++++++++++++++----------- redbot/core/events.py | 11 +- redbot/core/utils/chat_formatting.py | 31 +++- 4 files changed, 152 insertions(+), 158 deletions(-) delete mode 100644 redbot/cogs/mod/checks.py diff --git a/redbot/cogs/mod/checks.py b/redbot/cogs/mod/checks.py deleted file mode 100644 index 8553695a8..000000000 --- a/redbot/cogs/mod/checks.py +++ /dev/null @@ -1,66 +0,0 @@ -from redbot.core import commands - - -def mod_or_voice_permissions(**perms): - async def pred(ctx: commands.Context): - author = ctx.author - guild = ctx.guild - if await ctx.bot.is_owner(author) or guild.owner == author: - # Author is bot owner or guild owner - return True - - admin_role = guild.get_role(await ctx.bot.db.guild(guild).admin_role()) - mod_role = guild.get_role(await ctx.bot.db.guild(guild).mod_role()) - - if admin_role in author.roles or mod_role in author.roles: - return True - - for vc in guild.voice_channels: - resolved = vc.permissions_for(author) - good = resolved.administrator or all( - getattr(resolved, name, None) == value for name, value in perms.items() - ) - if not good: - return False - else: - return True - - return commands.permissions_check(pred) - - -def admin_or_voice_permissions(**perms): - async def pred(ctx: commands.Context): - author = ctx.author - guild = ctx.guild - if await ctx.bot.is_owner(author) or guild.owner == author: - return True - admin_role = guild.get_role(await ctx.bot.db.guild(guild).admin_role()) - if admin_role in author.roles: - return True - for vc in guild.voice_channels: - resolved = vc.permissions_for(author) - good = resolved.administrator or all( - getattr(resolved, name, None) == value for name, value in perms.items() - ) - if not good: - return False - else: - return True - - return commands.permissions_check(pred) - - -def bot_has_voice_permissions(**perms): - async def pred(ctx: commands.Context): - guild = ctx.guild - for vc in guild.voice_channels: - resolved = vc.permissions_for(guild.me) - good = resolved.administrator or all( - getattr(resolved, name, None) == value for name, value in perms.items() - ) - if not good: - return False - else: - return True - - return commands.check(pred) diff --git a/redbot/cogs/mod/mod.py b/redbot/cogs/mod/mod.py index 86b61c288..8928e7514 100644 --- a/redbot/cogs/mod/mod.py +++ b/redbot/cogs/mod/mod.py @@ -2,19 +2,18 @@ import asyncio import contextlib from datetime import datetime, timedelta from collections import deque, defaultdict, namedtuple -from typing import cast +from typing import cast, Optional import discord from redbot.core import checks, Config, modlog, commands from redbot.core.bot import Red from redbot.core.i18n import Translator, cog_i18n -from redbot.core.utils.chat_formatting import box, escape -from .checks import mod_or_voice_permissions, admin_or_voice_permissions, bot_has_voice_permissions +from redbot.core.utils.chat_formatting import box, escape, format_perms_list +from redbot.core.utils.common_filters import filter_invites, filter_various_mentions from redbot.core.utils.mod import is_mod_or_superior, is_allowed_by_hierarchy, get_audit_reason from .log import log -from redbot.core.utils.common_filters import filter_invites, filter_various_mentions _ = T_ = Translator("Mod", __file__) @@ -781,15 +780,60 @@ class Mod(commands.Cog): except discord.HTTPException: return + @staticmethod + async def _voice_perm_check( + ctx: commands.Context, user_voice_state: Optional[discord.VoiceState], **perms: bool + ) -> bool: + """Check if the bot and user have sufficient permissions for voicebans. + + This also verifies that the user's voice state and connected + channel are not ``None``. + + Returns + ------- + bool + ``True`` if the permissions are sufficient and the user has + a valid voice state. + + """ + if user_voice_state is None or user_voice_state.channel is None: + await ctx.send(_("That user is not in a voice channel.")) + return False + voice_channel: discord.VoiceChannel = user_voice_state.channel + required_perms = discord.Permissions() + required_perms.update(**perms) + if not voice_channel.permissions_for(ctx.me) >= required_perms: + await ctx.send( + _("I require the {perms} permission(s) in that user's channel to do that.").format( + perms=format_perms_list(required_perms) + ) + ) + return False + if ( + ctx.permission_state is commands.PermState.NORMAL + and not voice_channel.permissions_for(ctx.author) >= required_perms + ): + await ctx.send( + _( + "You must have the {perms} permission(s) in that user's channel to use this " + "command." + ).format(perms=format_perms_list(required_perms)) + ) + return False + return True + @commands.command() @commands.guild_only() - @admin_or_voice_permissions(mute_members=True, deafen_members=True) - @bot_has_voice_permissions(mute_members=True, deafen_members=True) + @checks.admin_or_permissions(mute_members=True, deafen_members=True) async def voiceban(self, ctx: commands.Context, user: discord.Member, *, reason: str = None): """Ban a user from speaking and listening in the server's voice channels.""" - user_voice_state = user.voice - if user_voice_state is None: - await ctx.send(_("No voice state for that user!")) + user_voice_state: discord.VoiceState = user.voice + if ( + await self._voice_perm_check( + ctx, user_voice_state, deafen_members=True, mute_members=True + ) + is False + ): return needs_mute = True if user_voice_state.mute is False else False needs_deafen = True if user_voice_state.deaf is False else False @@ -824,13 +868,15 @@ class Mod(commands.Cog): @commands.command() @commands.guild_only() - @admin_or_voice_permissions(mute_members=True, deafen_members=True) - @bot_has_voice_permissions(mute_members=True, deafen_members=True) async def voiceunban(self, ctx: commands.Context, user: discord.Member, *, reason: str = None): """Unban a user from speaking and listening in the server's voice channels.""" user_voice_state = user.voice - if user_voice_state is None: - await ctx.send(_("No voice state for that user!")) + if ( + await self._voice_perm_check( + ctx, user_voice_state, deafen_members=True, mute_members=True + ) + is False + ): return needs_unmute = True if user_voice_state.mute else False needs_undeafen = True if user_voice_state.deaf else False @@ -912,47 +958,43 @@ class Mod(commands.Cog): @mute.command(name="voice") @commands.guild_only() - @mod_or_voice_permissions(mute_members=True) - @bot_has_voice_permissions(mute_members=True) async def voice_mute(self, ctx: commands.Context, user: discord.Member, *, reason: str = None): """Mute a user in their current voice channel.""" user_voice_state = user.voice + if ( + await self._voice_perm_check( + ctx, user_voice_state, mute_members=True, manage_channels=True + ) + is False + ): + return guild = ctx.guild author = ctx.author - if user_voice_state: - channel = user_voice_state.channel - if channel: - audit_reason = get_audit_reason(author, reason) + channel = user_voice_state.channel + audit_reason = get_audit_reason(author, reason) - success, issue = await self.mute_user(guild, channel, author, user, audit_reason) + success, issue = await self.mute_user(guild, channel, author, user, audit_reason) - if success: - await ctx.send( - _("Muted {user} in channel {channel.name}").format( - user=user, channel=channel - ) - ) - try: - await modlog.create_case( - self.bot, - guild, - ctx.message.created_at, - "vmute", - user, - author, - reason, - until=None, - channel=channel, - ) - except RuntimeError as e: - await ctx.send(e) - else: - await channel.send(issue) - else: - await ctx.send(_("That user is not in a voice channel right now!")) + if success: + await ctx.send( + _("Muted {user} in channel {channel.name}").format(user=user, channel=channel) + ) + try: + await modlog.create_case( + self.bot, + guild, + ctx.message.created_at, + "vmute", + user, + author, + reason, + until=None, + channel=channel, + ) + except RuntimeError as e: + await ctx.send(e) else: - await ctx.send(_("No voice state for the target!")) - return + await ctx.send(issue) @mute.command(name="channel") @commands.guild_only() @@ -1068,51 +1110,45 @@ class Mod(commands.Cog): @unmute.command(name="voice") @commands.guild_only() - @mod_or_voice_permissions(mute_members=True) - @bot_has_voice_permissions(mute_members=True) async def unmute_voice( self, ctx: commands.Context, user: discord.Member, *, reason: str = None ): """Unmute a user in their current voice channel.""" user_voice_state = user.voice + if ( + await self._voice_perm_check( + ctx, user_voice_state, mute_members=True, manage_channels=True + ) + is False + ): + return guild = ctx.guild author = ctx.author - if user_voice_state: - channel = user_voice_state.channel - if channel: - audit_reason = get_audit_reason(author, reason) + channel = user_voice_state.channel + audit_reason = get_audit_reason(author, reason) - success, message = await self.unmute_user( - guild, channel, author, user, audit_reason + success, message = await self.unmute_user(guild, channel, author, user, audit_reason) + + if success: + await ctx.send( + _("Unmuted {user} in channel {channel.name}").format(user=user, channel=channel) + ) + try: + await modlog.create_case( + self.bot, + guild, + ctx.message.created_at, + "vunmute", + user, + author, + reason, + until=None, + channel=channel, ) - - if success: - await ctx.send( - _("Unmuted {user} in channel {channel.name}").format( - user=user, channel=channel - ) - ) - try: - await modlog.create_case( - self.bot, - guild, - ctx.message.created_at, - "vunmute", - user, - author, - reason, - until=None, - channel=channel, - ) - except RuntimeError as e: - await ctx.send(e) - else: - await ctx.send(_("Unmute failed. Reason: {}").format(message)) - else: - await ctx.send(_("That user is not in a voice channel right now!")) + except RuntimeError as e: + await ctx.send(e) else: - await ctx.send(_("No voice state for the target!")) - return + await ctx.send(_("Unmute failed. Reason: {}").format(message)) @checks.mod_or_permissions(administrator=True) @unmute.command(name="channel") @@ -1334,8 +1370,8 @@ class Mod(commands.Cog): user = author # A special case for a special someone :^) - special_date = datetime(2016, 1, 10, 6, 8, 4, 443_000) - is_special = user.id == 96_130_341_705_637_888 and guild.id == 133_049_272_517_001_216 + special_date = datetime(2016, 1, 10, 6, 8, 4, 443000) + is_special = user.id == 96130341705637888 and guild.id == 133049272517001216 roles = sorted(user.roles)[1:] names, nicks = await self.get_names_and_nicks(user) diff --git a/redbot/core/events.py b/redbot/core/events.py index 427eea041..9286fb2d5 100644 --- a/redbot/core/events.py +++ b/redbot/core/events.py @@ -15,7 +15,7 @@ from pkg_resources import DistributionNotFound from . import __version__ as red_version, version_info as red_version_info, VersionInfo, commands from .data_manager import storage_type -from .utils.chat_formatting import inline, bordered, humanize_list +from .utils.chat_formatting import inline, bordered, format_perms_list from .utils import fuzzy_command_search, format_fuzzy_results log = logging.getLogger("red") @@ -234,18 +234,13 @@ def init_events(bot, cli_flags): else: await ctx.send(await format_fuzzy_results(ctx, fuzzy_commands, embed=False)) elif isinstance(error, commands.BotMissingPermissions): - missing_perms: List[str] = [] - for perm, value in error.missing: - if value is True: - perm_name = '"' + perm.replace("_", " ").title() + '"' - missing_perms.append(perm_name) - if len(missing_perms) == 1: + if bin(error.missing.value).count("1") == 1: # Only one perm missing plural = "" else: plural = "s" await ctx.send( "I require the {perms} permission{plural} to execute that command.".format( - perms=humanize_list(missing_perms), plural=plural + perms=format_perms_list(error.missing), plural=plural ) ) elif isinstance(error, commands.CheckFailure): diff --git a/redbot/core/utils/chat_formatting.py b/redbot/core/utils/chat_formatting.py index 4fea93fe8..f0fb8aa21 100644 --- a/redbot/core/utils/chat_formatting.py +++ b/redbot/core/utils/chat_formatting.py @@ -1,5 +1,8 @@ import itertools from typing import Sequence, Iterator, List + +import discord + from redbot.core.i18n import Translator _ = Translator("UtilsChatFormatting", __file__) @@ -329,7 +332,7 @@ def escape(text: str, *, mass_mentions: bool = False, formatting: bool = False) return text -def humanize_list(items: Sequence[str]): +def humanize_list(items: Sequence[str]) -> str: """Get comma-separted list, with the last element joined with *and*. This uses an Oxford comma, because without one, items containing @@ -357,3 +360,29 @@ def humanize_list(items: Sequence[str]): if len(items) == 1: return items[0] return ", ".join(items[:-1]) + _(", and ") + items[-1] + + +def format_perms_list(perms: discord.Permissions) -> str: + """Format a list of permission names. + + This will return a humanized list of the names of all enabled + permissions in the provided `discord.Permissions` object. + + Parameters + ---------- + perms : discord.Permissions + The permissions object with the requested permissions to list + enabled. + + Returns + ------- + str + The humanized list. + + """ + perm_names: List[str] = [] + for perm, value in perms: + if value is True: + perm_name = '"' + perm.replace("_", " ").title() + '"' + perm_names.append(perm_name) + return humanize_list(perm_names).replace("Guild", "Server") From 78e4b578e20994a82fbf4fc23f2d2048f4621e1a Mon Sep 17 00:00:00 2001 From: Michael H Date: Thu, 10 Jan 2019 03:46:49 -0500 Subject: [PATCH 07/11] [Utils] Tunnel minor fixes (#2366) - Tunnel uses a safe max size (Max size is related to maximum payload, not maximum file size) - Checks attachment sizes prior to download --- redbot/core/utils/tunnel.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/redbot/core/utils/tunnel.py b/redbot/core/utils/tunnel.py index 5b757543d..aedcd7474 100644 --- a/redbot/core/utils/tunnel.py +++ b/redbot/core/utils/tunnel.py @@ -2,7 +2,6 @@ import discord from datetime import datetime from redbot.core.utils.chat_formatting import pagify import io -import sys import weakref from typing import List, Optional from .common_filters import filter_mass_mentions @@ -151,15 +150,12 @@ class Tunnel(metaclass=TunnelMeta): """ files = [] - size = 0 - max_size = 8 * 1024 * 1024 - for a in m.attachments: - _fp = io.BytesIO() - await a.save(_fp) - size += sys.getsizeof(_fp) - if size > max_size: - return [] - files.append(discord.File(_fp, filename=a.filename)) + max_size = 8 * 1000 * 1000 + if m.attachments and sum(a.size for a in m.attachments) <= max_size: + for a in m.attachments: + _fp = io.BytesIO() + await a.save(_fp) + files.append(discord.File(_fp, filename=a.filename)) return files async def communicate( From 7973babe4bad8647a1f87f7729e6aedd8b5c1bb6 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Fri, 11 Jan 2019 09:07:37 +1100 Subject: [PATCH 08/11] Catch exceptions in [p]backup (#2363) Resolves #2354. Signed-off-by: Toby Harradine --- redbot/core/core_commands.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/redbot/core/core_commands.py b/redbot/core/core_commands.py index 76f17d5b9..69b5fc601 100644 --- a/redbot/core/core_commands.py +++ b/redbot/core/core_commands.py @@ -1142,6 +1142,9 @@ class Core(commands.Cog, CoreLogic): await ctx.send( _("A backup has been made of this instance. It is at {}.").format(backup_file) ) + if backup_file.stat().st_size > 8_000_000: + await ctx.send(_("This backup is to large to send via DM.")) + return await ctx.send(_("Would you like to receive a copy via DM? (y/n)")) pred = MessagePredicate.yes_or_no(ctx) @@ -1152,10 +1155,18 @@ class Core(commands.Cog, CoreLogic): else: if pred.result is True: await ctx.send(_("OK, it's on its way!")) - async with ctx.author.typing(): - await ctx.author.send( - _("Here's a copy of the backup"), file=discord.File(str(backup_file)) + try: + async with ctx.author.typing(): + await ctx.author.send( + _("Here's a copy of the backup"), + file=discord.File(str(backup_file)), + ) + except discord.Forbidden: + await ctx.send( + _("I don't seem to be able to DM you. Do you have closed DMs?") ) + except discord.HTTPException: + await ctx.send(_("I could not send the backup file.")) else: await ctx.send(_("OK then.")) else: From 9752a9c7192f013293a95928f62f5a77351d6678 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Fri, 11 Jan 2019 11:10:01 +1100 Subject: [PATCH 09/11] Bump version to 3.0.0rc3 (#2367) Also updated some dependencies, including discord.py. Signed-off-by: Toby Harradine --- .travis.yml | 2 +- Pipfile.lock | 453 +++++++++++++++++-------------- dependency_links.txt | 2 +- redbot/core/__init__.py | 2 +- redbot/core/commands/commands.py | 2 +- setup.py | 50 ++-- 6 files changed, 272 insertions(+), 239 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d5a34fd6..acab5606a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ jobs: - 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==2.1 + - pip install redgettext==2.2 deploy: - provider: script script: make gettext diff --git a/Pipfile.lock b/Pipfile.lock index cd486bdf6..69d5be9a3 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -57,11 +57,10 @@ }, "async-timeout": { "hashes": [ - "sha256:474d4bc64cee20603e225eb1ece15e248962958b45a3648a9f5cc29e827a610c", - "sha256:b3c0ddc416736619bd4a95ca31de8da6920c3b9a140c64dbef2b2fa7bf521287" + "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", + "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" ], - "markers": "python_version >= '3.5.3'", - "version": "==3.0.0" + "version": "==3.0.1" }, "attrs": { "hashes": [ @@ -79,15 +78,20 @@ }, "colorama": { "hashes": [ - "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", - "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1" + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" ], - "version": "==0.3.9" + "version": "==0.4.1" + }, + "discord-py": { + "editable": true, + "git": "git://github.com/Rapptz/discord.py", + "ref": "7f4c57dd5ad20b7fa10aea485f674a4bc24b9547" }, "discord.py": { "editable": true, "git": "git://github.com/Rapptz/discord.py", - "ref": "836ae730401ea370aa10127bb9c86854c8b516ac" + "ref": "rewrite" }, "distro": { "hashes": [ @@ -98,10 +102,10 @@ }, "dnspython": { "hashes": [ - "sha256:40f563e1f7a7b80dc5a4e76ad75c23da53d62f1e15e6e517293b04e1f84ead7c", - "sha256:861e6e58faa730f9845aaaa9c6c832851fbf89382ac52915a51f89c71accdd31" + "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01", + "sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d" ], - "version": "==1.15.0" + "version": "==1.16.0" }, "e1839a8": { "editable": true, @@ -120,10 +124,10 @@ }, "idna": { "hashes": [ - "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", - "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" ], - "version": "==2.7" + "version": "==2.8" }, "idna-ssl": { "hashes": [ @@ -140,72 +144,76 @@ }, "multidict": { "hashes": [ - "sha256:05eeab69bf2b0664644c62bd92fabb045163e5b8d4376a31dfb52ce0210ced7b", - "sha256:0c85880efa7cadb18e3b5eef0aa075dc9c0a3064cbbaef2e20be264b9cf47a64", - "sha256:136f5a4a6a4adeacc4dc820b8b22f0a378fb74f326e259c54d1817639d1d40a0", - "sha256:14906ad3347c7d03e9101749b16611cf2028547716d0840838d3c5e2b3b0f2d3", - "sha256:1ade4a3b71b1bf9e90c5f3d034a87fe4949c087ef1f6cd727fdd766fe8bbd121", - "sha256:22939a00a511a59f9ecc0158b8db728afef57975ce3782b3a265a319d05b9b12", - "sha256:2b86b02d872bc5ba5b3a4530f6a7ba0b541458ab4f7c1429a12ac326231203f7", - "sha256:3c11e92c3dfc321014e22fb442bc9eb70e01af30d6ce442026b0c35723448c66", - "sha256:4ba3bd26f282b201fdbce351f1c5d17ceb224cbedb73d6e96e6ce391b354aacc", - "sha256:4c6e78d042e93751f60672989efbd6a6bc54213ed7ff695fff82784bbb9ea035", - "sha256:4d80d1901b89cc935a6cf5b9fd89df66565272722fe2e5473168927a9937e0ca", - "sha256:4fcf71d33178a00cc34a57b29f5dab1734b9ce0f1c97fb34666deefac6f92037", - "sha256:52f7670b41d4b4d97866ebc38121de8bcb9813128b7c4942b07794d08193c0ab", - "sha256:5368e2b7649a26b7253c6c9e53241248aab9da49099442f5be238fde436f18c9", - "sha256:5bb65fbb48999044938f0c0508e929b14a9b8bf4939d8263e9ea6691f7b54663", - "sha256:60672bb5577472800fcca1ac9dae232d1461db9f20f055184be8ce54b0052572", - "sha256:669e9be6d148fc0283f53e17dd140cde4dc7c87edac8319147edd5aa2a830771", - "sha256:6a0b7a804e8d1716aa2c72e73210b48be83d25ba9ec5cf52cf91122285707bb1", - "sha256:79034ea3da3cf2a815e3e52afdc1f6c1894468c98bdce5d2546fa2342585497f", - "sha256:79247feeef6abcc11137ad17922e865052f23447152059402fc320f99ff544bb", - "sha256:81671c2049e6bf42c7fd11a060f8bc58f58b7b3d6f3f951fc0b15e376a6a5a98", - "sha256:82ac4a5cb56cc9280d4ae52c2d2ebcd6e0668dd0f9ef17f0a9d7c82bd61e24fa", - "sha256:9436267dbbaa49dad18fbbb54f85386b0f5818d055e7b8e01d219661b6745279", - "sha256:94e4140bb1343115a1afd6d84ebf8fca5fb7bfb50e1c2cbd6f2fb5d3117ef102", - "sha256:a2cab366eae8a0ffe0813fd8e335cf0d6b9bb6c5227315f53bb457519b811537", - "sha256:a596019c3eafb1b0ae07db9f55a08578b43c79adb1fe1ab1fd818430ae59ee6f", - "sha256:e8848ae3cd6a784c29fae5055028bee9bffcc704d8bcad09bd46b42b44a833e2", - "sha256:e8a048bfd7d5a280f27527d11449a509ddedf08b58a09a24314828631c099306", - "sha256:f6dd28a0ac60e2426a6918f36f1b4e2620fc785a0de7654cd206ba842eee57fd" + "sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f", + "sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3", + "sha256:045b4dd0e5f6121e6f314d81759abd2c257db4634260abcfe0d3f7083c4908ef", + "sha256:047c0a04e382ef8bd74b0de01407e8d8632d7d1b4db6f2561106af812a68741b", + "sha256:068167c2d7bbeebd359665ac4fff756be5ffac9cda02375b5c5a7c4777038e73", + "sha256:148ff60e0fffa2f5fad2eb25aae7bef23d8f3b8bdaf947a65cdbe84a978092bc", + "sha256:1d1c77013a259971a72ddaa83b9f42c80a93ff12df6a4723be99d858fa30bee3", + "sha256:1d48bc124a6b7a55006d97917f695effa9725d05abe8ee78fd60d6588b8344cd", + "sha256:31dfa2fc323097f8ad7acd41aa38d7c614dd1960ac6681745b6da124093dc351", + "sha256:34f82db7f80c49f38b032c5abb605c458bac997a6c3142e0d6c130be6fb2b941", + "sha256:3d5dd8e5998fb4ace04789d1d008e2bb532de501218519d70bb672c4c5a2fc5d", + "sha256:4a6ae52bd3ee41ee0f3acf4c60ceb3f44e0e3bc52ab7da1c2b2aa6703363a3d1", + "sha256:4b02a3b2a2f01d0490dd39321c74273fed0568568ea0e7ea23e02bd1fb10a10b", + "sha256:4b843f8e1dd6a3195679d9838eb4670222e8b8d01bc36c9894d6c3538316fa0a", + "sha256:5de53a28f40ef3c4fd57aeab6b590c2c663de87a5af76136ced519923d3efbb3", + "sha256:61b2b33ede821b94fa99ce0b09c9ece049c7067a33b279f343adfe35108a4ea7", + "sha256:6a3a9b0f45fd75dc05d8e93dc21b18fc1670135ec9544d1ad4acbcf6b86781d0", + "sha256:76ad8e4c69dadbb31bad17c16baee61c0d1a4a73bed2590b741b2e1a46d3edd0", + "sha256:7ba19b777dc00194d1b473180d4ca89a054dd18de27d0ee2e42a103ec9b7d014", + "sha256:7c1b7eab7a49aa96f3db1f716f0113a8a2e93c7375dd3d5d21c4941f1405c9c5", + "sha256:7fc0eee3046041387cbace9314926aa48b681202f8897f8bff3809967a049036", + "sha256:8ccd1c5fff1aa1427100ce188557fc31f1e0a383ad8ec42c559aabd4ff08802d", + "sha256:8e08dd76de80539d613654915a2f5196dbccc67448df291e69a88712ea21e24a", + "sha256:c18498c50c59263841862ea0501da9f2b3659c00db54abfbf823a80787fde8ce", + "sha256:c49db89d602c24928e68c0d510f4fcf8989d77defd01c973d6cbe27e684833b1", + "sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a", + "sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9", + "sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7", + "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b" ], - "version": "==4.4.2" + "version": "==4.5.2" }, "pymongo": { "hashes": [ - "sha256:08dea6dbff33363419af7af3bf2e9a373ff71eb22833dd7063f9b953f09a0bdf", - "sha256:0949110db76eb1b54cecfc0c0f8468a8b9a7fd42ba23fd0d4a37d97e0b4ca203", - "sha256:0c31a39f440801cc8603547ccaacf4cb1f02b81af6ba656621c13677b27f4426", - "sha256:1e10b3fda5677d360440ebd12a1185944dc81d9ea9acf0c6b0681013b3fb9bc2", - "sha256:1f59440b993666a417ba1954cfb1b7fb11cb4dea1a1d2777897009f688d000ee", - "sha256:2b5a3806d9f656c14e9d9b693a344fc5684fdd045155594be0c505c6e9410a94", - "sha256:4a14e2d7c2c0e07b5affcfbfc5c395d767f94bb1a822934a41a3b5371cde1458", - "sha256:4cb50541225208b37786fdb0de632e475c4f00ec4792579df551ef48d6999d69", - "sha256:52999666ad01de885653e1f74a86c2a6520d1004afec475180bebf3d7393a8fc", - "sha256:562c353079e8ce7e2ad611fd7436a72f5df97be72bca59ae9ebf789a724afd5c", - "sha256:5ce2a71f473f4703daa8d6c61a00b35ce625a7f5015b4371e3af728dafca296a", - "sha256:6613e633676168a4500e5e6bb6e3e64d3fdb96d2dc472eb4b99235fb4141adb1", - "sha256:8330406f294df118399c721f80979f2516447bcc73e4262826687872c864751e", - "sha256:8e939dfa7d16609b99eb4d1fd2fc74f7a90f4fd0aaf31d611822daaff456236f", - "sha256:8fa4303e1f50d9f0c8f2f7833b5a370a94d19d41449def62b34ae072126b4dfd", - "sha256:966d987975aa3b4cfcdf1495930ff6ecb152fafe8e544e40633e41b24ca3e1c5", - "sha256:aec4ea43a1b8e9782246a259410f66692f2d3aa0f03c54477e506193b0781cb6", - "sha256:b73f889f032fbef05863f5056b46468a8262ae83628898e20b10bbbb79a3617e", - "sha256:b752088a2f819f163d11dfdbbe627b27eef9d8478c7e57d42c5e7c600fee434e", - "sha256:c8669f96277f140797e0ff99f80bd706271674942672a38ed694e2bfa66f3900", - "sha256:ccf00549efaf6f8d5b35b654beb9aed2b788a5b33b05606eb818ddaa4e924ea3", - "sha256:ce7c91463ad21ac72fc795188292b01c8366cf625e2d1e5ed473ce127b844f60", - "sha256:d776d8d47884e6ad39ff8a301f1ae6b7d2186f209218cf024f43334dbba79c64", - "sha256:dab0f63841aebb2b421fadb31f3c7eef27898f21274a8e5b45c4f2bccb40f9ed", - "sha256:daedcfbf3b24b2b687e35b33252a9315425c2dd06a085a36906d516135bdd60e", - "sha256:e7ad1ec621db2c5ad47924f63561f75abfd4fff669c62c8cc99c169c90432f59", - "sha256:f14fb6c4058772a0d74d82874d3b89d7264d89b4ed7fa0413ea0ef8112b268b9", - "sha256:f16c7b6b98bc400d180f05e65e2236ef4ee9d71f3815280558582670e1e67536", - "sha256:f2d9eb92b26600ae6e8092f66da4bcede1b61a647c9080d6b44c148aff3a8ea4", - "sha256:ffe94f9d17800610dda5282d7f6facfc216d79a93dd728a03d2f21cff3af7cc6" + "sha256:025f94fc1e1364f00e50badc88c47f98af20012f23317234e51a11333ef986e6", + "sha256:02aa7fb282606331aefbc0586e2cf540e9dbe5e343493295e7f390936ad2738e", + "sha256:057210e831573e932702cf332012ed39da78edf0f02d24a3f0b213264a87a397", + "sha256:0d946b79c56187fe139276d4c8ed612a27a616966c8b9779d6b79e2053587c8b", + "sha256:104790893b928d310aae8a955e0bdbaa442fb0ac0a33d1bbb0741c791a407778", + "sha256:15527ef218d95a8717486106553b0d54ff2641e795b65668754e17ab9ca6e381", + "sha256:1826527a0b032f6e20e7ac7f72d7c26dd476a5e5aa82c04aa1c7088a59fded7d", + "sha256:22e3aa4ce1c3eebc7f70f9ca7fd4ce1ea33e8bdb7b61996806cd312f08f84a3a", + "sha256:244e1101e9a48615b9a16cbd194f73c115fdfefc96894803158608115f703b26", + "sha256:24b8c04fdb633a84829d03909752c385faef249c06114cc8d8e1700b95aae5c8", + "sha256:2c276696350785d3104412cbe3ac70ab1e3a10c408e7b20599ee41403a3ed630", + "sha256:2d8474dc833b1182b651b184ace997a7bd83de0f51244de988d3c30e49f07de3", + "sha256:3119b57fe1d964781e91a53e81532c85ed1701baaddec592e22f6b77a9fdf3df", + "sha256:3bee8e7e0709b0fcdaa498a3e513bde9ffc7cd09dbceb11e425bd91c89dbd5b6", + "sha256:436c071e01a464753d30dbfc8768dd93aecf2a8e378e5314d130b95e77b4d612", + "sha256:46635e3f19ad04d5a7d7cf23d232388ddbfccf46d9a3b7436b6abadda4e84813", + "sha256:4772e0b679717e7ac4608d996f57b6f380748a919b457cb05bb941467b888b22", + "sha256:4e2cd80e16f481a62c3175b607373200e714ed29025f21559ebf7524f295689f", + "sha256:52732960efa0e003ca1c092dc0a3c65276e897681287a788a01ca78dda3b41f0", + "sha256:55a7de51ec7d1731b2431886d0349146645f2816e5b8eb982d7c49f89472c9f3", + "sha256:5f8ed5934197a2d4b2087646e98de3e099a237099dcf498b9e38dd3465f74ef4", + "sha256:64b064124fcbc8eb04a155117dc4d9a336e3cda3f069958fbc44fe70c3c3d1e9", + "sha256:65958b8e4319f992e85dad59d8081888b97fcdbde5f0d14bc28f2848b92d3ef1", + "sha256:7683428862e20c6a790c19e64f8ccf487f613fbc83d47e3d532df9c81668d451", + "sha256:78566d5570c75a127c2491e343dc006798a384f06be588fe9b0cbe5595711559", + "sha256:7d1cb00c093dbf1d0b16ccf123e79dee3b82608e4a2a88947695f0460eef13ff", + "sha256:8c74e2a9b594f7962c62cef7680a4cb92a96b4e6e3c2f970790da67cc0213a7e", + "sha256:8e60aa7699170f55f4b0f56ee6f8415229777ac7e4b4b1aa41fc61eec08c1f1d", + "sha256:9447b561529576d89d3bf973e5241a88cf76e45bd101963f5236888713dea774", + "sha256:970055bfeb0be373f2f5299a3db8432444bad3bc2f198753ee6c2a3a781e0959", + "sha256:a6344b8542e584e140dc3c651d68bde51270e79490aa9320f9e708f9b2c39bd5", + "sha256:ce309ca470d747b02ba6069d286a17b7df8e9c94d10d727d9cf3a64e51d85184", + "sha256:cfbd86ed4c2b2ac71bbdbcea6669bf295def7152e3722ddd9dda94ac7981f33d", + "sha256:d7929c513732dff093481f4a0954ed5ff16816365842136b17caa0b4992e49d3" ], - "version": "==3.7.1" + "version": "==3.7.2" }, "python-levenshtein": { "hashes": [ @@ -231,10 +239,10 @@ }, "raven": { "hashes": [ - "sha256:3fd787d19ebb49919268f06f19310e8112d619ef364f7989246fc8753d469888", - "sha256:95f44f3ea2c1b176d5450df4becdb96c15bf2632888f9ab193e9dd22300ce46a" + "sha256:3fa6de6efa2493a7c827472e984ce9b020797d0da16f1db67197bcc23c8fae54", + "sha256:44a13f87670836e153951af9a3c80405d36b43097db869a36e92809673692ce4" ], - "version": "==6.9.0" + "version": "==6.10.0" }, "raven-aiohttp": { "hashes": [ @@ -280,23 +288,23 @@ "sha256:ee55eb6bcf23ecc975e6b47c127c201b913598f38b6a300075f84eeef2d3baff", "sha256:f1414e6cbcea8d22843e7eafdfdfae3dd1aba41d1945f6ca66e4806c07c4f454" ], - "markers": "python_version >= '3.4'", "version": "==6.0" }, "yarl": { "hashes": [ - "sha256:2556b779125621b311844a072e0ed367e8409a18fa12cbd68eb1258d187820f9", - "sha256:4aec0769f1799a9d4496827292c02a7b1f75c0bab56ab2b60dd94ebb57cbd5ee", - "sha256:55369d95afaacf2fa6b49c84d18b51f1704a6560c432a0f9a1aeb23f7b971308", - "sha256:6c098b85442c8fe3303e708bbb775afd0f6b29f77612e8892627bcab4b939357", - "sha256:9182cd6f93412d32e009020a44d6d170d2093646464a88aeec2aef50592f8c78", - "sha256:c8cbc21bbfa1dd7d5386d48cc814fe3d35b80f60299cdde9279046f399c3b0d8", - "sha256:db6f70a4b09cde813a4807843abaaa60f3b15fb4a2a06f9ae9c311472662daa1", - "sha256:f17495e6fe3d377e3faac68121caef6f974fcb9e046bc075bcff40d8e5cc69a4", - "sha256:f85900b9cca0c67767bb61b2b9bd53208aaa7373dae633dbe25d179b4bf38aa7" + "sha256:024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9", + "sha256:2f3010703295fbe1aec51023740871e64bb9664c789cba5a6bdf404e93f7568f", + "sha256:3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb", + "sha256:3e2724eb9af5dc41648e5bb304fcf4891adc33258c6e14e2a7414ea32541e320", + "sha256:5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842", + "sha256:73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0", + "sha256:7ab825726f2940c16d92aaec7d204cfc34ac26c0040da727cf8ba87255a33829", + "sha256:b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310", + "sha256:c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4", + "sha256:c9bb7c249c4432cd47e75af3864bc02d26c9594f49c82e2a28624417f0ae63b8", + "sha256:e060906c0c585565c718d1c3841747b61c5439af2211e185f6739a9412dfbde1" ], - "markers": "python_version >= '3.4.1'", - "version": "==1.2.6" + "version": "==1.3.0" } }, "develop": { @@ -336,10 +344,10 @@ }, "alabaster": { "hashes": [ - "sha256:674bb3bab080f598371f4443c5008cbfeb1a5e622dd312395d2d82af2c54c456", - "sha256:b63b1f4dc77c074d386752ec4a8a7517600f6c0db8cd42980cae17ab7b3275d7" + "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", + "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" ], - "version": "==0.7.11" + "version": "==0.7.12" }, "appdirs": { "hashes": [ @@ -350,18 +358,16 @@ }, "async-timeout": { "hashes": [ - "sha256:474d4bc64cee20603e225eb1ece15e248962958b45a3648a9f5cc29e827a610c", - "sha256:b3c0ddc416736619bd4a95ca31de8da6920c3b9a140c64dbef2b2fa7bf521287" + "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", + "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" ], - "markers": "python_version >= '3.5.3'", - "version": "==3.0.0" + "version": "==3.0.1" }, "atomicwrites": { "hashes": [ "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" ], - "markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.1.*'", "version": "==1.2.1" }, "attrs": { @@ -387,10 +393,10 @@ }, "certifi": { "hashes": [ - "sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638", - "sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a" + "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", + "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" ], - "version": "==2018.8.24" + "version": "==2018.11.29" }, "chardet": { "hashes": [ @@ -408,10 +414,10 @@ }, "colorama": { "hashes": [ - "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", - "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1" + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" ], - "version": "==0.3.9" + "version": "==0.4.1" }, "distro": { "hashes": [ @@ -437,6 +443,13 @@ ], "path": "." }, + "filelock": { + "hashes": [ + "sha256:b8d5ca5ca1c815e1574aee746650ea7301de63d87935b3463d26368b76e31633", + "sha256:d610c1bb404daf85976d7a82eb2ada120f04671007266b708606565dd03b5be6" + ], + "version": "==3.0.10" + }, "fuzzywuzzy": { "hashes": [ "sha256:5ac7c0b3f4658d2743aa17da53a55598144edbc5bee3c6863840636e6926f254", @@ -446,10 +459,10 @@ }, "idna": { "hashes": [ - "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", - "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" ], - "version": "==2.7" + "version": "==2.8" }, "idna-ssl": { "hashes": [ @@ -462,7 +475,6 @@ "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5" ], - "markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.1.*'", "version": "==1.1.0" }, "jinja2": { @@ -474,51 +486,78 @@ }, "markupsafe": { "hashes": [ - "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", + "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", + "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", + "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", + "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", + "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", + "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", + "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", + "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", + "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", + "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", + "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", + "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", + "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", + "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", + "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", + "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", + "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", + "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", + "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", + "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", + "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", + "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", + "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", + "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", + "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", + "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", + "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" ], - "version": "==1.0" + "version": "==1.1.0" }, "more-itertools": { "hashes": [ - "sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", - "sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", - "sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d" + "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4", + "sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc", + "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9" ], - "version": "==4.3.0" + "version": "==5.0.0" }, "multidict": { "hashes": [ - "sha256:05eeab69bf2b0664644c62bd92fabb045163e5b8d4376a31dfb52ce0210ced7b", - "sha256:0c85880efa7cadb18e3b5eef0aa075dc9c0a3064cbbaef2e20be264b9cf47a64", - "sha256:136f5a4a6a4adeacc4dc820b8b22f0a378fb74f326e259c54d1817639d1d40a0", - "sha256:14906ad3347c7d03e9101749b16611cf2028547716d0840838d3c5e2b3b0f2d3", - "sha256:1ade4a3b71b1bf9e90c5f3d034a87fe4949c087ef1f6cd727fdd766fe8bbd121", - "sha256:22939a00a511a59f9ecc0158b8db728afef57975ce3782b3a265a319d05b9b12", - "sha256:2b86b02d872bc5ba5b3a4530f6a7ba0b541458ab4f7c1429a12ac326231203f7", - "sha256:3c11e92c3dfc321014e22fb442bc9eb70e01af30d6ce442026b0c35723448c66", - "sha256:4ba3bd26f282b201fdbce351f1c5d17ceb224cbedb73d6e96e6ce391b354aacc", - "sha256:4c6e78d042e93751f60672989efbd6a6bc54213ed7ff695fff82784bbb9ea035", - "sha256:4d80d1901b89cc935a6cf5b9fd89df66565272722fe2e5473168927a9937e0ca", - "sha256:4fcf71d33178a00cc34a57b29f5dab1734b9ce0f1c97fb34666deefac6f92037", - "sha256:52f7670b41d4b4d97866ebc38121de8bcb9813128b7c4942b07794d08193c0ab", - "sha256:5368e2b7649a26b7253c6c9e53241248aab9da49099442f5be238fde436f18c9", - "sha256:5bb65fbb48999044938f0c0508e929b14a9b8bf4939d8263e9ea6691f7b54663", - "sha256:60672bb5577472800fcca1ac9dae232d1461db9f20f055184be8ce54b0052572", - "sha256:669e9be6d148fc0283f53e17dd140cde4dc7c87edac8319147edd5aa2a830771", - "sha256:6a0b7a804e8d1716aa2c72e73210b48be83d25ba9ec5cf52cf91122285707bb1", - "sha256:79034ea3da3cf2a815e3e52afdc1f6c1894468c98bdce5d2546fa2342585497f", - "sha256:79247feeef6abcc11137ad17922e865052f23447152059402fc320f99ff544bb", - "sha256:81671c2049e6bf42c7fd11a060f8bc58f58b7b3d6f3f951fc0b15e376a6a5a98", - "sha256:82ac4a5cb56cc9280d4ae52c2d2ebcd6e0668dd0f9ef17f0a9d7c82bd61e24fa", - "sha256:9436267dbbaa49dad18fbbb54f85386b0f5818d055e7b8e01d219661b6745279", - "sha256:94e4140bb1343115a1afd6d84ebf8fca5fb7bfb50e1c2cbd6f2fb5d3117ef102", - "sha256:a2cab366eae8a0ffe0813fd8e335cf0d6b9bb6c5227315f53bb457519b811537", - "sha256:a596019c3eafb1b0ae07db9f55a08578b43c79adb1fe1ab1fd818430ae59ee6f", - "sha256:e8848ae3cd6a784c29fae5055028bee9bffcc704d8bcad09bd46b42b44a833e2", - "sha256:e8a048bfd7d5a280f27527d11449a509ddedf08b58a09a24314828631c099306", - "sha256:f6dd28a0ac60e2426a6918f36f1b4e2620fc785a0de7654cd206ba842eee57fd" + "sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f", + "sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3", + "sha256:045b4dd0e5f6121e6f314d81759abd2c257db4634260abcfe0d3f7083c4908ef", + "sha256:047c0a04e382ef8bd74b0de01407e8d8632d7d1b4db6f2561106af812a68741b", + "sha256:068167c2d7bbeebd359665ac4fff756be5ffac9cda02375b5c5a7c4777038e73", + "sha256:148ff60e0fffa2f5fad2eb25aae7bef23d8f3b8bdaf947a65cdbe84a978092bc", + "sha256:1d1c77013a259971a72ddaa83b9f42c80a93ff12df6a4723be99d858fa30bee3", + "sha256:1d48bc124a6b7a55006d97917f695effa9725d05abe8ee78fd60d6588b8344cd", + "sha256:31dfa2fc323097f8ad7acd41aa38d7c614dd1960ac6681745b6da124093dc351", + "sha256:34f82db7f80c49f38b032c5abb605c458bac997a6c3142e0d6c130be6fb2b941", + "sha256:3d5dd8e5998fb4ace04789d1d008e2bb532de501218519d70bb672c4c5a2fc5d", + "sha256:4a6ae52bd3ee41ee0f3acf4c60ceb3f44e0e3bc52ab7da1c2b2aa6703363a3d1", + "sha256:4b02a3b2a2f01d0490dd39321c74273fed0568568ea0e7ea23e02bd1fb10a10b", + "sha256:4b843f8e1dd6a3195679d9838eb4670222e8b8d01bc36c9894d6c3538316fa0a", + "sha256:5de53a28f40ef3c4fd57aeab6b590c2c663de87a5af76136ced519923d3efbb3", + "sha256:61b2b33ede821b94fa99ce0b09c9ece049c7067a33b279f343adfe35108a4ea7", + "sha256:6a3a9b0f45fd75dc05d8e93dc21b18fc1670135ec9544d1ad4acbcf6b86781d0", + "sha256:76ad8e4c69dadbb31bad17c16baee61c0d1a4a73bed2590b741b2e1a46d3edd0", + "sha256:7ba19b777dc00194d1b473180d4ca89a054dd18de27d0ee2e42a103ec9b7d014", + "sha256:7c1b7eab7a49aa96f3db1f716f0113a8a2e93c7375dd3d5d21c4941f1405c9c5", + "sha256:7fc0eee3046041387cbace9314926aa48b681202f8897f8bff3809967a049036", + "sha256:8ccd1c5fff1aa1427100ce188557fc31f1e0a383ad8ec42c559aabd4ff08802d", + "sha256:8e08dd76de80539d613654915a2f5196dbccc67448df291e69a88712ea21e24a", + "sha256:c18498c50c59263841862ea0501da9f2b3659c00db54abfbf823a80787fde8ce", + "sha256:c49db89d602c24928e68c0d510f4fcf8989d77defd01c973d6cbe27e684833b1", + "sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a", + "sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9", + "sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7", + "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b" ], - "version": "==4.4.2" + "version": "==4.5.2" }, "packaging": { "hashes": [ @@ -529,48 +568,45 @@ }, "pluggy": { "hashes": [ - "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", - "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" + "sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616", + "sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a" ], - "markers": "python_version != '3.0.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*'", - "version": "==0.7.1" + "version": "==0.8.1" }, "py": { "hashes": [ - "sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1", - "sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6" + "sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", + "sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6" ], - "markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.1.*'", - "version": "==1.6.0" + "version": "==1.7.0" }, "pygments": { "hashes": [ - "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", - "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" + "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", + "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d" ], - "version": "==2.2.0" + "version": "==2.3.1" }, "pyparsing": { "hashes": [ - "sha256:bc6c7146b91af3f567cf6daeaec360bc07d45ffec4cf5353f4d7a208ce7ca30a", - "sha256:d29593d8ebe7b57d6967b62494f8c72b03ac0262b1eed63826c6f788b3606401" + "sha256:40856e74d4987de5d01761a22d1621ae1c7f8774585acae358aa5c5936c6c90b", + "sha256:f353aab21fd474459d97b709e527b5571314ee5f067441dc9f88e33eecd96592" ], - "version": "==2.2.2" + "version": "==2.3.0" }, "pytest": { "hashes": [ - "sha256:7e258ee50338f4e46957f9e09a0f10fb1c2d05493fa901d113a8dafd0790de4e", - "sha256:9332147e9af2dcf46cd7ceb14d5acadb6564744ddff1fe8c17f0ce60ece7d9a2" + "sha256:3e65a22eb0d4f1bdbc1eacccf4a3198bf8d4049dea5112d70a0c61b00e748d02", + "sha256:5924060b374f62608a078494b909d341720a050b5224ff87e17e12377486a71d" ], - "version": "==3.8.2" + "version": "==4.1.0" }, "pytest-asyncio": { "hashes": [ - "sha256:a962e8e1b6ec28648c8fe214edab4e16bacdb37b52df26eb9d63050af309b2a9", - "sha256:fbd92c067c16111174a1286bfb253660f1e564e5146b39eeed1133315cf2c2cf" + "sha256:9fac5100fd716cbecf6ef89233e8590a4ad61d729d1732e0a96b84182df1daaf", + "sha256:d734718e25cfc32d2bf78d346e99d33724deeba774cc4afdf491530c6184b63b" ], - "markers": "python_version != '3.0.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*'", - "version": "==0.9.0" + "version": "==0.10.0" }, "python-levenshtein": { "hashes": [ @@ -580,10 +616,10 @@ }, "pytz": { "hashes": [ - "sha256:a061aa0a9e06881eb8b3b2b43f05b9439d6583c206d0a6c340ff72a7b6669053", - "sha256:ffb9ef1de172603304d9d2819af6f5ece76f2e85ec10692a524dd876e72bf277" + "sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9", + "sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c" ], - "version": "==2018.5" + "version": "==2018.9" }, "pyyaml": { "hashes": [ @@ -603,10 +639,10 @@ }, "raven": { "hashes": [ - "sha256:3fd787d19ebb49919268f06f19310e8112d619ef364f7989246fc8753d469888", - "sha256:95f44f3ea2c1b176d5450df4becdb96c15bf2632888f9ab193e9dd22300ce46a" + "sha256:3fa6de6efa2493a7c827472e984ce9b020797d0da16f1db67197bcc23c8fae54", + "sha256:44a13f87670836e153951af9a3c80405d36b43097db869a36e92809673692ce4" ], - "version": "==6.9.0" + "version": "==6.10.0" }, "raven-aiohttp": { "hashes": [ @@ -617,10 +653,10 @@ }, "requests": { "hashes": [ - "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", - "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a" + "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", + "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" ], - "version": "==2.19.1" + "version": "==2.21.0" }, "schema": { "hashes": [ @@ -631,10 +667,10 @@ }, "six": { "hashes": [ - "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", - "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" ], - "version": "==1.11.0" + "version": "==1.12.0" }, "snowballstemmer": { "hashes": [ @@ -645,17 +681,17 @@ }, "sphinx": { "hashes": [ - "sha256:217a7705adcb573da5bbe1e0f5cab4fa0bd89fd9342c9159121746f593c2d5a4", - "sha256:a602513f385f1d5785ff1ca420d9c7eb1a1b63381733b2f0ea8188a391314a86" + "sha256:429e3172466df289f0f742471d7e30ba3ee11f3b5aecd9a840480d03f14bcfe5", + "sha256:c4cb17ba44acffae3d3209646b6baec1e215cad3065e852c68cc569d4df1b9f8" ], - "version": "==1.7.9" + "version": "==1.8.3" }, "sphinx-rtd-theme": { "hashes": [ - "sha256:3b49758a64f8a1ebd8a33cb6cc9093c3935a908b716edfaa5772fd86aac27ef6", - "sha256:80e01ec0eb711abacb1fa507f3eae8b805ae8fa3e8b057abfdf497e3f644c82c" + "sha256:02f02a676d6baabb758a20c7a479d58648e0f64f13e07d1b388e9bb2afe86a09", + "sha256:d0f6bc70f98961145c5b0e26a992829363a197321ba571b31b24ea91879e0c96" ], - "version": "==0.4.1" + "version": "==0.4.2" }, "sphinxcontrib-asyncio": { "hashes": [ @@ -668,39 +704,36 @@ "sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd", "sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9" ], - "markers": "python_version != '3.0.*' and python_version != '3.3.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*'", "version": "==1.1.0" }, "toml": { "hashes": [ - "sha256:380178cde50a6a79f9d2cf6f42a62a5174febe5eea4126fe4038785f1d888d42", - "sha256:a7901919d3e4f92ffba7ff40a9d697e35bbbc8a8049fe8da742f34c83606d957" + "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", + "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" ], - "version": "==0.9.6" + "version": "==0.10.0" }, "tox": { "hashes": [ - "sha256:7f802b37fffd3b5ef2aab104943fa5dad24bf9564bb7e732e54b8d0cfec2fca0", - "sha256:cc97859bd7f38aa5b3b8ba55ffe7ee9952e7050faad1aedc0829cd3db2fb61d6" + "sha256:2a8d8a63660563e41e64e3b5b677e81ce1ffa5e2a93c2c565d3768c287445800", + "sha256:edfca7809925f49bdc110d0a2d9966bbf35a0c25637216d9586e7a5c5de17bfb" ], "index": "pypi", - "version": "==3.4.0" + "version": "==3.6.1" }, "urllib3": { "hashes": [ - "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", - "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" ], - "markers": "python_version != '3.0.*' and python_version != '3.3.*' and python_version != '3.2.*' and python_version < '4' and python_version >= '2.6' and python_version != '3.1.*'", - "version": "==1.23" + "version": "==1.24.1" }, "virtualenv": { "hashes": [ - "sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669", - "sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752" + "sha256:34b9ae3742abed2f95d3970acf4d80533261d6061b51160b197f84e5b4c98b4c", + "sha256:fa736831a7b18bd2bfeef746beb622a92509e9733d645952da136b0639cd40cd" ], - "markers": "python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.1.*'", - "version": "==16.0.0" + "version": "==16.2.0" }, "websockets": { "hashes": [ @@ -726,23 +759,23 @@ "sha256:ee55eb6bcf23ecc975e6b47c127c201b913598f38b6a300075f84eeef2d3baff", "sha256:f1414e6cbcea8d22843e7eafdfdfae3dd1aba41d1945f6ca66e4806c07c4f454" ], - "markers": "python_version >= '3.4'", "version": "==6.0" }, "yarl": { "hashes": [ - "sha256:2556b779125621b311844a072e0ed367e8409a18fa12cbd68eb1258d187820f9", - "sha256:4aec0769f1799a9d4496827292c02a7b1f75c0bab56ab2b60dd94ebb57cbd5ee", - "sha256:55369d95afaacf2fa6b49c84d18b51f1704a6560c432a0f9a1aeb23f7b971308", - "sha256:6c098b85442c8fe3303e708bbb775afd0f6b29f77612e8892627bcab4b939357", - "sha256:9182cd6f93412d32e009020a44d6d170d2093646464a88aeec2aef50592f8c78", - "sha256:c8cbc21bbfa1dd7d5386d48cc814fe3d35b80f60299cdde9279046f399c3b0d8", - "sha256:db6f70a4b09cde813a4807843abaaa60f3b15fb4a2a06f9ae9c311472662daa1", - "sha256:f17495e6fe3d377e3faac68121caef6f974fcb9e046bc075bcff40d8e5cc69a4", - "sha256:f85900b9cca0c67767bb61b2b9bd53208aaa7373dae633dbe25d179b4bf38aa7" + "sha256:024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9", + "sha256:2f3010703295fbe1aec51023740871e64bb9664c789cba5a6bdf404e93f7568f", + "sha256:3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb", + "sha256:3e2724eb9af5dc41648e5bb304fcf4891adc33258c6e14e2a7414ea32541e320", + "sha256:5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842", + "sha256:73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0", + "sha256:7ab825726f2940c16d92aaec7d204cfc34ac26c0040da727cf8ba87255a33829", + "sha256:b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310", + "sha256:c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4", + "sha256:c9bb7c249c4432cd47e75af3864bc02d26c9594f49c82e2a28624417f0ae63b8", + "sha256:e060906c0c585565c718d1c3841747b61c5439af2211e185f6739a9412dfbde1" ], - "markers": "python_version >= '3.4.1'", - "version": "==1.2.6" + "version": "==1.3.0" } } } diff --git a/dependency_links.txt b/dependency_links.txt index 791ce4d0c..c05bff902 100644 --- a/dependency_links.txt +++ b/dependency_links.txt @@ -1 +1 @@ -https://github.com/Rapptz/discord.py/tarball/836ae730401ea370aa10127bb9c86854c8b516ac#egg=discord.py-1.0.0a0 +https://github.com/Rapptz/discord.py/tarball/7f4c57dd5ad20b7fa10aea485f674a4bc24b9547#egg=discord.py-1.0.0a0 diff --git a/redbot/core/__init__.py b/redbot/core/__init__.py index d3b2c08b3..1f02d4df6 100644 --- a/redbot/core/__init__.py +++ b/redbot/core/__init__.py @@ -148,5 +148,5 @@ class VersionInfo: ) -__version__ = "3.0.0rc2" +__version__ = "3.0.0rc3" version_info = VersionInfo.from_str(__version__) diff --git a/redbot/core/commands/commands.py b/redbot/core/commands/commands.py index 0c0a77323..ea37af87a 100644 --- a/redbot/core/commands/commands.py +++ b/redbot/core/commands/commands.py @@ -145,7 +145,7 @@ class Command(CogCommandMixin, commands.Command): @property def parents(self) -> List["Group"]: - """List[Group] : Returns all parent commands of this command. + """List[commands.Group] : Returns all parent commands of this command. This is sorted by the length of :attr:`.qualified_name` from highest to lowest. If the command has no parents, this will be an empty list. diff --git a/setup.py b/setup.py index 22b92a58b..0c463f01a 100644 --- a/setup.py +++ b/setup.py @@ -9,59 +9,59 @@ install_requires = [ "aiohttp-json-rpc==0.11.2", "aiohttp==3.4.4", "appdirs==1.4.3", - "async-timeout==3.0.0", + "async-timeout==3.0.1", "attrs==18.2.0", "chardet==3.0.4", - "colorama==0.3.9", + "colorama==0.4.1", "discord.py>=1.0.0a0", "distro==1.3.0; sys_platform == 'linux'", "fuzzywuzzy==0.17.0", "idna-ssl==1.1.0", - "idna==2.7", - "multidict==4.4.2", + "idna==2.8", + "multidict==4.5.2", "python-levenshtein==0.12.0", "pyyaml==3.13", - "raven==6.9.0", + "raven==6.10.0", "raven-aiohttp==0.7.0", "schema==0.6.8", "websockets==6.0", - "yarl==1.2.6", + "yarl==1.3.0", ] extras_require = { "test": [ "atomicwrites==1.2.1", - "more-itertools==4.3.0", - "pluggy==0.7.1", - "py==1.6.0", - "pytest==3.8.2", - "pytest-asyncio==0.9.0", - "six==1.11.0", + "more-itertools==5.0.0", + "pluggy==0.8.1", + "py==1.7.0", + "pytest==4.1.0", + "pytest-asyncio==0.10.0", + "six==1.12.0", ], - "mongo": ["motor==2.0.0", "pymongo==3.7.1", "dnspython==1.15.0"], + "mongo": ["motor==2.0.0", "pymongo==3.7.2", "dnspython==1.16.0"], "docs": [ - "alabaster==0.7.11", + "alabaster==0.7.12", "babel==2.6.0", - "certifi==2018.8.24", + "certifi==2018.11.29", "docutils==0.14", "imagesize==1.1.0", "Jinja2==2.10", - "MarkupSafe==1.0", + "MarkupSafe==1.1.0", "packaging==18.0", - "pyparsing==2.2.2", - "Pygments==2.2.0", - "pytz==2018.5", - "requests==2.19.1", - "urllib3==1.23", - "six==1.11.0", + "pyparsing==2.3.0", + "Pygments==2.3.1", + "pytz==2018.9", + "requests==2.21.0", + "six==1.12.0", "snowballstemmer==1.2.1", - "sphinx==1.7.9", - "sphinx_rtd_theme==0.4.1", + "sphinx==1.8.3", + "sphinx_rtd_theme==0.4.2", "sphinxcontrib-asyncio==0.2.0", "sphinxcontrib-websupport==1.1.0", + "urllib3==1.24.1", ], "voice": ["red-lavalink==0.1.2"], - "style": ["black==18.9b0", "click==7.0", "toml==0.9.6"], + "style": ["black==18.9b0", "click==7.0", "toml==0.10.0"], } python_requires = ">=3.6.2,<3.8" From 1bb5d698ccee89bac5c8c96e36e5bea75a4428d3 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Fri, 11 Jan 2019 13:04:00 +1100 Subject: [PATCH 10/11] Make Travis only do py36 tox when deploying Signed-off-by: Toby Harradine --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index acab5606a..2d83eccff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ jobs: python: 3.6.6 env: - DEPLOYING=true + - TOXENV=py36 deploy: - provider: pypi user: Red-DiscordBot @@ -49,6 +50,7 @@ jobs: python: 3.6.6 env: - DEPLOYING=true + - TOXENV=py36 before_deploy: - 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 From 32bd47e105c0d3038f381acf0f3bc6a3179ec5dc Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Fri, 11 Jan 2019 13:09:40 +1100 Subject: [PATCH 11/11] Bump version to 3.0.0rc3.post1 Signed-off-by: Toby Harradine --- redbot/core/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redbot/core/__init__.py b/redbot/core/__init__.py index 1f02d4df6..049f4e4a5 100644 --- a/redbot/core/__init__.py +++ b/redbot/core/__init__.py @@ -148,5 +148,5 @@ class VersionInfo: ) -__version__ = "3.0.0rc3" +__version__ = "3.0.0rc3.post1" version_info = VersionInfo.from_str(__version__)