From f6361992e35c6736fb05fdeb83eac4ec23081592 Mon Sep 17 00:00:00 2001 From: Michael H Date: Fri, 28 Feb 2020 15:37:35 -0500 Subject: [PATCH] Use a metaclass for config's singletons (#3137) * Usea metaclass for config's singletons * make this a little safer --- redbot/core/config.py | 50 +++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/redbot/core/config.py b/redbot/core/config.py index bd2f1da39..e7a57bf61 100644 --- a/redbot/core/config.py +++ b/redbot/core/config.py @@ -30,6 +30,33 @@ _config_cache = weakref.WeakValueDictionary() _retrieved = weakref.WeakSet() +class ConfigMeta(type): + """ + We want to prevent re-initializing existing config instances while having a singleton + """ + + def __call__( + cls, + cog_name: str, + unique_identifier: str, + driver: BaseDriver, + force_registration: bool = False, + defaults: dict = None, + ): + if cog_name is None: + raise ValueError("You must provide either the cog instance or a cog name.") + + key = (cog_name, unique_identifier) + if key in _config_cache: + return _config_cache[key] + + instance = super(ConfigMeta, cls).__call__( + cog_name, unique_identifier, driver, force_registration, defaults + ) + _config_cache[key] = instance + return instance + + def get_latest_confs() -> Tuple["Config"]: global _retrieved ret = set(_config_cache.values()) - set(_retrieved) @@ -562,7 +589,7 @@ class Group(Value): await self.driver.set(identifier_data, value=value) -class Config: +class Config(metaclass=ConfigMeta): """Configuration manager for cogs and Red. You should always use `get_conf` to instantiate a Config object. Use @@ -605,19 +632,6 @@ class Config: USER = "USER" MEMBER = "MEMBER" - def __new__(cls, cog_name, unique_identifier, *args, **kwargs): - key = (cog_name, unique_identifier) - - if key[0] is None: - raise ValueError("You must provide either the cog instance or a cog name.") - - if key in _config_cache: - conf = _config_cache[key] - else: - conf = object.__new__(cls) - _config_cache[key] = conf - return conf - def __init__( self, cog_name: str, @@ -893,10 +907,10 @@ class Config: """ Initializes a custom group for usage. This method must be called first! """ - if group_identifier in self.custom_groups: - raise ValueError(f"Group identifier already registered: {group_identifier}") - - self.custom_groups[group_identifier] = identifier_count + if identifier_count != self.custom_groups.setdefault(group_identifier, identifier_count): + raise ValueError( + f"Cannot change identifier count of already registered group: {group_identifier}" + ) def _get_base_group(self, category: str, *primary_keys: str) -> Group: """