def load(obj, namespace=None, silent=True, key=None): """ Reads and loads in to "settings" a single key or all keys from redis :param obj: the settings instance :param namespace: settings namespace default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in namespace :return: None """ redis = StrictRedis(**obj.REDIS_FOR_DYNACONF) namespace = namespace or obj.DYNACONF_NAMESPACE holder = "DYNACONF_%s" % namespace try: if key: value = parse_conf_data(redis.hget(holder.upper(), key)) if value: obj.set(key, value) else: data = { key: parse_conf_data(value) for key, value in redis.hgetall(holder.upper()).items() } if data: obj.update(data, loader_identifier=IDENTIFIER) except Exception as e: e.message = 'Unable to load config from redis (%s)' % e.message if silent: obj.logger.error(e.message) return False raise
def test_casting_bool(settings): res = parse_conf_data("@bool true") assert isinstance(res, bool) and res is True settings.set("value", "true") res = parse_conf_data("@bool @jinja {{ this.value }}")(settings) assert isinstance(res, bool) and res is True settings.set("value", "false") res = parse_conf_data("@bool @format {this.value}")(settings) assert isinstance(res, bool) and res is False
def test_meta_values(settings): reset = parse_conf_data( "@reset [1, 2]", tomlfy=True, box_settings=settings ) assert reset.value == [1, 2] assert reset._dynaconf_reset is True assert "Reset([1, 2])" in repr(reset) _del = parse_conf_data("@del", tomlfy=True, box_settings=settings) assert _del.value == "" assert _del._dynaconf_del is True assert "Del()" in repr(_del)
def test_meta_values(settings): reset = parse_conf_data("@reset [1, 2]", tomlfy=True, box_settings=settings) # @reset is DEPRECATED in v3.0.0 but kept for backwards compatibility assert reset.value == [1, 2] assert reset._dynaconf_reset is True assert "Reset([1, 2])" in repr(reset) _del = parse_conf_data("@del", tomlfy=True, box_settings=settings) assert _del.value == "" assert _del._dynaconf_del is True assert "Del()" in repr(_del)
def load_from_env( obj, prefix=False, key=None, silent=False, identifier=IDENTIFIER, env=False, # backwards compatibility bc renamed param ): if prefix is False and env is not False: prefix = env env_ = "" if prefix is not False: if not isinstance(prefix, str): raise TypeError("`prefix/env` must be str or False") prefix = prefix.upper() env_ = f"{prefix}_" # Load a single environment variable explicitly. if key: key = upperfy(key) value = environ.get(f"{env_}{key}") if value: try: # obj is a Settings obj.set(key, value, loader_identifier=identifier, tomlfy=True) except AttributeError: # obj is a dict obj[key] = parse_conf_data(value, tomlfy=True, box_settings=obj) # Load environment variables in bulk (when matching). else: # Only known variables should be loaded from environment. ignore_unknown = obj.get("IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF") known_keys = set(obj.store) trim_len = len(env_) data = { key[trim_len:]: parse_conf_data(data, tomlfy=True, box_settings=obj) for key, data in environ.items() if key.startswith(env_) and not ( # Ignore environment variables that haven't been # pre-defined in settings space. ignore_unknown and key[trim_len:] not in known_keys) } # Update the settings space based on gathered data from environment. if data: obj.update(data, loader_identifier=identifier)
def load(obj, env=None, silent=True, key=None): """Reads and loads in to "settings" a single key or all keys from redis :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: None """ redis = StrictRedis(**obj.get("REDIS_FOR_DYNACONF")) prefix = obj.get("ENVVAR_PREFIX_FOR_DYNACONF") # prefix is added to env_list to keep backwards compatibility env_list = [prefix] + build_env_list(obj, env or obj.current_env) for env_name in env_list: holder = "{0}_{1}".format(prefix.upper(), env_name.upper()) try: if key: value = redis.hget(holder.upper(), key) if value: obj.logger.debug( "redis_loader: loading by key: %s:%s (%s:%s)", key, value, IDENTIFIER, holder, ) if value: parsed_value = parse_conf_data(value, tomlfy=True) if parsed_value: obj.set(key, parsed_value) else: data = { key: parse_conf_data(value, tomlfy=True) for key, value in redis.hgetall(holder.upper()).items() } if data: obj.logger.debug( "redis_loader: loading: %s (%s:%s)", data, IDENTIFIER, holder, ) obj.update(data, loader_identifier=IDENTIFIER) except Exception as e: if silent: if hasattr(obj, "logger"): obj.logger.error(str(e)) return False raise
def load_from_env(identifier, key, env, obj, silent): env_ = "" if env is not False: env = env.upper() env_ = f"{env}_" try: if key: value = environ.get(f"{env_}{key}") if value: obj.logger.debug( f"env_loader: loading by key: {key}:{value} " f"({identifier}:{env})" ) obj.set(key, value, loader_identifier=identifier, tomlfy=True) else: trim_len = len(env_) data = { key[trim_len:]: parse_conf_data(data, tomlfy=True) for key, data in environ.items() if key.startswith(env_) } if data: obj.logger.debug( f"env_loader: loading: {data} ({identifier}:{env})" ) obj.update(data, loader_identifier=identifier) # box.exceptions.BoxKeyError except Exception as e: # pragma: no cover e.message = f"env_loader: Error ({str(e)})" if silent: obj.logger.error(str(e)) else: raise
def set(self, key, value, loader_identifier=None, tomlfy=False): """Set a value storing references for the loader :param key: The key to store :param value: The value to store :param loader_identifier: Optional loader name e.g: toml, yaml etc. :param tomlfy: Bool define if value is parsed by toml (defaults False) """ value = parse_conf_data(value, tomlfy=tomlfy) if isinstance(value, dict): value = DynaBox(value, box_it_up=True) key = key.strip().upper() setattr(self, key, value) self.store[key] = value self._deleted.discard(key) # set loader identifiers so cleaners know which keys to clean if loader_identifier and loader_identifier in self.loaded_by_loaders: self.loaded_by_loaders[loader_identifier][key] = value elif loader_identifier: self.loaded_by_loaders[loader_identifier] = {key: value} elif loader_identifier is None: # if .set is called without loader identifier it becomes # a default value and goes away only when explicitly unset self._defaults[key] = value
def split_vars(_vars): """Splits values like foo=bar=zaz in {'foo': 'bar=zaz'}""" return ({ upperfy(k.strip()): parse_conf_data( v.strip(), tomlfy=True, box_settings=settings) for k, _, v in [item.partition("=") for item in _vars] } if _vars else {})
def load_from_env(identifier, key, env, obj, silent): env_ = "" if env is not False: env = env.upper() env_ = "{0}_".format(env) try: if key: value = os.environ.get("{0}{1}".format(env_, key)) if value: obj.logger.debug( "env_loader: loading by key: %s:%s (%s:%s)", key, value, identifier, env, ) obj.set(key, value, loader_identifier=identifier, tomlfy=True) else: trim_len = len(env_) data = { key[trim_len:]: parse_conf_data(data, tomlfy=True) for key, data in os.environ.items() if key.startswith(env_) } if data: obj.logger.debug("env_loader: loading: %s (%s:%s)", data, identifier, env) obj.update(data, loader_identifier=identifier) except Exception as e: # pragma: no cover e.message = ("env_loader: Error ({0})").format(str(e)) if silent: obj.logger.error(str(e)) else: raise
def _dotted_get( self, dotted_key, default=None, parent=None, cast=None, **kwargs ): """ Perform dotted key lookups and keep track of where we are. :param key: The name of the setting value, will always be upper case :param default: In case of not found it will be returned :param parent: Is there a pre-loaded parent in a nested data? """ split_key = dotted_key.split(".") name, keys = split_key[0], split_key[1:] result = self.get(name, default=default, parent=parent, **kwargs) # If we've reached the end, or parent key not found, then return result if not keys or result == default: if cast and cast in converters: return get_converter(cast, result, box_settings=self) elif cast is True: return parse_conf_data(result, tomlfy=True, box_settings=self) return result # If we've still got key elements to traverse, let's do that. return self._dotted_get( ".".join(keys), default=default, parent=result, cast=cast, **kwargs )
def _dotted_set(self, dotted_key, value, tomlfy=False, **kwargs): """Sets dotted keys as nested dictionaries. Dotted set will always reassign the value, to merge use `@merge` token Arguments: dotted_key {str} -- A traversal name e.g: foo.bar.zaz value {Any} -- The value to set to the nested value. Keyword Arguments: tomlfy {bool} -- Perform toml parsing (default: {False}) """ split_keys = dotted_key.split(".") existing_data = self.get(split_keys[0], {}) new_data = DynaBox() tree = new_data for k in split_keys[:-1]: tree = tree.setdefault(k, {}) value = parse_conf_data(value, tomlfy=tomlfy) tree[split_keys[-1]] = value if existing_data: object_merge( old={split_keys[0]: existing_data}, new=new_data, tail=split_keys[-1], ) self.update(data=new_data, tomlfy=tomlfy, **kwargs)
def _dotted_set(self, dotted_key, value, tomlfy=False, merge=True, **kwargs): """Sets dotted keys as nested dictionaries. Arguments: dotted_key {str} -- A traversal name e.g: foo.bar.zaz value {Any} -- The value to set to the nested value. Keyword Arguments: tomlfy {bool} -- Perform toml parsing (default: {False}) merge {bool} -- Merge existing dictionaries (default: {True}) """ split_keys = dotted_key.split(".") existing_data = self.get(split_keys[0], {}) if merge else {} new_data = DynaBox(default_box=True) tree = new_data for k in split_keys[:-1]: tree = tree.setdefault(k, {}) value = parse_conf_data(value, tomlfy=tomlfy) tree[split_keys[-1]] = value if existing_data and merge: object_merge({split_keys[0]: existing_data}, new_data) self.update(data=new_data, tomlfy=tomlfy, **kwargs)
def load(obj, env=None, silent=None, key=None): """Reads and loads in to "settings" a single key or all keys from vault :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: None """ client = get_client(obj) holder = obj.get('GLOBAL_ENV_FOR_DYNACONF') path = os.path.join(obj.VAULT_PATH_FOR_DYNACONF, holder.lower()) data = client.read(path) if data: data = data.get('data', {}).get('data') try: if data and key: value = parse_conf_data(data.get(key), tomlfy=True) if value: obj.logger.debug("vault_loader: loading by key: %s:%s (%s:%s)", key, '****', IDENTIFIER, holder) obj.set(key, value) elif data: obj.logger.debug("vault_loader: loading: %s (%s:%s)", list(data.keys()), IDENTIFIER, holder) obj.update(data, loader_identifier=IDENTIFIER, tomlfy=True) except Exception as e: if silent: if hasattr(obj, 'logger'): obj.logger.error(str(e)) return False raise
def load(obj, env=None, silent=True, key=None, filename=None): """ Reads and loads in to "obj" a single key or all keys from source :param obj: the settings instance :param env: settings current env (upper case) default='DEVELOPMENT' :param silent: if errors should raise :param key: if defined load a single key, else load all from `env` :param filename: Custom filename to load (useful for tests) :return: None """ # Load data from your custom data source (file, database, memory etc) # use `obj.set(key, value)` or `obj.update(dict)` to load data # use `obj.find_file('filename.ext')` to find the file in search tree # Return nothing prefix = "" if obj.get("AWS_SSM_PREFIX"): prefix = "/{}".format(obj.AWS_SSM_PREFIX) path = "{}/{}/".format(prefix, env.lower()) if key: path = "{}{}/".format(path, key) data = _read_aws_ssm_parameters(path) try: if data and key: value = parse_conf_data(data.get(key), tomlfy=True, box_settings=obj) if value: obj.set(key, value) elif data: obj.update(data, loader_identifier=IDENTIFIER, tomlfy=True) except Exception as e: if silent: return False raise
def split_vars(_vars): """Splits values like foo=bar=zaz in {'foo': 'bar=zaz'}""" return { k.upper().strip(): parse_conf_data(v.strip(), tomlfy=True) for k, _, v in [item.partition('=') for item in _vars] } if _vars else {}
def test_tomlfy(): assert parse_conf_data("1", tomlfy=True) == 1 assert parse_conf_data("true", tomlfy=True) is True assert parse_conf_data("'true'", tomlfy=True) == 'true' assert parse_conf_data('"42"', tomlfy=True) == "42" assert parse_conf_data("[1, 32, 3]", tomlfy=True) == [1, 32, 3] assert parse_conf_data("[1.1, 32.1, 3.3]", tomlfy=True) == [1.1, 32.1, 3.3] assert parse_conf_data("['a', 'b', 'c']", tomlfy=True) == ['a', 'b', 'c'] assert parse_conf_data("[true, false]", tomlfy=True) == [True, False] assert parse_conf_data("{key='value', v=1}", tomlfy=True) == { 'key': 'value', 'v': 1 }
def test_tomlfy(): assert parse_conf_data("1", tomlfy=True) == 1 assert parse_conf_data("true", tomlfy=True) is True assert parse_conf_data("'true'", tomlfy=True) == "true" assert parse_conf_data('"42"', tomlfy=True) == "42" assert parse_conf_data("[1, 32, 3]", tomlfy=True) == [1, 32, 3] assert parse_conf_data("[1.1, 32.1, 3.3]", tomlfy=True) == [1.1, 32.1, 3.3] assert parse_conf_data("['a', 'b', 'c']", tomlfy=True) == ["a", "b", "c"] assert parse_conf_data("[true, false]", tomlfy=True) == [True, False] assert parse_conf_data("{key='value', v=1}", tomlfy=True) == { "key": "value", "v": 1, }
def get(key, default=None): value = os.environ.get(upperfy(key)) # compatibility with renamed variables for old, new in RENAMED_VARS.items(): value = try_renamed(key, value, old, new) return (parse_conf_data(value, tomlfy=True) if value is not None else default)
def settings_module(self): """Gets SETTINGS_MODULE variable""" settings_module = parse_conf_data( os.environ.get(self.ENVVAR_FOR_DYNACONF, self.SETTINGS_FILE_FOR_DYNACONF), tomlfy=True, ) if settings_module != getattr(self, "SETTINGS_MODULE", None): self.set("SETTINGS_MODULE", settings_module) return self.SETTINGS_MODULE
def load(obj, env=None, silent=True, key=None): """Reads and loads in to "settings" a single key or all keys from redis :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: None """ if StrictRedis is None: raise ImportError( "redis package is not installed in your environment. " "`pip install dynaconf[redis]` or disable the redis loader with " "export REDIS_ENABLED_FOR_DYNACONF=false" ) redis = StrictRedis(**obj.get("REDIS_FOR_DYNACONF")) prefix = obj.get("ENVVAR_PREFIX_FOR_DYNACONF") # prefix is added to env_list to keep backwards compatibility env_list = [prefix] + build_env_list(obj, env or obj.current_env) for env_name in env_list: holder = f"{prefix.upper()}_{env_name.upper()}" try: if key: value = redis.hget(holder.upper(), key) if value: parsed_value = parse_conf_data( value, tomlfy=True, box_settings=obj ) if parsed_value: obj.set(key, parsed_value) else: data = { key: parse_conf_data(value, tomlfy=True, box_settings=obj) for key, value in redis.hgetall(holder.upper()).items() } if data: obj.update(data, loader_identifier=IDENTIFIER) except Exception: if silent: return False raise
def set(self, key, value, loader_identifier=None): """Set a value storing references for the loader""" value = parse_conf_data(value) key = key.strip().upper() setattr(self, key, value) self.store[key] = value if loader_identifier and loader_identifier in self.loaded_by_loaders: self.loaded_by_loaders[loader_identifier][key] = value elif loader_identifier: self.loaded_by_loaders[loader_identifier] = {key: value}
def load_from_env( obj, prefix=False, key=None, silent=False, identifier=IDENTIFIER, env=False, # backwards compatibility bc renamed param ): if prefix is False and env is not False: prefix = env env_ = "" if prefix is not False: if not isinstance(prefix, str): raise TypeError("`prefix/env` must be str or False") prefix = prefix.upper() env_ = f"{prefix}_" logger = get_logger(obj) if key: key = upperfy(key) value = environ.get(f"{env_}{key}") if value: logger.debug(f"env_loader: loading by key: " f"{key}:{value} ({identifier}:{prefix})") try: # obj is a Settings obj.set(key, value, loader_identifier=identifier, tomlfy=True) except AttributeError: # obj is a dict obj[key] = parse_conf_data(value, tomlfy=True) else: trim_len = len(env_) data = { key[trim_len:]: parse_conf_data(data, tomlfy=True) for key, data in environ.items() if key.startswith(env_) } if data: logger.debug( f"env_loader: loading: {data} ({identifier}:{prefix})") obj.update(data, loader_identifier=identifier)
def load(obj, env=None, silent=None, key=None): """Reads and loads in to "settings" a single key or all keys from vault :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: None """ client = get_client(obj) try: dirs = client.secrets.kv.list_secrets( path=obj.VAULT_PATH_FOR_DYNACONF, mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF, )["data"]["keys"] except InvalidPath: # The given path is not a directory dirs = [] env_list = build_env_list(obj, env) + dirs for env in env_list: path = "/".join([obj.VAULT_PATH_FOR_DYNACONF, env]) try: if obj.VAULT_KV_VERSION_FOR_DYNACONF == 2: data = client.secrets.kv.v2.read_secret_version( path, mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF) else: data = client.secrets.kv.read_secret( "data/" + path, mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF, ) except InvalidPath: # If the path doesn't exist, ignore it and set data to None data = None if data: # There seems to be a data dict within a data dict, # extract the inner data data = data.get("data", {}).get("data", {}) try: if obj.VAULT_KV_VERSION_FOR_DYNACONF == 2 and data: data = data.get("data", {}) if data and key: value = parse_conf_data(data.get(key), tomlfy=True, box_settings=obj) if value: obj.set(key, value) elif data: obj.update(data, loader_identifier=IDENTIFIER, tomlfy=True) except Exception: if silent: return False raise
def _dotted_set(self, dotted_key, value, tomlfy=False, **kwargs): data = DynaBox(default_box=True) tree = data split_keys = dotted_key.split(".") for k in split_keys[:-1]: tree = tree.setdefault(k, {}) value = parse_conf_data(value, tomlfy=tomlfy) tree[split_keys[-1]] = value self.update(data=data, **kwargs)
def get(key, default=None): value = os.environ.get(key.upper()) # compatibility renames before 1.x version value = try_renamed(key, value, 'ENV_FOR_DYNACONF', 'NAMESPACE_FOR_DYNACONF') value = try_renamed(key, value, 'ENV_FOR_DYNACONF', 'DYNACONF_NAMESPACE') value = try_renamed(key, value, 'DEFAULT_ENV_FOR_DYNACONF', 'BASE_NAMESPACE_FOR_DYNACONF') value = try_renamed(key, value, 'SETTINGS_MODULE_FOR_DYNACONF', 'DYNACONF_SETTINGS') return parse_conf_data(value, tomlfy=True) if value is not None else default
def load(obj, env=None, silent=None, key=None): """Reads and loads in to "settings" a single key or all keys from vault :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: None """ client = get_client(obj) env_list = _get_env_list(obj, env) for env in env_list: path = "/".join([obj.VAULT_PATH_FOR_DYNACONF, env]) try: data = client.secrets.kv.read_secret_version(path) except InvalidPath: # If the path doesn't exist, ignore it and set data to None data = None if data: # There seems to be a data dict within a data dict, # extract the inner data data = data.get("data", {}).get("data", {}) try: if data and key: value = parse_conf_data(data.get(key), tomlfy=True) if value: obj.logger.debug( "vault_loader: loading by key: %s:%s (%s:%s)", key, "****", IDENTIFIER, path, ) obj.set(key, value) elif data: obj.logger.debug( "vault_loader: loading: %s (%s:%s)", list(data.keys()), IDENTIFIER, path, ) obj.update(data, loader_identifier=IDENTIFIER, tomlfy=True) except Exception as e: if silent: if hasattr(obj, "logger"): obj.logger.error(str(e)) return False raise
def load(obj, env=None, silent=True, key=None): """Reads and loads in to "settings" a single key or all keys from redis :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: None """ redis = StrictRedis(**obj.get('REDIS_FOR_DYNACONF')) holder = obj.get('GLOBAL_ENV_FOR_DYNACONF') try: if key: value = redis.hget(holder.upper(), key) if value: obj.logger.debug("redis_loader: loading by key: %s:%s (%s:%s)", key, value, IDENTIFIER, holder) if value: parsed_value = parse_conf_data(value, tomlfy=True) if parsed_value: obj.set(key, parsed_value) else: data = { key: parse_conf_data(value, tomlfy=True) for key, value in redis.hgetall(holder.upper()).items() } if data: obj.logger.debug("redis_loader: loading: %s (%s:%s)", data, IDENTIFIER, holder) obj.update(data, loader_identifier=IDENTIFIER) except Exception as e: if silent: if hasattr(obj, 'logger'): obj.logger.error(str(e)) return False raise
def settings_module(self): """Gets SETTINGS_MODULE variable""" settings_module = parse_conf_data( os.environ.get(self.ENVVAR_FOR_DYNACONF, self.SETTINGS_FILE_FOR_DYNACONF), tomlfy=True, box_settings=self, ) if settings_module != getattr(self, "SETTINGS_MODULE", None): self.set("SETTINGS_MODULE", settings_module) # This is for backewards compatibility, to be removed on 4.x.x if not self.SETTINGS_MODULE and self.get("default_settings_paths"): self.SETTINGS_MODULE = self.get("default_settings_paths") return self.SETTINGS_MODULE
def get_env(self, key, default=None, cast=None): """ Get value from environment variable using os.environ.get :param key: The name of the setting value, will always be upper case :param default: In case of not found it will be returned :param cast: Should cast in to @int, @float, @bool or @json ? or cast must be true to use cast inference :return: The value if found, default or None """ key = key.upper() data = self.env.get(key, default) if data: if cast in converters: data = converters.get(cast)(data) if cast is True: data = parse_conf_data(data) return data
def set( self, key, value, loader_identifier=None, tomlfy=False, dotted_lookup=True, is_secret=False, ): """Set a value storing references for the loader :param key: The key to store :param value: The value to store :param loader_identifier: Optional loader name e.g: toml, yaml etc. :param tomlfy: Bool define if value is parsed by toml (defaults False) :param is_secret: Bool define if secret values is hidden on logs. """ if "." in key and dotted_lookup is True: return self._dotted_set(key, value, loader_identifier=loader_identifier, tomlfy=tomlfy) value = parse_conf_data(value, tomlfy=tomlfy) key = key.strip().upper() existing = getattr(self, key, None) if existing is not None and existing != value: value = self._merge_before_set(key, existing, value, is_secret) if isinstance(value, dict): value = DynaBox(value, box_it_up=True) setattr(self, key, value) self.store[key] = value self._deleted.discard(key) # set loader identifiers so cleaners know which keys to clean if loader_identifier and loader_identifier in self.loaded_by_loaders: self.loaded_by_loaders[loader_identifier][key] = value elif loader_identifier: self.loaded_by_loaders[loader_identifier] = {key: value} elif loader_identifier is None: # if .set is called without loader identifier it becomes # a default value and goes away only when explicitly unset self._defaults[key] = value
def load(obj, namespace=None, silent=True, key=None): namespace = namespace or obj.DYNACONF_NAMESPACE try: if key: value = os.environ.get('%s_%s' % (namespace.upper(), key)) if value: obj.set(key, value) else: data = { key.partition('_')[-1]: parse_conf_data(data) for key, data in os.environ.items() if key.startswith('%s_' % namespace.upper()) } obj.update(data, loader_identifier=IDENTIFIER) except Exception as e: e.message = 'Unable to load config env namespace (%s)' % e.message if silent: obj.logger.error(e.message) return False raise
def parse_data(data): """Return converted data from @int, @float, @bool, @json markers""" return parse_conf_data(data)