[Config] Modify config's all methods to provide default values (#916)

* Add in functionality for Tobotimus

* Cover all_guilds

* Make it obvious

* Fix auto rename of docstrings

* Fix downloader docs warning
This commit is contained in:
Will 2017-08-14 15:56:53 -04:00 committed by palmtree5
parent 248d2baa2a
commit da28630644
5 changed files with 101 additions and 26 deletions

View File

@ -108,12 +108,16 @@ class Group(Value):
defaults: dict,
spawner,
force_registration: bool=False):
self.defaults = defaults
self._defaults = defaults
self.force_registration = force_registration
self.spawner = spawner
super().__init__(identifiers, {}, self.spawner)
@property
def defaults(self):
return self._defaults.copy()
# noinspection PyTypeChecker
def __getattr__(self, item: str) -> Union["Group", Value]:
"""
@ -135,14 +139,14 @@ class Group(Value):
if is_group:
return Group(
identifiers=new_identifiers,
defaults=self.defaults[item],
defaults=self._defaults[item],
spawner=self.spawner,
force_registration=self.force_registration
)
elif is_value:
return Value(
identifiers=new_identifiers,
default_value=self.defaults[item],
default_value=self._defaults[item],
spawner=self.spawner
)
elif self.force_registration:
@ -174,7 +178,7 @@ class Group(Value):
:param str item:
See :py:meth:`__getattr__`.
"""
default = self.defaults.get(item)
default = self._defaults.get(item)
return isinstance(default, dict)
def is_value(self, item: str) -> bool:
@ -185,7 +189,7 @@ class Group(Value):
See :py:meth:`__getattr__`.
"""
try:
default = self.defaults[item]
default = self._defaults[item]
except KeyError:
return False
@ -231,19 +235,42 @@ class Group(Value):
This method allows you to get "all" of a particular group of data. It will return the dictionary of all data
for a particular Guild/Channel/Role/User/Member etc.
.. note::
Any values that have not been set from the registered defaults will have their default values
added to the dictionary that this method returns.
:rtype: dict
"""
return await self()
defaults = self.defaults
defaults.update(await self())
return defaults
async def all_from_kind(self) -> dict:
"""
This method allows you to get all data from all entries in a given Kind. It will return a dictionary of Kind
ID's -> data.
.. note::
Any values that have not been set from the registered defaults will have their default values
added to the dictionary that this method returns.
.. important::
This method is overridden in :py:meth:`.MemberGroup.all_from_kind` and functions slightly differently.
:rtype: dict
"""
# noinspection PyTypeChecker
return await self._super_group()
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):
if not isinstance(value, dict):
@ -307,14 +334,29 @@ class MemberGroup(Group):
"""
Returns a dict of :code:`GUILD_ID -> MEMBER_ID -> data`.
.. note::
Any values that have not been set from the registered defaults will have their default values
added to the dictionary that this method returns.
:rtype: dict
"""
# noinspection PyTypeChecker
return await self._super_group()
return await super().all_from_kind()
async def all(self) -> dict:
# noinspection PyTypeChecker
return await self._guild_group()
async def all_from_kind(self) -> dict:
"""
Returns a dict of all members from the same guild as the given one.
.. note::
Any values that have not been set from the registered defaults will have their default values
added to the dictionary that this method returns.
:rtype: dict
"""
guild_member = await super().all_from_kind()
return guild_member.get(self.identifiers[-2], {})
class Config:
@ -366,7 +408,11 @@ class Config:
self.spawner = driver_spawn
self.force_registration = force_registration
self.defaults = defaults or {}
self._defaults = defaults or {}
@property
def defaults(self):
return self._defaults.copy()
@classmethod
def get_conf(cls, cog_instance, identifier: int,
@ -425,7 +471,7 @@ class Config:
def _get_defaults_dict(key: str, value) -> dict:
"""
Since we're allowing nested config stuff now, not storing the
defaults as a flat dict sounds like a good idea. May turn
_defaults as a flat dict sounds like a good idea. May turn
out to be an awful one but we'll see.
:param key:
:param value:
@ -447,7 +493,7 @@ class Config:
@staticmethod
def _update_defaults(to_add: dict, _partial: dict):
"""
This tries to update the defaults dictionary with the nested
This tries to update the _defaults dictionary with the nested
partial dict generated by _get_defaults_dict. This WILL
throw an error if you try to have both a value and a group
registered under the same name.
@ -471,14 +517,14 @@ class Config:
_partial[k] = v
def _register_default(self, key: str, **kwargs):
if key not in self.defaults:
self.defaults[key] = {}
if key not in self._defaults:
self._defaults[key] = {}
data = deepcopy(kwargs)
for k, v in data.items():
to_add = self._get_defaults_dict(k, v)
self._update_defaults(to_add, self.defaults[key])
self._update_defaults(to_add, self._defaults[key])
def register_global(self, **kwargs):
"""
@ -497,7 +543,7 @@ class Config:
You can also now register nested values::
defaults = {
_defaults = {
"foo": {
"bar": True,
"baz": False
@ -506,10 +552,10 @@ class Config:
# Will register `foo.bar` == True and `foo.baz` == False
conf.register_global(
**defaults
**_defaults
)
You can do the same thing without a :python:`defaults` dict by using double underscore as a variable
You can do the same thing without a :python:`_defaults` dict by using double underscore as a variable
name separator::
# This is equivalent to the previous example
@ -556,7 +602,7 @@ class Config:
# noinspection PyTypeChecker
return group_class(
identifiers=(self.unique_identifier, key) + identifiers,
defaults=self.defaults.get(key, {}),
defaults=self._defaults.get(key, {}),
spawner=self.spawner,
force_registration=self.force_registration
)

View File

@ -43,16 +43,28 @@ API Reference
.. automodule:: core.config
Config
^^^^^^
.. autoclass:: Config
:members:
Group
^^^^^
.. autoclass:: Group
:members:
:special-members:
MemberGroup
^^^^^^^^^^^
.. autoclass:: MemberGroup
:members:
Value
^^^^^
.. autoclass:: Value
:members:
:special-members: __call__

View File

@ -69,7 +69,7 @@ Repo Manager
:members:
Exceptions
^^^^^^
^^^^^^^^^^
.. automodule:: cogs.downloader.errors
:members:

View File

@ -37,7 +37,7 @@ def config(json_driver):
unique_identifier=str(uuid.uuid4()),
driver_spawn=json_driver)
yield conf
conf.defaults = {}
conf._defaults = {}
@pytest.fixture()
@ -53,7 +53,7 @@ def config_fr(json_driver):
force_registration=True
)
yield conf
conf.defaults = {}
conf._defaults = {}
#region Dpy Mocks

View File

@ -242,7 +242,7 @@ async def test_membergroup_allguilds(config, empty_member):
async def test_membergroup_allmembers(config, empty_member):
await config.member(empty_member).foo.set(False)
all_members = await config.member(empty_member).all()
all_members = await config.member(empty_member).all_from_kind()
assert str(empty_member.id) in all_members
@ -301,6 +301,10 @@ async def test_member_clear_all(config, member_factory):
# Get All testing
@pytest.mark.asyncio
async def test_user_get_all_from_kind(config, user_factory):
config.register_user(
foo=False,
bar=True
)
for _ in range(5):
user = user_factory.get()
await config.user(user).foo.set(True)
@ -310,10 +314,23 @@ async def test_user_get_all_from_kind(config, user_factory):
assert len(all_data) == 5
for _, v in all_data.items():
assert v['foo'] is True
assert v['bar'] is True
@pytest.mark.asyncio
async def test_user_getalldata(config, user_factory):
user = user_factory.get()
config.register_user(
foo=True,
bar=False
)
await config.user(user).foo.set(False)
assert "foo" in await config.user(user).all()
all_data = await config.user(user).all()
assert "foo" in all_data
assert "bar" in all_data
assert config.user(user).defaults['foo'] is True