Config¶
Config was introduced in V3 as a way to make data storage easier and safer for all developers regardless of skill level. It will take some getting used to as the syntax is entirely different from what Red has used before, but we believe Config will be extremely beneficial to both cog developers and end users in the long run.
Note
While config is great for storing data safely, there are some caveats to writing performant code which uses it. Make sure to read the section on best practices for more of these details.
Basic Usage¶
from redbot.core import Config
from redbot.core import commands
class MyCog(commands.Cog):
def __init__(self):
self.config = Config.get_conf(self, identifier=1234567890)
self.config.register_global(
foo=True
)
@commands.command()
async def return_some_data(self, ctx):
await ctx.send(await self.config.foo())
Tutorial¶
This tutorial will walk you through how to use Config.
First, you need to import Config:
from redbot.core import Config
Then, in the class’s __init__
function, you need to get a config instance:
class MyCog(commands.Cog):
def __init__(self):
self.config = Config.get_conf(self, identifier=1234567890)
The identifier
in Config.get_conf()
is used to keep your cog’s data separate
from that of another cog, and thus should be unique to your cog. For example: if we
have two cogs named MyCog
and their identifier is different, each will have
its own data without overwriting the other’s data. Note that it is also possible
to force registration of a data key before allowing you to get and set data for
that key by adding force_registration=True
after identifier (that defaults
to False
though)
After we’ve gotten that, we need to register default values:
class MyCog(commands.Cog):
def __init__(self):
self.config = Config.get_conf(self, identifier=1234567890)
default_global = {
"foobar": True,
"foo": {
"bar": True,
"baz": False
}
}
default_guild = {
"blah": [],
"baz": 1234567890
}
self.config.register_global(**default_global)
self.config.register_guild(**default_guild)
As seen in the example above, we can set up our defaults in dicts and then use those in
the appropriate register
function. As seen above, there’s Config.register_global()
and Config.register_guild()
, but there’s also Config.register_member()
,
Config.register_role()
, Config.register_user()
, and Config.register_channel()
.
Note that member
stores based on guild id AND the user’s id.
Once we have our defaults registered and we have the object, we can now use those values in various ways:
@commands.command()
@checks.admin_or_permissions(manage_guild=True)
async def setbaz(self, ctx, new_value):
await self.config.guild(ctx.guild).baz.set(new_value)
await ctx.send("Value of baz has been changed!")
@commands.command()
@checks.is_owner()
async def setfoobar(self, ctx, new_value):
await self.config.foobar.set(new_value)
@commands.command()
async def checkbaz(self, ctx):
baz_val = await self.config.guild(ctx.guild).baz()
await ctx.send("The value of baz is {}".format("True" if baz_val else "False"))
Notice a few things in the above examples:
Global doesn’t have anything in between
self.config
and the variable.Both the getters and setters need to be awaited because they’re coroutines.
If you’re getting the value, the syntax is:
self.config.<insert scope here, or nothing if global>.variable_name()
If setting, it’s:
self.config.<insert scope here, or nothing if global>.variable_name.set(new_value)
It is also possible to use async with
syntax to get and set config
values. When entering the statement, the config value is retreived, and on exit,
it is saved. This puts a safeguard on any code within the async with
block such that if it breaks from the block in any way (whether it be from
return
, break
, continue
or an exception), the value will
still be saved.
Important
Only mutable config values can be used in the async with
statement
(namely lists or dicts), and they must be modified in place for their
changes to be saved.
Here is an example of the async with
syntax:
@commands.command()
async def addblah(self, ctx, new_blah):
guild_group = self.config.guild(ctx.guild)
async with guild_group.blah() as blah:
blah.append(new_blah)
await ctx.send("The new blah value has been added!")
Important
Please note that while you have nothing between config
and the variable name for global
data, you also have the following commands to get data specific to each category.
Config.guild()
for guild data which takes an object of typediscord.Guild
.Config.member()
which takesdiscord.Member
.Config.user()
which takesdiscord.User
.Config.role()
which takesdiscord.Role
.Config.channel()
which takesdiscord.TextChannel
.
If you need to wipe data from the config, you want to look at Group.clear()
, or Config.clear_all()
and similar methods, such as Config.clear_all_guilds()
.
Which one you should use depends on what you want to do.
If you’re looking to clear data for a single guild/member/channel/role/user,
you want to use Group.clear()
as that will clear the data only for the
specified thing.
If using Config.clear_all()
, it will reset all data everywhere.
There are other methods provided to reset data from a particular scope. For
example, Config.clear_all_guilds()
resets all guild data. For member
data, you can clear on both a per-guild and guild-independent basis, see
Config.clear_all_members()
for more info.
Advanced Usage¶
Config makes it extremely easy to organize data that can easily fit into one of the standard categories (global, guild, user etc.) but there may come a time when your data does not work with the existing categories. There are now features within Config to enable developers to work with data how they wish.
This usage guide will cover the following features:
Custom Groups¶
While Config has built-in groups for the common discord objects, sometimes you need a combination of these or your own defined grouping. Config handles this by allowing you to define custom groups.
Let’s start by showing how Config.custom()
can be equivalent to Config.guild()
by modifying the above
Tutorial example.
from redbot.core import Config, commands
class MyCog(commands.Cog):
def __init__(self):
self.config = Config.get_conf(self, identifier=1234567890)
default_guild = {
"blah": [],
"baz": 1234567890
}
# self.config.register_guild(**default_guild)
self.config.init_custom("CustomGuildGroup", 1)
self.config.register_custom("CustomGuildGroup", **default_guild)
In the above, we registered the custom group named “CustomGuildGroup” to contain the same defaults
that self.config.guild
normally would. First, we initialized the group “CustomGuildGroup” to
accept one identifier by calling Config.init_custom()
with the argument 1
. Then we used
Config.register_custom()
to register the default values.
Important
Config.init_custom()
must be called prior to using a custom group.
Now let’s use this custom group:
@commands.command()
async def setbaz(self, ctx, new_value):
# await self.config.guild(ctx.guild).baz.set(new_value)
await self.config.custom("CustomGuildGroup", ctx.guild.id).baz.set(new_value)
await ctx.send("Value of baz has been changed!")
@commands.command()
async def checkbaz(self, ctx):
# baz_val = await self.config.guild(ctx.guild).baz()
baz_val = await self.config.custom("CustomGuildGroup", ctx.guild.id).baz()
await ctx.send("The value of baz is {}".format("True" if baz_val else "False"))
Here we used Config.custom()
to access our custom group much like we would have used Config.guild()
.
Since it’s a custom group, we need to use id
attribute of guild to get a unique identifier.
Now let’s see an example that uses multiple identifiers:
from redbot.core import Config, commands, checks
class ChannelAccesss(commands.Cog):
def __init__(self):
self.config = Config.get_conf(self, identifier=1234567890)
default_access = {
"allowed": False
}
self.config.init_custom("ChannelAccess", 2)
self.config.register_custom("ChannelAccess", **default_access)
@commands.command()
@checks.is_owner()
async def grantaccess(self, ctx, channel: discord.TextChannel, member: discord.Member):
await self.config.custom("ChannelAccess", channel.id, member.id).allowed.set(True)
await ctx.send("Member has been granted access to that channel")
@commands.command()
async def checkaccess(self, ctx, channel: discord.TextChannel):
allowed = await self.config.custom("ChannelAccess", channel.id, ctx.author.id).allowed()
await ctx.send("Your access to this channel is {}".format("Allowed" if allowed else "Denied"))
In the above example, we defined the custom group “ChannelAccess” to accept two identifiers
using Config.init_custom()
. Then, we were able to set the default value for any member’s
access to any channel to False
until the bot owner grants them access.
Important
The ordering of the identifiers matter. custom("ChannelAccess", channel.id, member.id)
is NOT the same
as custom("ChannelAccess", member.id, channel.id)
Raw Group Access¶
For this example let’s suppose that we’re creating a cog that allows users to buy and own multiple pets using the built-in Economy credits:
from redbot.core import bank
from redbot.core import Config, commands
class Pets(commands.Cog):
def __init__(self):
self.config = Config.get_conf(self, 1234567890)
# Here we'll assign some default costs for the pets
self.config.register_global(
dog=100,
cat=100,
bird=50
)
self.config.register_user(
pets={}
)
And now that the cog is set up we’ll need to create some commands that allow users to purchase these pets:
# continued
@commands.command()
async def get_pet(self, ctx, pet_type: str, pet_name: str):
"""
Purchase a pet.
Pet type must be one of: dog, cat, bird
"""
# Now we need to determine what the cost of the pet is and
# if the user has enough credits to purchase it.
# We will need to use "get_raw"
try:
cost = await self.config.get_raw(pet_type)
except KeyError:
# KeyError is thrown whenever the data you try to access does not
# exist in the registered defaults or in the saved data.
await ctx.send("Bad pet type, try again.")
return
After we’ve determined the cost of the pet we need to check if the user has enough credits and then we’ll need to
assign a new pet to the user. This is very easily done using the V3 bank API and Group.set_raw()
:
# continued
if await bank.can_spend(ctx.author, cost):
await self.config.user(ctx.author).pets.set_raw(
pet_name, value={'cost': cost, 'hunger': 0}
)
# this is equivalent to doing the following
pets = await self.config.user(ctx.author).pets()
pets[pet_name] = {'cost': cost, 'hunger': 0}
await self.config.user(ctx.author).pets.set(pets)
Since the pets can get hungry we’re gonna need a command that let’s pet owners check how hungry their pets are:
# continued
@commands.command()
async def hunger(self, ctx, pet_name: str):
try:
hunger = await self.config.user(ctx.author).pets.get_raw(pet_name, 'hunger')
except KeyError:
# Remember, this is thrown if something in the provided identifiers
# is not found in the saved data or the defaults.
await ctx.send("You don't own that pet!")
return
await ctx.send("Your pet has {}/100 hunger".format(hunger))
We’re responsible pet owners here, so we’ve also got to have a way to feed our pets:
# continued
@commands.command()
async def feed(self, ctx, pet_name: str, food: int):
# This is a bit more complicated because we need to check if the pet is
# owned first.
try:
pet = await self.config.user(ctx.author).pets.get_raw(pet_name)
except KeyError:
# If the given pet name doesn't exist in our data
await ctx.send("You don't own that pet!")
return
hunger = pet.get("hunger")
# Determine the new hunger and make sure it doesn't go negative
new_hunger = max(hunger - food, 0)
await self.config.user(ctx.author).pets.set_raw(
pet_name, 'hunger', value=new_hunger
)
# We could accomplish the same thing a slightly different way
await self.config.user(ctx.author).pets.get_attr(pet_name).hunger.set(new_hunger)
await ctx.send("Your pet is now at {}/100 hunger!".format(new_hunger)
Of course, if we’re less than responsible pet owners, there are consequences:
#continued
@commands.command()
async def adopt(self, ctx, pet_name: str, *, member: discord.Member):
try:
pet = await self.config.user(member).pets.get_raw(pet_name)
except KeyError:
await ctx.send("That person doesn't own that pet!")
return
hunger = pet.get("hunger")
if hunger < 80:
await ctx.send("That pet is too well taken care of to be adopted.")
return
await self.config.user(member).pets.clear_raw(pet_name)
# this is equivalent to doing the following
pets = await self.config.user(member).pets()
del pets[pet_name]
await self.config.user(member).pets.set(pets)
await self.config.user(ctx.author).pets.set_raw(pet_name, value=pet)
await ctx.send(
"Your request to adopt this pet has been granted due to "
"how poorly it was taken care of."
)
V2 Data Usage¶
There has been much conversation on how to bring V2 data into V3 and, officially, we recommend that cog developers make use of the public interface in Config (using the categories as described in these docs) rather than simply copying and pasting your V2 data into V3. Using Config as recommended will result in a much better experience for you in the long run and will simplify cog creation and maintenance.
However.
We realize that many of our cog creators have expressed disinterest in writing converters for V2 to V3 style data. As a result we have opened up config to take standard V2 data and allow cog developers to manipulate it in V3 in much the same way they would in V2. The following examples will demonstrate how to accomplish this.
Warning
By following this method to use V2 data in V3 you may be at risk of data corruption if your cog is used on a bot with multiple shards. USE AT YOUR OWN RISK.
from redbot.core import Config, commands
class ExampleCog(commands.Cog):
def __init__(self):
self.config = Config.get_conf(self, 1234567890)
self.config.init_custom("V2", 1)
self.data = {}
async def load_data(self):
self.data = await self.config.custom("V2", "V2").all()
async def save_data(self):
await self.config.custom("V2", "V2").set(self.data)
async def setup(bot):
cog = ExampleCog()
await cog.load_data()
bot.add_cog(cog)
Best practices and performance notes¶
Config prioritizes being a safe data store without developers needing to know how end users have configured their bot.
This does come with some performance costs, so keep the following in mind when choosing to develop using config
Config use in events should be kept minimal and should only occur after confirming the event needs to interact with config
Caching frequently used things, especially things used by events, results in faster and less event loop blocking code.
Only use config’s context managers when you intend to modify data.
While config is a great general use option, it may not always be the right one for you. As a cog developer, even though config doesn’t require one, you can choose to require a database or store to something such as an sqlite database stored within your cog’s datapath.
API Reference¶
Important
Before we begin with the nitty gritty API Reference, you should know that there are tons of working code examples
inside the bot itself! Simply take a peek inside of the tests/core/test_config.py
file for examples of using
Config in all kinds of ways.
Important
When getting, setting or clearing values in Config, all keys are casted to str
for you. This
includes keys within a dict
when one is being set, as well as keys in nested dictionaries
within that dict
. For example:
>>> config = Config.get_conf(self, identifier=999)
>>> config.register_global(foo={})
>>> await config.foo.set_raw(123, value=True)
>>> await config.foo()
{'123': True}
>>> await config.foo.set({123: True, 456: {789: False}}
>>> await config.foo()
{'123': True, '456': {'789': False}}
Config¶
- class redbot.core.config.Config(cog_name, unique_identifier, driver, force_registration=False, defaults=None)[source]¶
Bases:
object
Configuration manager for cogs and Red.
You should always use
get_conf
to instantiate a Config object. Useget_core_conf
for Config used in the core package.Important
Most config data should be accessed through its respective group method (e.g.
guild()
) however the process for accessing global data is a bit different. There is noglobal
method because global data is accessed by normal attribute access:await config.foo()
- unique_identifier¶
Unique identifier provided to differentiate cog data when name conflicts occur.
- Type
- driver¶
An instance of a driver that implements
redbot.core.drivers.BaseDriver
.
- force_registration¶
Determines if Config should throw an error if a cog attempts to access an attribute which has not been previously registered.
Note
You should use this. By enabling force registration you give Config the ability to alert you instantly if you’ve made a typo when attempting to access data.
- Type
- await all_channels()[source]¶
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.
- await all_guilds()[source]¶
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.
- await all_members(guild=None)[source]¶
Get data for all members.
If
guild
is specified, only the data for the members of that guild will be returned. As such, the dict will mapMEMBER_ID -> data
. Otherwise, the dict mapsGUILD_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
A dictionary of all specified member data.
- Return type
- await all_roles()[source]¶
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.
- await all_users()[source]¶
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.
- channel(channel)[source]¶
Returns a
Group
for the given channel.This does not discriminate between text and voice channels.
- Parameters
channel (
discord.abc.GuildChannel
) – A channel object.- Returns
The channel’s Group object.
- Return type
- channel_from_id(channel_id)[source]¶
Returns a
Group
for the given channel id.This does not discriminate between text and voice channels.
- await clear_all()[source]¶
Clear all data from this Config instance.
This resets all data to its registered defaults.
Important
This cannot be undone.
- await clear_all_channels()[source]¶
Clear all channel data.
This resets all channel data to its registered defaults.
- await clear_all_custom(group_identifier)[source]¶
Clear all custom group data.
This resets all custom group data to its registered defaults.
- await clear_all_globals()[source]¶
Clear all global data.
This resets all global data to its registered defaults.
- await clear_all_guilds()[source]¶
Clear all guild data.
This resets all guild data to its registered defaults.
- await clear_all_members(guild=None)[source]¶
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.
- await clear_all_roles()[source]¶
Clear all role data.
This resets all role data to its registered defaults.
- await clear_all_users()[source]¶
Clear all user data.
This resets all user data to its registered defaults.
- get_channels_lock()[source]¶
Get a lock for all channel data.
- Returns
A lock for all channels data.
- Return type
- classmethod get_conf(cog_instance, identifier, force_registration=False, cog_name=None, allow_old=False)[source]¶
Get a Config instance for your cog.
Warning
If you are using this classmethod to get a second instance of an existing Config object for a particular cog, you MUST provide the correct identifier. If you do not, you will screw up all other Config instances for that cog.
- Parameters
cog_instance – This is an instance of your cog after it has been instantiated. If you’re calling this method from within your cog’s
__init__
, this is justself
.identifier (int) – A (hard-coded) random integer, used to keep your data distinct from any other cog with the same name.
force_registration (
bool
, optional) – Should config require registration of data keys before allowing you to get/set values? Seeforce_registration
.cog_name (str, optional) – Config normally uses
cog_instance
to determine the name of your cog. If you wish you may passNone
tocog_instance
and directly specify the name of your cog here.
- Returns
A new Config object.
- Return type
- classmethod get_core_conf(force_registration=False, allow_old=False)[source]¶
Get a Config instance for the core bot.
All core modules that require a config instance should use this classmethod instead of
get_conf
.- Parameters
force_registration (
bool
, optional) – Seeforce_registration
.
- get_custom_lock(group_identifier)[source]¶
Get a lock for all data in a custom scope.
- Parameters
group_identifier (str) – The group identifier for the custom scope you want to lock.
- Returns
A lock for all data in a custom scope with given group identifier.
- Return type
- get_guilds_lock()[source]¶
Get a lock for all guild data.
- Returns
A lock for all guild data.
- Return type
- get_members_lock(guild=None)[source]¶
Get a lock for all member data.
- Parameters
guild (Optional[discord.Guild]) – The guild containing the members whose data you want to lock. Omit to lock all data for all members in all guilds.
- Returns
A lock for all member data for the given guild. If
guild
is omitted this will give a lock for all data for all members in all guilds.- Return type
- get_roles_lock()[source]¶
Get a lock for all role data.
- Returns
A lock for all roles data.
- Return type
- get_users_lock()[source]¶
Get a lock for all user data.
- Returns
A lock for all user data.
- Return type
- guild(guild)[source]¶
Returns a
Group
for the given guild.- Parameters
guild (discord.Guild) – A guild object.
- Returns
The guild’s Group object.
- Return type
- init_custom(group_identifier, identifier_count)[source]¶
Initializes a custom group for usage. This method must be called first!
- member(member)[source]¶
Returns a
Group
for the given member.- Parameters
member (discord.Member) – A member object.
- Returns
The member’s Group object.
- Return type
- register_channel(**kwargs)[source]¶
Register default values on a per-channel level.
See
register_global
for more details.
- register_custom(group_identifier, **kwargs)[source]¶
Registers default values for a custom group.
See
register_global
for more details.
- register_global(**kwargs)[source]¶
Register default values for attributes you wish to store in
Config
at a global level.Examples
You can register a single value or multiple values:
config.register_global( foo=True ) config.register_global( bar=False, baz=None )
You can also now register nested values:
_defaults = { "foo": { "bar": True, "baz": False } } # Will register `foo.bar` == True and `foo.baz` == False config.register_global( **_defaults )
You can do the same thing without a
_defaults
dict by using double underscore as a variable name separator:# This is equivalent to the previous example config.register_global( foo__bar=True, foo__baz=False )
- register_guild(**kwargs)[source]¶
Register default values on a per-guild level.
See
register_global
for more details.
- register_member(**kwargs)[source]¶
Registers default values on a per-member level.
This means that each user’s data is guild-dependent.
See
register_global
for more details.
- register_role(**kwargs)[source]¶
Registers default values on a per-role level.
See
register_global
for more details.
- register_user(**kwargs)[source]¶
Registers default values on a per-user level.
This means that each user’s data is guild-independent.
See
register_global
for more details.
- role(role)[source]¶
Returns a
Group
for the given role.- Parameters
role (discord.Role) – A role object.
- Returns
The role’s Group object.
- Return type
- user(user)[source]¶
Returns a
Group
for the given user.- Parameters
user (discord.User) – A user object.
- Returns
The user’s Group object.
- Return type
Group¶
- class redbot.core.config.Group(identifier_data, defaults, driver, config, force_registration=False)[source]¶
Bases:
redbot.core.config.Value
Represents a group of data, composed of more
Group
orValue
objects.Inherits from
Value
which means that all of the attributes and methods available inValue
are also available when working with aGroup
object.- force_registration¶
Same as
Config.force_registration
.- Type
- driver¶
A reference to
Config.driver
.
- __getattr__(item)[source]¶
Get an attribute of this group.
This special method is called whenever dot notation is used on this object.
- Parameters
item (str) – The name of the attribute being accessed.
- Returns
A child value of this Group. This, of course, can be another
Group
, due to Config’s composite pattern.- Return type
- Raises
AttributeError – If the attribute has not been registered and
force_registration
is set toTrue
.
- all(*, acquire_lock=True)[source]¶
Get a dictionary representation of this group’s data.
The return value of this method can also be used as an asynchronous context manager, i.e. with
async with
syntax.Note
The return value of this method will include registered defaults for values which have not yet been set.
- Parameters
acquire_lock (bool) – Same as the
acquire_lock
keyword parameter inValue.__call__
.- Returns
All of this Group’s attributes, resolved as raw data values.
- Return type
- await clear_raw(*nested_path)[source]¶
Allows a developer to clear data as if it was stored in a standard Python dictionary.
For example:
await config.clear_raw("foo", "bar") # is equivalent to data = {"foo": {"bar": None}} del data["foo"]["bar"]
- Parameters
nested_path (Any) – Multiple arguments that mirror the arguments passed in for nested dict access. These are casted to
str
for you.
- get_attr(item)[source]¶
Manually get an attribute of this Group.
This is available to use as an alternative to using normal Python attribute access. It may be required if you find a need for dynamic attribute access.
Example
A possible use case:
@commands.command() async def some_command(self, ctx, item: str): user = ctx.author # Where the value of item is the name of the data field in Config await ctx.send(await self.config.user(user).get_attr(item).foo())
- await get_raw(*nested_path, default=Ellipsis)[source]¶
Allows a developer to access data as if it was stored in a standard Python dictionary.
For example:
d = await config.get_raw("foo", "bar") # is equivalent to data = {"foo": {"bar": "baz"}} d = data["foo"]["bar"]
Note
If retrieving a sub-group, the return value of this method will include registered defaults for values which have not yet been set.
- Parameters
- Returns
The value of the path requested.
- Return type
Any
- Raises
KeyError – If the value does not exist yet in Config’s internal storage.
- is_group(item)[source]¶
A helper method for
__getattr__
. Most developers will have no need to use this.- Parameters
item (Any) – See
__getattr__
.
- is_value(item)[source]¶
A helper method for
__getattr__
. Most developers will have no need to use this.- Parameters
item (Any) – See
__getattr__
.
- nested_update(current, defaults=Ellipsis)[source]¶
Robust updater for nested dictionaries
If no defaults are passed, then the instance attribute ‘defaults’ will be used.
- await set(value)[source]¶
Set the value of the data elements pointed to by
Identifiers and keywords
.Example
# Sets global value "foo" to False await config.foo.set(False) # Sets guild specific value of "bar" to True await config.guild(some_guild).bar.set(True)
- Parameters
value – The new literal value of this attribute.
Value¶
- class redbot.core.config.Value(identifier_data, default_value, driver, config)[source]¶
Bases:
object
A singular “value” of data.
- identifier_data¶
Information on identifiers for this value.
- Type
IdentifierData
- default¶
The default value for the data element that
Identifiers and keywords
points at.
- driver¶
A reference to
Config.driver
.
- __call__(default=Ellipsis, *, acquire_lock=True)[source]¶
Get the literal value of this data element.
Each
Value
object is created by theGroup.__getattr__
method. The “real” data of theValue
object is accessed by this method. It is a replacement for aget()
method.The return value of this method can also be used as an asynchronous context manager, i.e. with
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. It will also acquire this value’s lock to protect the critical region inside this context manager’s body, unless theacquire_lock
keyword argument is set toFalse
.Example
foo = await config.guild(some_guild).foo() # Is equivalent to this group_obj = config.guild(some_guild) value_obj = group_obj.foo foo = await value_obj()
Important
This is now, for all intents and purposes, a coroutine.
- Parameters
default (
object
, optional) – This argument acts as an override for the registered default provided bydefault
. This argument is ignored if its value is...
.acquire_lock (bool) – Set to
False
to disable the acquisition of the value’s lock over the context manager body. Defaults toTrue
. Has no effect when not used as a context manager.
- Returns
A coroutine object mixed in with an async context manager. When awaited, this returns the raw data value. When used in
async with
syntax, on gets the value on entrance, and sets it on exit.- Return type
awaitable
mixed withasynchronous context manager
- await clear()[source]¶
Clears the value from record for the data element pointed to by
Identifiers and keywords
.
- get_lock()[source]¶
Get a lock to create a critical region where this value is accessed.
When using this lock, make sure you either use it with the
async with
syntax, or if that’s not feasible, ensure you keep a reference to it from the acquisition to the release of the lock. That is, if you can’t useasync with
syntax, use the lock like this:lock = config.foo.get_lock() await lock.acquire() # Do stuff... lock.release()
Do not use it like this:
await config.foo.get_lock().acquire() # Do stuff... config.foo.get_lock().release()
Doing it the latter way will likely cause an error, as the acquired lock will be cleaned up by the garbage collector before it is released, meaning the second call to
get_lock()
will return a different lock to the first call.- Returns
A lock which is weakly cached for this value object.
- Return type
- await set(value)[source]¶
Set the value of the data elements pointed to by
Identifiers and keywords
.Example
# Sets global value "foo" to False await config.foo.set(False) # Sets guild specific value of "bar" to True await config.guild(some_guild).bar.set(True)
- Parameters
value – The new literal value of this attribute.
Driver Reference¶
- redbot.core.drivers.get_driver(cog_name, identifier, storage_type=None, *, allow_old=False, **kwargs)[source]¶
Get a driver instance.
- Parameters
cog_name (str) – The cog’s name.
identifier (str) – The cog’s discriminator.
storage_type (Optional[BackendType]) – The backend you want a driver for. Omit to try to obtain the backend from data manager.
**kwargs – Driver-specific keyword arguments.
- Returns
A driver instance.
- Return type
- Raises
RuntimeError – If the storage type is MongoV1, Mongo, or invalid.
- class redbot.core.drivers.BackendType(value)[source]¶
Bases:
enum.Enum
Represents storage backend type.
- JSON = 'JSON'¶
JSON storage backend.
- POSTGRES = 'Postgres'¶
Postgres storage backend.
- class redbot.core.drivers.ConfigCategory(value)[source]¶
-
Represents config category.
- CHANNEL = 'TEXTCHANNEL'¶
Channel category.
- GLOBAL = 'GLOBAL'¶
Global category.
- GUILD = 'GUILD'¶
Guild category.
- MEMBER = 'MEMBER'¶
Member category.
- ROLE = 'ROLE'¶
Role category.
- USER = 'USER'¶
User category.
Base Driver¶
- class redbot.core.drivers.BaseDriver(cog_name, identifier, **kwargs)[source]¶
Bases:
abc.ABC
- abstractmethod classmethod aiter_cogs()[source]¶
Get info for cogs which have data stored on this backend.
- Yields
Tuple[str, str] – Asynchronously yields (cog_name, cog_identifier) tuples.
- abstractmethod await clear(identifier_data)[source]¶
Clears out the value specified by the given identifiers.
Equivalent to using
del
on a dict.- Parameters
identifier_data –
- classmethod await delete_all_data(**kwargs)[source]¶
Delete all data being stored by this driver.
The driver must be initialized before this operation.
The BaseDriver provides a generic method which may be overridden by subclasses.
- Parameters
**kwargs – Driver-specific kwargs to change the way this method operates.
- abstractmethod await get(identifier_data)[source]¶
Finds the value indicate by the given identifiers.
- Parameters
identifier_data –
- Returns
Stored value.
- Return type
Any
- abstractmethod staticmethod get_config_details()[source]¶
Asks users for additional configuration information necessary to use this config driver.
- Returns
Dictionary of configuration details.
- Return type
Dict[str, Any]
- abstractmethod classmethod await initialize(**storage_details)[source]¶
Initialize this driver.
- Parameters
**storage_details – The storage details required to initialize this driver. Should be the same as
data_manager.storage_details()
- Raises
MissingExtraRequirements – If initializing the driver requires an extra which isn’t installed.
- classmethod await migrate_to(new_driver_cls, all_custom_group_data)[source]¶
Migrate data from this backend to another.
Both drivers must be initialized beforehand.
This will only move the data - no instance metadata is modified as a result of this operation.
- Parameters
new_driver_cls – Subclass of
BaseDriver
.all_custom_group_data (Dict[str, Dict[str, Dict[str, int]]]) – Dict mapping cog names, to cog IDs, to custom groups, to primary key lengths.
JSON Driver¶
- class redbot.core.drivers.JsonDriver(cog_name, identifier, *, data_path_override=None, file_name_override='settings.json')[source]¶
Bases:
redbot.core.drivers.base.BaseDriver
Subclass of
BaseDriver
.- file_name¶
The name of the file in which to store JSON data.
- classmethod async for ... in aiter_cogs()[source]¶
Get info for cogs which have data stored on this backend.
- Yields
Tuple[str, str] – Asynchronously yields (cog_name, cog_identifier) tuples.
- await clear(identifier_data)[source]¶
Clears out the value specified by the given identifiers.
Equivalent to using
del
on a dict.- Parameters
identifier_data –
- await get(identifier_data)[source]¶
Finds the value indicate by the given identifiers.
- Parameters
identifier_data –
- Returns
Stored value.
- Return type
Any
- staticmethod get_config_details()[source]¶
Asks users for additional configuration information necessary to use this config driver.
- Returns
Dictionary of configuration details.
- Return type
Dict[str, Any]
- classmethod await initialize(**storage_details)[source]¶
Initialize this driver.
- Parameters
**storage_details – The storage details required to initialize this driver. Should be the same as
data_manager.storage_details()
- Raises
MissingExtraRequirements – If initializing the driver requires an extra which isn’t installed.
Postgres Driver¶
- class redbot.core.drivers.PostgresDriver(cog_name, identifier, **kwargs)[source]¶
Bases:
redbot.core.drivers.base.BaseDriver
- classmethod async for ... in aiter_cogs()[source]¶
Get info for cogs which have data stored on this backend.
- Yields
Tuple[str, str] – Asynchronously yields (cog_name, cog_identifier) tuples.
- await clear(identifier_data)[source]¶
Clears out the value specified by the given identifiers.
Equivalent to using
del
on a dict.- Parameters
identifier_data –
- classmethod await delete_all_data(*, drop_db=None, **kwargs)[source]¶
Delete all data being stored by this driver.
Schemas within the database which store bot data will be dropped, as well as functions, aggregates, event triggers, and meta-tables.
- Parameters
drop_db (Optional[bool]) – If set to
True
, function will print information about not being able to drop the entire database.
- await get(identifier_data)[source]¶
Finds the value indicate by the given identifiers.
- Parameters
identifier_data –
- Returns
Stored value.
- Return type
Any
- staticmethod get_config_details()[source]¶
Asks users for additional configuration information necessary to use this config driver.
- Returns
Dictionary of configuration details.
- Return type
Dict[str, Any]
- classmethod await initialize(**storage_details)[source]¶
Initialize this driver.
- Parameters
**storage_details – The storage details required to initialize this driver. Should be the same as
data_manager.storage_details()
- Raises
MissingExtraRequirements – If initializing the driver requires an extra which isn’t installed.