mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-21 10:17:59 -05:00
[Config] Retrieve/save values with async context manager (#1131)
* [Config] Retrieve/save values with async context manager * Add a little docstring * Documentation * Implement async with syntax in existing modules
This commit is contained in:
@@ -142,15 +142,14 @@ class RedBase(BotBase, RpcMethodMixin):
|
||||
await self.db.packages.set(packages)
|
||||
|
||||
async def add_loaded_package(self, pkg_name: str):
|
||||
curr_pkgs = await self.db.packages()
|
||||
if pkg_name not in curr_pkgs:
|
||||
curr_pkgs.append(pkg_name)
|
||||
await self.save_packages_status(curr_pkgs)
|
||||
async with self.db.packages() as curr_pkgs:
|
||||
if pkg_name not in curr_pkgs:
|
||||
curr_pkgs.append(pkg_name)
|
||||
|
||||
async def remove_loaded_package(self, pkg_name: str):
|
||||
curr_pkgs = await self.db.packages()
|
||||
if pkg_name in curr_pkgs:
|
||||
await self.save_packages_status([p for p in curr_pkgs if p != pkg_name])
|
||||
async with self.db.packages() as curr_pkgs:
|
||||
while pkg_name in curr_pkgs:
|
||||
curr_pkgs.remove(pkg_name)
|
||||
|
||||
def load_extension(self, spec: ModuleSpec):
|
||||
name = spec.name.split('.')[-1]
|
||||
|
||||
@@ -10,6 +10,37 @@ from .drivers import get_driver
|
||||
log = logging.getLogger("red.config")
|
||||
|
||||
|
||||
class _ValueCtxManager:
|
||||
"""Context manager implementation of config values.
|
||||
|
||||
This class allows mutable config values to be both "get" and "set" from
|
||||
within an async context manager.
|
||||
|
||||
The context manager can only be used to get and set a mutable data type,
|
||||
i.e. `dict`s or `list`s. This is because this class's ``raw_value``
|
||||
attribute must contain a reference to the object being modified within the
|
||||
context manager.
|
||||
"""
|
||||
|
||||
def __init__(self, value_obj, coro):
|
||||
self.value_obj = value_obj
|
||||
self.coro = coro
|
||||
|
||||
def __await__(self):
|
||||
return self.coro.__await__()
|
||||
|
||||
async def __aenter__(self):
|
||||
self.raw_value = await self
|
||||
if not isinstance(self.raw_value, (list, dict)):
|
||||
raise TypeError("Type of retrieved value must be mutable (i.e. "
|
||||
"list or dict) in order to use a config value as "
|
||||
"a context manager.")
|
||||
return self.raw_value
|
||||
|
||||
async def __aexit__(self, *exc_info):
|
||||
await self.value_obj.set(self.raw_value)
|
||||
|
||||
|
||||
class Value:
|
||||
"""A singular "value" of data.
|
||||
|
||||
@@ -49,6 +80,11 @@ class Value:
|
||||
"real" data of the `Value` object is accessed by this method. It is a
|
||||
replacement for a :code:`get()` method.
|
||||
|
||||
The return value of this method can also be used as an asynchronous
|
||||
context manager, i.e. with :code:`async with` syntax. This can only be
|
||||
used on values which are mutable (namely lists and dicts), and will
|
||||
set the value with its changes on exit of the context manager.
|
||||
|
||||
Example
|
||||
-------
|
||||
::
|
||||
@@ -74,11 +110,13 @@ class Value:
|
||||
|
||||
Returns
|
||||
-------
|
||||
types.coroutine
|
||||
A coroutine object that must be awaited.
|
||||
`awaitable` mixed with `asynchronous context manager`
|
||||
A coroutine object mixed in with an async context manager. When
|
||||
awaited, this returns the raw data value. When used in :code:`async
|
||||
with` syntax, on gets the value on entrance, and sets it on exit.
|
||||
|
||||
"""
|
||||
return self._get(default)
|
||||
return _ValueCtxManager(self, self._get(default))
|
||||
|
||||
async def set(self, value):
|
||||
"""Set the value of the data elements pointed to by `identifiers`.
|
||||
|
||||
Reference in New Issue
Block a user