mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[V3 Config] Redesign "all_from_XXX" and "clear_all" methods (#1033)
* Added alternative to all_from_kind * Returned dicts include default values Also added docstrings Also removed all_globals since it's kind of redundant and it wasn't working out for me * Refactored clear_all * Tests * Tests again.. * Make all new methods coroutines
This commit is contained in:
parent
13fef45e06
commit
815678584f
@ -63,7 +63,7 @@ class Bank:
|
|||||||
If the bank is global, it will become per-guild
|
If the bank is global, it will become per-guild
|
||||||
If the bank is per-guild, it will become global"""
|
If the bank is per-guild, it will become global"""
|
||||||
cur_setting = await bank.is_global()
|
cur_setting = await bank.is_global()
|
||||||
await bank.set_global(not cur_setting, ctx.author)
|
await bank.set_global(not cur_setting)
|
||||||
|
|
||||||
word = _("per-guild") if cur_setting else _("global")
|
word = _("per-guild") if cur_setting else _("global")
|
||||||
|
|
||||||
|
|||||||
@ -322,7 +322,7 @@ async def get_guild_accounts(guild: discord.Guild) -> List[Account]:
|
|||||||
raise RuntimeError("The bank is currently global.")
|
raise RuntimeError("The bank is currently global.")
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
accs = await _conf.member(guild.owner).all_from_kind()
|
accs = await _conf.all_members(guild)
|
||||||
for user_id, acc in accs.items():
|
for user_id, acc in accs.items():
|
||||||
acc_data = acc.copy() # There ya go kowlin
|
acc_data = acc.copy() # There ya go kowlin
|
||||||
acc_data['created_at'] = _decode_time(acc_data['created_at'])
|
acc_data['created_at'] = _decode_time(acc_data['created_at'])
|
||||||
@ -353,7 +353,7 @@ async def get_global_accounts(user: discord.User) -> List[Account]:
|
|||||||
raise RuntimeError("The bank is not currently global.")
|
raise RuntimeError("The bank is not currently global.")
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
accs = await _conf.user(user).all_from_kind() # this is a dict of user -> acc
|
accs = await _conf.all_users() # this is a dict of user -> acc
|
||||||
for user_id, acc in accs.items():
|
for user_id, acc in accs.items():
|
||||||
acc_data = acc.copy()
|
acc_data = acc.copy()
|
||||||
acc_data['created_at'] = _decode_time(acc_data['created_at'])
|
acc_data['created_at'] = _decode_time(acc_data['created_at'])
|
||||||
@ -412,8 +412,6 @@ async def is_global() -> bool:
|
|||||||
async def set_global(global_: bool, user: Union[discord.User, discord.Member]) -> bool:
|
async def set_global(global_: bool, user: Union[discord.User, discord.Member]) -> bool:
|
||||||
"""Set global status of the bank.
|
"""Set global status of the bank.
|
||||||
|
|
||||||
Requires the user parameter for technical reasons.
|
|
||||||
|
|
||||||
.. important::
|
.. important::
|
||||||
|
|
||||||
All accounts are reset when you switch!
|
All accounts are reset when you switch!
|
||||||
@ -422,8 +420,6 @@ async def set_global(global_: bool, user: Union[discord.User, discord.Member]) -
|
|||||||
----------
|
----------
|
||||||
global_ : bool
|
global_ : bool
|
||||||
:code:`True` will set bank to global mode.
|
:code:`True` will set bank to global mode.
|
||||||
user : `discord.User` or `discord.Member`
|
|
||||||
Must be a Member object if changing TO global mode.
|
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -440,12 +436,9 @@ async def set_global(global_: bool, user: Union[discord.User, discord.Member]) -
|
|||||||
return global_
|
return global_
|
||||||
|
|
||||||
if is_global():
|
if is_global():
|
||||||
await _conf.user(user).clear_all()
|
await _conf.clear_all_users()
|
||||||
elif isinstance(user, discord.Member):
|
|
||||||
await _conf.member(user).clear_all()
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("You must provide a member if you're changing to global"
|
await _conf.clear_all_members()
|
||||||
" bank mode.")
|
|
||||||
|
|
||||||
await _conf.is_global.set(global_)
|
await _conf.is_global.set(global_)
|
||||||
return global_
|
return global_
|
||||||
|
|||||||
@ -292,36 +292,6 @@ class Group(Value):
|
|||||||
defaults.update(await self())
|
defaults.update(await self())
|
||||||
return defaults
|
return defaults
|
||||||
|
|
||||||
async def all_from_kind(self) -> dict:
|
|
||||||
"""Get all data from this group and its siblings.
|
|
||||||
|
|
||||||
.. important::
|
|
||||||
|
|
||||||
This method is overridden in `MemberGroup.all_from_kind` and
|
|
||||||
functions slightly differently.
|
|
||||||
|
|
||||||
Note
|
|
||||||
----
|
|
||||||
The return value of this method will include registered defaults
|
|
||||||
for groups which have not had their values set.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
dict
|
|
||||||
A dict of :code:`ID -> data`, with the data being a dict
|
|
||||||
of the group's raw values.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# noinspection PyTypeChecker
|
|
||||||
all_from_kind = await self._super_group()
|
|
||||||
|
|
||||||
for k, v in all_from_kind.items():
|
|
||||||
defaults = self.defaults
|
|
||||||
defaults.update(v)
|
|
||||||
all_from_kind[k] = defaults
|
|
||||||
|
|
||||||
return all_from_kind
|
|
||||||
|
|
||||||
async def set(self, value):
|
async def set(self, value):
|
||||||
if not isinstance(value, dict):
|
if not isinstance(value, dict):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@ -358,13 +328,6 @@ class Group(Value):
|
|||||||
"""
|
"""
|
||||||
await self.set({})
|
await self.set({})
|
||||||
|
|
||||||
async def clear_all(self):
|
|
||||||
"""Wipe all data from this group and its siblings.
|
|
||||||
|
|
||||||
If used on a global group, this method wipes all data from all groups.
|
|
||||||
"""
|
|
||||||
await self._super_group.set({})
|
|
||||||
|
|
||||||
|
|
||||||
class MemberGroup(Group):
|
class MemberGroup(Group):
|
||||||
"""A specific group class for use with member data only.
|
"""A specific group class for use with member data only.
|
||||||
@ -392,41 +355,6 @@ class MemberGroup(Group):
|
|||||||
)
|
)
|
||||||
return group_obj
|
return group_obj
|
||||||
|
|
||||||
async def all_guilds(self) -> dict:
|
|
||||||
"""Get a dict of :code:`GUILD_ID -> MEMBER_ID -> data`.
|
|
||||||
|
|
||||||
Note
|
|
||||||
----
|
|
||||||
The return value of this method will include registered defaults
|
|
||||||
for groups which have not had their values set.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
dict
|
|
||||||
A dict of data from all members from all guilds.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# noinspection PyTypeChecker
|
|
||||||
return await super().all_from_kind()
|
|
||||||
|
|
||||||
async def all_from_kind(self) -> dict:
|
|
||||||
"""Get a dict of all members from the same guild as the given one.
|
|
||||||
|
|
||||||
Note
|
|
||||||
----
|
|
||||||
The return value of this method will include registered defaults
|
|
||||||
for groups which have not had their values set.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
dict
|
|
||||||
A dict of :code:`MEMBER_ID -> data`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
guild_member = await super().all_from_kind()
|
|
||||||
return guild_member.get(self.identifiers[-2], {})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
"""Configuration manager for cogs and Red.
|
"""Configuration manager for cogs and Red.
|
||||||
@ -519,11 +447,13 @@ class Config:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_core_conf(cls, force_registration: bool=False):
|
def get_core_conf(cls, force_registration: bool=False):
|
||||||
"""All core modules that require a config instance should use this
|
"""Get a Config instance for a core module.
|
||||||
|
|
||||||
|
All core modules that require a config instance should use this
|
||||||
classmethod instead of `get_conf`.
|
classmethod instead of `get_conf`.
|
||||||
|
|
||||||
identifier : int
|
Parameters
|
||||||
See `get_conf`.
|
----------
|
||||||
force_registration : `bool`, optional
|
force_registration : `bool`, optional
|
||||||
See `force_registration`.
|
See `force_registration`.
|
||||||
|
|
||||||
@ -765,3 +695,226 @@ class Config:
|
|||||||
return self._get_base_group(self.MEMBER, member.guild.id, member.id,
|
return self._get_base_group(self.MEMBER, member.guild.id, member.id,
|
||||||
group_class=MemberGroup)
|
group_class=MemberGroup)
|
||||||
|
|
||||||
|
async def _all_from_scope(self, scope: str):
|
||||||
|
"""Get a dict of all values from a particular scope of data.
|
||||||
|
|
||||||
|
:code:`scope` must be one of the constants attributed to
|
||||||
|
this class, i.e. :code:`GUILD`, :code:`MEMBER` et cetera.
|
||||||
|
|
||||||
|
IDs as keys in the returned dict are casted to `int` for convenience.
|
||||||
|
|
||||||
|
Default values are also mixed into the data if they have not yet been
|
||||||
|
overwritten.
|
||||||
|
"""
|
||||||
|
group = self._get_base_group(scope)
|
||||||
|
dict_ = await group()
|
||||||
|
ret = {}
|
||||||
|
for k, v in dict_.items():
|
||||||
|
data = group.defaults
|
||||||
|
data.update(v)
|
||||||
|
ret[int(k)] = data
|
||||||
|
return ret
|
||||||
|
|
||||||
|
async def all_guilds(self) -> dict:
|
||||||
|
"""Get all guild data as a dict.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
The return value of this method will include registered defaults for
|
||||||
|
values which have not yet been set.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A dictionary in the form {`int`: `dict`} mapping
|
||||||
|
:code:`GUILD_ID -> data`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return await self._all_from_scope(self.GUILD)
|
||||||
|
|
||||||
|
async def all_channels(self) -> dict:
|
||||||
|
"""Get all channel data as a dict.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
The return value of this method will include registered defaults for
|
||||||
|
values which have not yet been set.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A dictionary in the form {`int`: `dict`} mapping
|
||||||
|
:code:`CHANNEL_ID -> data`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return await self._all_from_scope(self.CHANNEL)
|
||||||
|
|
||||||
|
async def all_roles(self) -> dict:
|
||||||
|
"""Get all role data as a dict.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
The return value of this method will include registered defaults for
|
||||||
|
values which have not yet been set.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A dictionary in the form {`int`: `dict`} mapping
|
||||||
|
:code:`ROLE_ID -> data`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return await self._all_from_scope(self.ROLE)
|
||||||
|
|
||||||
|
async def all_users(self) -> dict:
|
||||||
|
"""Get all user data as a dict.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
The return value of this method will include registered defaults for
|
||||||
|
values which have not yet been set.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A dictionary in the form {`int`: `dict`} mapping
|
||||||
|
:code:`USER_ID -> data`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return await self._all_from_scope(self.USER)
|
||||||
|
|
||||||
|
def _all_members_from_guild(self, group: Group, guild_data: dict) -> dict:
|
||||||
|
ret = {}
|
||||||
|
for member_id, member_data in guild_data.items():
|
||||||
|
new_member_data = group.defaults
|
||||||
|
new_member_data.update(member_data)
|
||||||
|
ret[int(member_id)] = new_member_data
|
||||||
|
return ret
|
||||||
|
|
||||||
|
async def all_members(self, guild: discord.Guild=None) -> dict:
|
||||||
|
"""Get data for all members.
|
||||||
|
|
||||||
|
If :code:`guild` is specified, only the data for the members of that
|
||||||
|
guild will be returned. As such, the dict will map
|
||||||
|
:code:`MEMBER_ID -> data`. Otherwise, the dict maps
|
||||||
|
:code:`GUILD_ID -> MEMBER_ID -> data`.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
The return value of this method will include registered defaults for
|
||||||
|
values which have not yet been set.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
guild : `discord.Guild`, optional
|
||||||
|
The guild to get the member data from. Can be omitted if data
|
||||||
|
from every member of all guilds is desired.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A dictionary of all specified member data.
|
||||||
|
|
||||||
|
"""
|
||||||
|
ret = {}
|
||||||
|
if guild is None:
|
||||||
|
group = self._get_base_group(self.MEMBER)
|
||||||
|
dict_ = await group()
|
||||||
|
for guild_id, guild_data in dict_.items():
|
||||||
|
ret[int(guild_id)] = self._all_members_from_guild(
|
||||||
|
group, guild_data)
|
||||||
|
else:
|
||||||
|
group = self._get_base_group(self.MEMBER, guild.id)
|
||||||
|
guild_data = await group()
|
||||||
|
ret = self._all_members_from_guild(group, guild_data)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
async def _clear_scope(self, *scopes: str):
|
||||||
|
"""Clear all data in a particular scope.
|
||||||
|
|
||||||
|
The only situation where a second scope should be passed in is if
|
||||||
|
member data from a specific guild is being cleared.
|
||||||
|
|
||||||
|
If no scopes are passed, then all data is cleared from every scope.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
*scopes : str, optional
|
||||||
|
The scope of the data. Generally only one scope needs to be
|
||||||
|
provided, a second only necessary for clearing member data
|
||||||
|
of a specific guild.
|
||||||
|
|
||||||
|
**Leaving blank removes all data from this Config instance.**
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not scopes:
|
||||||
|
group = Group(identifiers=(self.unique_identifier),
|
||||||
|
defaults={},
|
||||||
|
spawner=self.spawner)
|
||||||
|
else:
|
||||||
|
group = self._get_base_group(*scopes)
|
||||||
|
await group.set({})
|
||||||
|
|
||||||
|
async def clear_all(self):
|
||||||
|
"""Clear all data from this Config instance.
|
||||||
|
|
||||||
|
This resets all data to its registered defaults.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
This cannot be undone.
|
||||||
|
|
||||||
|
"""
|
||||||
|
await self._clear_scope()
|
||||||
|
|
||||||
|
async def clear_all_globals(self):
|
||||||
|
"""Clear all global data.
|
||||||
|
|
||||||
|
This resets all global data to its registered defaults.
|
||||||
|
"""
|
||||||
|
await self._clear_scope(self.GLOBAL)
|
||||||
|
|
||||||
|
async def clear_all_guilds(self):
|
||||||
|
"""Clear all guild data.
|
||||||
|
|
||||||
|
This resets all guild data to its registered defaults.
|
||||||
|
"""
|
||||||
|
await self._clear_scope(self.GUILD)
|
||||||
|
|
||||||
|
async def clear_all_channels(self):
|
||||||
|
"""Clear all channel data.
|
||||||
|
|
||||||
|
This resets all channel data to its registered defaults.
|
||||||
|
"""
|
||||||
|
await self._clear_scope(self.CHANNEL)
|
||||||
|
|
||||||
|
async def clear_all_roles(self):
|
||||||
|
"""Clear all role data.
|
||||||
|
|
||||||
|
This resets all role data to its registered defaults.
|
||||||
|
"""
|
||||||
|
await self._clear_scope(self.ROLE)
|
||||||
|
|
||||||
|
async def clear_all_users(self):
|
||||||
|
"""Clear all user data.
|
||||||
|
|
||||||
|
This resets all user data to its registered defaults.
|
||||||
|
"""
|
||||||
|
await self._clear_scope(self.USER)
|
||||||
|
|
||||||
|
async def clear_all_members(self, guild: discord.Guild=None):
|
||||||
|
"""Clear all member data.
|
||||||
|
|
||||||
|
This resets all specified member data to its registered defaults.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
guild : `discord.Guild`, optional
|
||||||
|
The guild to clear member data from. Omit to clear member data from
|
||||||
|
all guilds.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if guild is not None:
|
||||||
|
await self._clear_scope(self.MEMBER, guild.id)
|
||||||
|
return
|
||||||
|
await self._clear_scope(self.MEMBER)
|
||||||
|
|||||||
@ -234,16 +234,16 @@ async def test_get_dynamic_attr(config):
|
|||||||
async def test_membergroup_allguilds(config, empty_member):
|
async def test_membergroup_allguilds(config, empty_member):
|
||||||
await config.member(empty_member).foo.set(False)
|
await config.member(empty_member).foo.set(False)
|
||||||
|
|
||||||
all_servers = await config.member(empty_member).all_guilds()
|
all_servers = await config.all_members()
|
||||||
assert str(empty_member.guild.id) in all_servers
|
assert empty_member.guild.id in all_servers
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_membergroup_allmembers(config, empty_member):
|
async def test_membergroup_allmembers(config, empty_member):
|
||||||
await config.member(empty_member).foo.set(False)
|
await config.member(empty_member).foo.set(False)
|
||||||
|
|
||||||
all_members = await config.member(empty_member).all_from_kind()
|
all_members = await config.all_members(empty_member.guild)
|
||||||
assert str(empty_member.id) in all_members
|
assert empty_member.id in all_members
|
||||||
|
|
||||||
|
|
||||||
# Clearing testing
|
# Clearing testing
|
||||||
@ -291,11 +291,11 @@ async def test_member_clear_all(config, member_factory):
|
|||||||
server_ids.append(member.guild.id)
|
server_ids.append(member.guild.id)
|
||||||
|
|
||||||
member = member_factory.get()
|
member = member_factory.get()
|
||||||
assert len(await config.member(member).all_guilds()) == len(server_ids)
|
assert len(await config.all_members()) == len(server_ids)
|
||||||
|
|
||||||
await config.member(member).clear_all()
|
await config.clear_all_members()
|
||||||
|
|
||||||
assert len(await config.member(member).all_guilds()) == 0
|
assert len(await config.all_members()) == 0
|
||||||
|
|
||||||
|
|
||||||
# Get All testing
|
# Get All testing
|
||||||
@ -309,8 +309,7 @@ async def test_user_get_all_from_kind(config, user_factory):
|
|||||||
user = user_factory.get()
|
user = user_factory.get()
|
||||||
await config.user(user).foo.set(True)
|
await config.user(user).foo.set(True)
|
||||||
|
|
||||||
user = user_factory.get()
|
all_data = await config.all_users()
|
||||||
all_data = await config.user(user).all_from_kind()
|
|
||||||
|
|
||||||
assert len(all_data) == 5
|
assert len(all_data) == 5
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user