From 7049a0052b375d8fa28288ab8ca63f7b99c069ed Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Thu, 8 Jul 2021 13:52:28 +0200 Subject: Create `join_role_stats` function in helpers Add `join_role_stats` function that joins the relevant information (number of members) of the given roles into one group under a pre-specified `name` --- bot/utils/helpers.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bot/utils/helpers.py b/bot/utils/helpers.py index 3501a3933..1da5da5a3 100644 --- a/bot/utils/helpers.py +++ b/bot/utils/helpers.py @@ -1,6 +1,8 @@ from abc import ABCMeta -from typing import Optional +from types import List +from typing import Dict, Optional +from discord import Guild from discord.ext.commands import CogMeta @@ -30,3 +32,11 @@ def has_lines(string: str, count: int) -> bool: def pad_base64(data: str) -> str: """Return base64 `data` with padding characters to ensure its length is a multiple of 4.""" return data + "=" * (-len(data) % 4) + + +def join_role_stats(role_ids: List[int], name: str, guild: Guild) -> Dict[str, int]: + """Return a dict object with the number of `members` of each role given, and the `name` for this joined group.""" + members = [] + for role_id in role_ids: + members += guild.get_role(role_id).members + return {name: len(set(members))} -- cgit v1.2.3 From a8e30f6c67cd64a5cf5a1ab0b3668a06a9621485 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Thu, 8 Jul 2021 13:53:48 +0200 Subject: Add `Leads` role(s) to the server information embed --- bot/exts/info/information.py | 7 ++++++- bot/utils/helpers.py | 3 +-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index 1b1243118..677b5d1f7 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -17,8 +17,10 @@ from bot.decorators import in_whitelist from bot.pagination import LinePaginator from bot.utils.channel import is_mod_channel, is_staff_channel from bot.utils.checks import cooldown_with_role_bypass, has_no_roles_check, in_whitelist_check +from bot.utils.helpers import join_role_stats from bot.utils.time import humanize_delta, time_since + log = logging.getLogger(__name__) @@ -50,7 +52,10 @@ class Information(Cog): constants.Roles.owners, constants.Roles.contributors, ) ) - return {role.name.title(): len(role.members) for role in roles} + role_stats = {role.name.title(): len(role.members) for role in roles} + role_stats.update( + **join_role_stats([constants.Roles.project_leads, constants.Roles.domain_leads], "Leads", guild)) + return role_stats def get_extended_server_info(self, ctx: Context) -> str: """Return additional server info only visible in moderation channels.""" diff --git a/bot/utils/helpers.py b/bot/utils/helpers.py index 1da5da5a3..b0d17c3b8 100644 --- a/bot/utils/helpers.py +++ b/bot/utils/helpers.py @@ -1,6 +1,5 @@ from abc import ABCMeta -from types import List -from typing import Dict, Optional +from typing import Dict, List, Optional from discord import Guild from discord.ext.commands import CogMeta -- cgit v1.2.3 From b2b9d23469960bcf9c8a0e17af7a6c0d51dda58a Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Wed, 28 Jul 2021 14:45:21 +0200 Subject: Handle non-existent roles in `join_role_stats` --- bot/utils/helpers.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bot/utils/helpers.py b/bot/utils/helpers.py index b0d17c3b8..cb1d46411 100644 --- a/bot/utils/helpers.py +++ b/bot/utils/helpers.py @@ -2,7 +2,7 @@ from abc import ABCMeta from typing import Dict, List, Optional from discord import Guild -from discord.ext.commands import CogMeta +from discord.ext.commands import BadArgument, CogMeta class CogABCMeta(CogMeta, ABCMeta): @@ -37,5 +37,8 @@ def join_role_stats(role_ids: List[int], name: str, guild: Guild) -> Dict[str, i """Return a dict object with the number of `members` of each role given, and the `name` for this joined group.""" members = [] for role_id in role_ids: - members += guild.get_role(role_id).members + if (role := guild.get_role(role_id)) is None: + raise BadArgument("Unable to fetch role data, the specified role does not exist.") + else: + members += role.members return {name: len(set(members))} -- cgit v1.2.3 From ed00aad9245769137a47e3e536bfa0da93b63917 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Thu, 29 Jul 2021 11:12:56 +0200 Subject: Modify error handling in join_role_stats and move it to the Information Cog --- bot/exts/info/information.py | 17 ++++++++++++++--- bot/utils/helpers.py | 16 ++-------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index eef18298c..54616a1c6 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -3,7 +3,7 @@ import logging import pprint import textwrap from collections import defaultdict -from typing import Any, DefaultDict, Dict, Mapping, Optional, Tuple, Union +from typing import Any, DefaultDict, Dict, List, Mapping, Optional, Tuple, Union import rapidfuzz from discord import AllowedMentions, Colour, Embed, Guild, Message, Role @@ -17,7 +17,6 @@ from bot.decorators import in_whitelist from bot.pagination import LinePaginator from bot.utils.channel import is_mod_channel, is_staff_channel from bot.utils.checks import cooldown_with_role_bypass, has_no_roles_check, in_whitelist_check -from bot.utils.helpers import join_role_stats from bot.utils.time import TimestampFormats, discord_timestamp, humanize_delta @@ -43,6 +42,17 @@ class Information(Cog): return channel_counter + @staticmethod + def join_role_stats(role_ids: List[int], name: str, guild: Guild) -> Dict[str, int]: + """Return a dictionary with the number of `members` of each role given, and the `name` for this joined group.""" + members = [] + for role_id in role_ids: + if (role := guild.get_role(role_id)) is None: + raise ValueError(f"Could not fetch data for role {role} for server embed.") + else: + members += role.members + return {name: len(set(members))} + @staticmethod def get_member_counts(guild: Guild) -> Dict[str, int]: """Return the total number of members for certain roles in `guild`.""" @@ -54,7 +64,8 @@ class Information(Cog): ) role_stats = {role.name.title(): len(role.members) for role in roles} role_stats.update( - **join_role_stats([constants.Roles.project_leads, constants.Roles.domain_leads], "Leads", guild)) + **Information.join_role_stats([constants.Roles.project_leads, constants.Roles.domain_leads], "Leads", guild) + ) return role_stats def get_extended_server_info(self, ctx: Context) -> str: diff --git a/bot/utils/helpers.py b/bot/utils/helpers.py index cb1d46411..3501a3933 100644 --- a/bot/utils/helpers.py +++ b/bot/utils/helpers.py @@ -1,8 +1,7 @@ from abc import ABCMeta -from typing import Dict, List, Optional +from typing import Optional -from discord import Guild -from discord.ext.commands import BadArgument, CogMeta +from discord.ext.commands import CogMeta class CogABCMeta(CogMeta, ABCMeta): @@ -31,14 +30,3 @@ def has_lines(string: str, count: int) -> bool: def pad_base64(data: str) -> str: """Return base64 `data` with padding characters to ensure its length is a multiple of 4.""" return data + "=" * (-len(data) % 4) - - -def join_role_stats(role_ids: List[int], name: str, guild: Guild) -> Dict[str, int]: - """Return a dict object with the number of `members` of each role given, and the `name` for this joined group.""" - members = [] - for role_id in role_ids: - if (role := guild.get_role(role_id)) is None: - raise BadArgument("Unable to fetch role data, the specified role does not exist.") - else: - members += role.members - return {name: len(set(members))} -- cgit v1.2.3 From 43240643642fae3fe92413189e99d772fdebf562 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Fri, 30 Jul 2021 03:25:25 +0200 Subject: Update join_role_stats, add new custom error - Add new custom error to handle non-existent roles in the Information cog - Update join_role_stats to use built in generics for typing --- bot/errors.py | 12 ++++++++++++ bot/exts/info/information.py | 24 +++++++++++++----------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/bot/errors.py b/bot/errors.py index 46efb6d4f..ce2371f56 100644 --- a/bot/errors.py +++ b/bot/errors.py @@ -41,3 +41,15 @@ class BrandingMisconfiguration(RuntimeError): """Raised by the Branding cog when a misconfigured event is encountered.""" pass + + +class NonExistentRoleError(ValueError): + """ + Raised by the Information Cog when encountering a role that does not exist. + + Attributes: + `role_id` -- the ID of the role that does not exist + """ + + def __init__(self, role_id: int): + super().__init__(f"Could not fetch data for role {role_id}") diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index 54616a1c6..78a9b2122 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -3,7 +3,7 @@ import logging import pprint import textwrap from collections import defaultdict -from typing import Any, DefaultDict, Dict, List, Mapping, Optional, Tuple, Union +from typing import Any, DefaultDict, Mapping, Optional, Tuple, Union import rapidfuzz from discord import AllowedMentions, Colour, Embed, Guild, Message, Role @@ -14,12 +14,12 @@ from bot.api import ResponseCodeError from bot.bot import Bot from bot.converters import FetchedMember from bot.decorators import in_whitelist +from bot.errors import NonExistentRoleError from bot.pagination import LinePaginator from bot.utils.channel import is_mod_channel, is_staff_channel from bot.utils.checks import cooldown_with_role_bypass, has_no_roles_check, in_whitelist_check from bot.utils.time import TimestampFormats, discord_timestamp, humanize_delta - log = logging.getLogger(__name__) @@ -43,25 +43,27 @@ class Information(Cog): return channel_counter @staticmethod - def join_role_stats(role_ids: List[int], name: str, guild: Guild) -> Dict[str, int]: + def join_role_stats(role_ids: list[int], name: str, guild: Guild) -> dict[str, int]: """Return a dictionary with the number of `members` of each role given, and the `name` for this joined group.""" members = [] for role_id in role_ids: if (role := guild.get_role(role_id)) is None: - raise ValueError(f"Could not fetch data for role {role} for server embed.") + raise NonExistentRoleError(role_id) else: members += role.members return {name: len(set(members))} @staticmethod - def get_member_counts(guild: Guild) -> Dict[str, int]: + def get_member_counts(guild: Guild) -> dict[str, int]: """Return the total number of members for certain roles in `guild`.""" - roles = ( - guild.get_role(role_id) for role_id in ( - constants.Roles.helpers, constants.Roles.mod_team, constants.Roles.admins, - constants.Roles.owners, constants.Roles.contributors, - ) - ) + role_ids = [constants.Roles.helpers, constants.Roles.mod_team, constants.Roles.admins, + constants.Roles.owners, constants.Roles.contributors] + roles = [] + for role_id in role_ids: + if (role := guild.get_role(role_id)) is None: + raise NonExistentRoleError(role_id) + else: + roles.append(role) role_stats = {role.name.title(): len(role.members) for role in roles} role_stats.update( **Information.join_role_stats([constants.Roles.project_leads, constants.Roles.domain_leads], "Leads", guild) -- cgit v1.2.3 From 3c91cfb852de5e4d01e8e1778e366ddc59e57f0f Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Sun, 1 Aug 2021 18:53:04 +0200 Subject: Update join_role_stats and NonExistentError to be clear --- bot/errors.py | 3 ++- bot/exts/info/information.py | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/bot/errors.py b/bot/errors.py index ce2371f56..69c588f4a 100644 --- a/bot/errors.py +++ b/bot/errors.py @@ -52,4 +52,5 @@ class NonExistentRoleError(ValueError): """ def __init__(self, role_id: int): - super().__init__(f"Could not fetch data for role {role_id}") + self.role_id = role_id + super().__init__(f"Could not fetch data for role {self.role_id}") diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index 78a9b2122..62fde5473 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -47,10 +47,10 @@ class Information(Cog): """Return a dictionary with the number of `members` of each role given, and the `name` for this joined group.""" members = [] for role_id in role_ids: - if (role := guild.get_role(role_id)) is None: - raise NonExistentRoleError(role_id) + if (role := guild.get_role(role_id)) is not None: + members.append(role.members) else: - members += role.members + raise NonExistentRoleError(role_id) return {name: len(set(members))} @staticmethod @@ -60,10 +60,11 @@ class Information(Cog): constants.Roles.owners, constants.Roles.contributors] roles = [] for role_id in role_ids: - if (role := guild.get_role(role_id)) is None: - raise NonExistentRoleError(role_id) - else: + if (role := guild.get_role(role_id)) is not None: roles.append(role) + else: + raise NonExistentRoleError(role_id) + role_stats = {role.name.title(): len(role.members) for role in roles} role_stats.update( **Information.join_role_stats([constants.Roles.project_leads, constants.Roles.domain_leads], "Leads", guild) -- cgit v1.2.3 From 20997b425168890636a04b270e7433fa82c60fa6 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Mon, 2 Aug 2021 18:28:05 +0200 Subject: Optimize Information Cog's join_role_stats and get_member counts --- bot/errors.py | 3 ++- bot/exts/info/information.py | 20 ++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/bot/errors.py b/bot/errors.py index 69c588f4a..5209997f9 100644 --- a/bot/errors.py +++ b/bot/errors.py @@ -52,5 +52,6 @@ class NonExistentRoleError(ValueError): """ def __init__(self, role_id: int): + super().__init__(f"Could not fetch data for role {role_id}") + self.role_id = role_id - super().__init__(f"Could not fetch data for role {self.role_id}") diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index 62fde5473..2621e15b1 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -43,31 +43,27 @@ class Information(Cog): return channel_counter @staticmethod - def join_role_stats(role_ids: list[int], name: str, guild: Guild) -> dict[str, int]: + def join_role_stats(role_ids: list[int], guild: Guild, name: Optional[str] = None) -> dict[str, int]: """Return a dictionary with the number of `members` of each role given, and the `name` for this joined group.""" - members = [] + members = int() for role_id in role_ids: if (role := guild.get_role(role_id)) is not None: - members.append(role.members) + members += len(role.members) else: raise NonExistentRoleError(role_id) - return {name: len(set(members))} + return {name or role.name.title(): members} @staticmethod def get_member_counts(guild: Guild) -> dict[str, int]: """Return the total number of members for certain roles in `guild`.""" role_ids = [constants.Roles.helpers, constants.Roles.mod_team, constants.Roles.admins, constants.Roles.owners, constants.Roles.contributors] - roles = [] - for role_id in role_ids: - if (role := guild.get_role(role_id)) is not None: - roles.append(role) - else: - raise NonExistentRoleError(role_id) - role_stats = {role.name.title(): len(role.members) for role in roles} + role_stats = {} + for role_id in role_ids: + role_stats.update(Information.join_role_stats([role_id], guild)) role_stats.update( - **Information.join_role_stats([constants.Roles.project_leads, constants.Roles.domain_leads], "Leads", guild) + Information.join_role_stats([constants.Roles.project_leads, constants.Roles.domain_leads], guild, "Leads") ) return role_stats -- cgit v1.2.3 From 8bb2ffc4f7bb324c7940fb88ae1b698f56f8ce67 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Mon, 2 Aug 2021 20:42:56 +0200 Subject: Improve code consistency of join_role_stats and NonExistentRoleError --- bot/errors.py | 2 +- bot/exts/info/information.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/errors.py b/bot/errors.py index 5209997f9..5785faa44 100644 --- a/bot/errors.py +++ b/bot/errors.py @@ -45,7 +45,7 @@ class BrandingMisconfiguration(RuntimeError): class NonExistentRoleError(ValueError): """ - Raised by the Information Cog when encountering a role that does not exist. + Raised by the Information Cog when encountering a Role that does not exist. Attributes: `role_id` -- the ID of the role that does not exist diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index 2621e15b1..b879e1330 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -45,7 +45,7 @@ class Information(Cog): @staticmethod def join_role_stats(role_ids: list[int], guild: Guild, name: Optional[str] = None) -> dict[str, int]: """Return a dictionary with the number of `members` of each role given, and the `name` for this joined group.""" - members = int() + members = 0 for role_id in role_ids: if (role := guild.get_role(role_id)) is not None: members += len(role.members) -- cgit v1.2.3