from __future__ import annotations from io import TextIOWrapper from typing import Callable, TypeAlias FileParser: TypeAlias = Callable[[TextIOWrapper], dict[str, str]] def load_data(obj, file_parser: FileParser, extensions: tuple[str, ...], **kwargs): """ Utility to load data to dynaconf settings from files that match `extensions` using custom file_reader :obj: the obj provided by `load()` (a settings instance) :param file_parser: a function that receives a file stream and return it's content as a dict :extensions: the extensions used to select which files will be read. """ if filename := kwargs.get("filename"): with open(filename) as open_file: data = file_parser(open_file) obj.update(data) obj._loaded_files.append(filename) else: # get all filenames with given extension all_files = obj.settings_file or obj.settings_files sff_files = [file for file in all_files if file.endswith(extensions)] # read all selected files for file in all_files: with open(file) as open_file: data = file_parser(open_file) obj.update(data) obj._loaded_files.append(file) def load(obj, *args, **kwargs): """ 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 # This loader reads the .sff file // Stupid File Format SFF_EXTENSIONS = (".sff", ".sfx") def file_parser(file: TextIOWrapper): """Should be implemented by the user to parse his own filetype""" keys = [] values = [] for line in file.readlines(): if line.startswith("#"): continue if line.startswith("KEYS:"): keys = line.strip("KEYS:").strip("\n").split(";") if line.startswith("VALUES:"): values = line.strip("VALUES:").strip("\n").split(";") return dict(zip(keys, values)) load_data(obj, file_parser, SFF_EXTENSIONS, **kwargs)