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()
@commands.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()
@commands.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:

  1. Global doesn’t have anything in between self.config and the variable.

  2. Both the getters and setters need to be awaited because they’re coroutines.

  3. If you’re getting the value, the syntax is:

    self.config.<insert scope here, or nothing if global>.variable_name()
    
  4. 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 retrieved, 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.

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


class ChannelAccess(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()
    @commands.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()
    await 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. Use get_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 no global method because global data is accessed by normal attribute access:

await config.foo()
cog_name

The name of the cog that has requested a Config object.

Type:

str

unique_identifier

Unique identifier provided to differentiate cog data when name conflicts occur.

Type:

int

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:

bool

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.

Returns:

A dictionary in the form {int: dict} mapping CHANNEL_ID -> data.

Return type:

dict

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.

Returns:

A dictionary in the form {int: dict} mapping GUILD_ID -> data.

Return type:

dict

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 map MEMBER_ID -> data. Otherwise, the dict maps 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:

A dictionary of all specified member data.

Return type:

dict

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.

Returns:

A dictionary in the form {int: dict} mapping ROLE_ID -> data.

Return type:

dict

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.

Returns:

A dictionary in the form {int: dict} mapping USER_ID -> data.

Return type:

dict

channel(channel)[source]

Returns a Group for the given channel.

This does not discriminate between text and voice channels.

Parameters:

channel (discord.abc.GuildChannel or discord.Thread) – A channel object.

Returns:

The channel’s Group object.

Return type:

Group

channel_from_id(channel_id)[source]

Returns a Group for the given channel id.

This does not discriminate between text and voice channels.

Parameters:

channel_id (int) – A channel id.

Returns:

The channel’s Group object.

Return type:

Group

Raises:

TypeError – If the given channel_id parameter is not of type int

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.

Parameters:

group_identifier (str) – The identifier for the custom group. This is casted to str for you.

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.

custom(group_identifier, *identifiers)[source]

Returns a Group for the given custom group.

Parameters:
  • group_identifier (str) – Used to identify the custom group.

  • identifiers (str) – The attributes necessary to uniquely identify an entry in the custom group. These are casted to str for you.

Returns:

The custom group’s Group object.

Return type:

Group

get_channels_lock()[source]

Get a lock for all channel data.

Returns:

A lock for all channels data.

Return type:

asyncio.Lock

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 just self.

  • 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? See force_registration.

  • cog_name (str, optional) – Config normally uses cog_instance to determine the name of your cog. If you wish you may pass None to cog_instance and directly specify the name of your cog here.

Returns:

A new Config object.

Return type:

Config

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) – See force_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:

asyncio.Lock

get_guilds_lock()[source]

Get a lock for all guild data.

Returns:

A lock for all guild data.

Return type:

asyncio.Lock

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:

asyncio.Lock

get_roles_lock()[source]

Get a lock for all role data.

Returns:

A lock for all roles data.

Return type:

asyncio.Lock

get_users_lock()[source]

Get a lock for all user data.

Returns:

A lock for all user data.

Return type:

asyncio.Lock

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:

Group

guild_from_id(guild_id)[source]

Returns a Group for the given guild id.

Parameters:

guild_id (int) – A guild id.

Returns:

The guild’s Group object.

Return type:

Group

Raises:

TypeError – If the given guild_id parameter is not of type int

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:

Group

member_from_ids(guild_id, member_id)[source]

Returns a Group for the ids which represent a member.

Parameters:
  • guild_id (int) – The id of the guild of the member

  • member_id (int) – The id of the member

Returns:

The member’s Group object.

Return type:

Group

Raises:

TypeError – If the given guild_id or member_id parameter is not of type int

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:

Group

role_from_id(role_id)[source]

Returns a Group for the given role id.

Parameters:

role_id (int) – A role id.

Returns:

The role’s Group object.

Return type:

Group

Raises:

TypeError – If the given role_id parameter is not of type int

user(user)[source]

Returns a Group for the given user.

Parameters:

user (discord.abc.User) – A user object.

Returns:

The user’s Group object.

Return type:

Group

user_from_id(user_id)[source]

Returns a Group for the given user id.

Parameters:

user_id (int) – The user’s id

Returns:

The user’s Group object.

Return type:

Group

Raises:

TypeError – If the given user_id parameter is not of type int

Group

class redbot.core.config.Group(identifier_data, defaults, driver, config, force_registration=False)[source]

Bases: Value

Represents a group of data, composed of more Group or Value objects.

Inherits from Value which means that all of the attributes and methods available in Value are also available when working with a Group object.

This class should not be instantiated directly - you should get instances of this class through methods and attribute lookup on instances of Config and Group.

defaults

All registered default values for this Group.

Type:

dict

force_registration

Same as Config.force_registration.

Type:

bool

__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:

Group or Value

Raises:

AttributeError – If the attribute has not been registered and force_registration is set to True.

__init__(identifier_data, defaults, driver, config, force_registration=False)[source]
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 in Value.__call__.

Returns:

All of this Group’s attributes, resolved as raw data values.

Return type:

dict

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())
Parameters:

item (str) – The name of the data field in Config. This is casted to str for you.

Returns:

The attribute which was requested.

Return type:

Value or Group

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:
  • nested_path (str) – Multiple arguments that mirror the arguments passed in for nested dict access. These are casted to str for you.

  • default – Default argument for the value attempting to be accessed. If the value does not exist the default will be returned.

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.

await set_raw(*nested_path, value)[source]

Allows a developer to set data as if it was stored in a standard Python dictionary.

For example:

await config.set_raw("foo", "bar", value="baz")

# is equivalent to

data = {"foo": {"bar": None}}
data["foo"]["bar"] = "baz"
Parameters:
  • nested_path (Any) – Multiple arguments that mirror the arguments passed in for nested dict access. These are casted to str for you.

  • value – The value to store.

Value

class redbot.core.config.Value(identifier_data, default_value, driver, config)[source]

Bases: object

A singular “value” of data.

This class should not be instantiated directly - you should get instances of this class through methods and attribute lookup on instances of Config and Group.

identifier_data

Information on identifiers for this value.

Type:

IdentifierData

default

The default value for the data element that Identifiers and keywords points at.

__call__(default=Ellipsis, *, acquire_lock=True)[source]

Get the literal value of this data element.

Each Value object is created by the Group.__getattr__ method. The “real” data of the Value object is accessed by this method. It is a replacement for a get() 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 the acquire_lock keyword argument is set to False.

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 by default. 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 to True. 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 with asynchronous 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 use async 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:

asyncio.Lock

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.

IdentifierData

class redbot.core.config.IdentifierData(cog_name, uuid, category, primary_key, identifiers, primary_key_len, is_custom=False)[source]

Bases: object

ConfigCategory

class redbot.core.config.ConfigCategory(value)[source]

Bases: str, Enum

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.

classmethod get_pkey_info(category, custom_group_data)[source]

Get the full primary key length for the given category, and whether or not the category is a custom category.