def load(self, filename=None, key=None, silent=True): """ Reads and loads in to `self.obj` a single key or all keys from source :param filename: Optional filename to load :param key: if provided load a single key :param silent: if load erros should be silenced """ filename = filename or self.obj.get(self.identifier.upper()) if not filename: return if not isinstance(filename, (list, tuple)): split_files = ensure_a_list(filename) if all([f.endswith(self.extensions) for f in split_files]): # noqa files = split_files # it is a ['file.ext', ...] else: # it is a single config as string files = [filename] else: # it is already a list/tuple files = filename source_data = self.get_source_data(files) if self.obj.get("ENVIRONMENTS_FOR_DYNACONF") is False: self._envless_load(source_data, silent, key) else: self._load_all_envs(source_data, silent, key)
def load(self, filename=None, key=None, silent=True): """ Reads and loads in to `self.obj` a single key or all keys from source :param filename: Optional filename to load :param key: if provided load a single key :param silent: if load erros should be silenced """ filename = filename or self.obj.get(self.identifier.upper()) if not filename: return if not isinstance(filename, (list, tuple)): split_files = ensure_a_list(filename) if all([f.endswith(self.extensions) for f in split_files]): # noqa files = split_files # it is a ['file.ext', ...] else: # it is a single config as string files = [filename] else: # it is already a list/tuple files = filename self.obj._loaded_files.extend(files) env_list = build_env_list(self.obj, self.env) # load all envs self._read(files, env_list, silent, key)
def load_includes(self, env, silent, key): """Do we have any nested includes we need to process?""" includes = self.get("DYNACONF_INCLUDE", []) includes.extend(ensure_a_list(self.get("INCLUDES_FOR_DYNACONF"))) if includes: self.logger.debug("Processing includes %s", includes) self.load_file(path=includes, env=env, silent=silent, key=key)
def load_includes(self, env, silent, key): """Do we have any nested includes we need to process?""" includes = self.get("DYNACONF_INCLUDE", []) includes.extend(ensure_a_list(self.get("INCLUDES_FOR_DYNACONF"))) if includes: self.load_file(path=includes, env=env, silent=silent, key=key) # ensure env vars are the last thing loaded after all includes last_loader = self.loaders and self.loaders[-1] if last_loader and last_loader == env_loader: last_loader.load(self, env, silent, key)
def validate( self, settings: Any, only: Optional[Union[str, Sequence]] = None, exclude: Optional[Union[str, Sequence]] = None, ) -> None: """Raise ValidationError if invalid""" # If only or exclude are not set, this value always passes startswith only = ensure_a_list(only or [""]) if only and not isinstance(only[0], str): raise ValueError("'only' must be a string or list of strings.") exclude = ensure_a_list(exclude) if exclude and not isinstance(exclude[0], str): raise ValueError("'exclude' must be a string or list of strings.") if self.envs is None: self.envs = [settings.current_env] if self.when is not None: try: # inherit env if not defined if self.when.envs is None: self.when.envs = self.envs self.when.validate(settings, only=only, exclude=exclude) except ValidationError: # if when is invalid, return canceling validation flow return # If only using current_env, skip using_env decoration (reload) if (len(self.envs) == 1 and self.envs[0].upper() == settings.current_env.upper()): self._validate_items(settings, settings.current_env, only=only, exclude=exclude) return for env in self.envs: self._validate_items(settings.from_env(env), only=only, exclude=exclude)
def load_file(self, path=None, env=None, silent=True, key=None): """Programmatically load files from ``path``. :param path: A single filename or a file list :param env: Which env to load from file (default current_env) :param silent: Should raise errors? :param key: Load a single key? """ env = (env or self.current_env).upper() files = ensure_a_list(path) if files: already_loaded = set() for _filename in files: if py_loader.try_to_load_from_py_module_name( obj=self, name=_filename, silent=True ): # if it was possible to load from module name # continue the loop. continue # python 3.6 does not resolve Pathlib basedirs # issue #494 root_dir = str(self._root_path or os.getcwd()) if ( isinstance(_filename, Path) and str(_filename.parent) in root_dir ): # pragma: no cover filepath = str(_filename) else: filepath = os.path.join( self._root_path or os.getcwd(), str(_filename) ) paths = [ p for p in sorted(glob.glob(filepath)) if ".local." not in p ] local_paths = [ p for p in sorted(glob.glob(filepath)) if ".local." in p ] # Handle possible *.globs sorted alphanumeric for path in paths + local_paths: if path in already_loaded: # pragma: no cover continue settings_loader( obj=self, env=env, silent=silent, key=key, filename=path, ) already_loaded.add(path)
def load_file(self, path=None, env=None, silent=True, key=None): """Programmatically load files from ``path``. :param path: A single filename or a file list :param env: Which env to load from file (default current_env) :param silent: Should raise errors? :param key: Load a single key? """ env = (env or self.current_env).upper() files = ensure_a_list(path) if files: self.logger.debug(f"Got {files} files to process") already_loaded = set() for _filename in files: self.logger.debug(f"Processing file {_filename}") if py_loader.try_to_load_from_py_module_name( obj=self, name=_filename, silent=True ): # if it was possible to load from module name # continue the loop. continue filepath = os.path.join( self._root_path or os.getcwd(), _filename ) self.logger.debug(f"File path is {filepath}") paths = [ p for p in sorted(glob.glob(filepath)) if ".local." not in p ] local_paths = [ p for p in sorted(glob.glob(filepath)) if ".local." in p ] # Handle possible *.globs sorted alphanumeric for path in paths + local_paths: self.logger.debug(f"Loading {path}") if path in already_loaded: # pragma: no cover self.logger.debug(f"Skipping {path}, already loaded") continue settings_loader( obj=self, env=env, silent=silent, key=key, filename=path, ) already_loaded.add(path) if not already_loaded: self.logger.warning( f"Not able to locate the files {files} " "to load" )
def test_ensure_a_list(): # No data is empty list assert ensure_a_list(None) == [] # Sequence types is only converted assert ensure_a_list([1, 2]) == [1, 2] assert ensure_a_list((1, 2)) == [1, 2] assert ensure_a_list({1, 2}) == [1, 2] # A string is trimmed_splitted assert ensure_a_list("ab.toml") == ["ab.toml"] assert ensure_a_list("ab.toml,cd.toml") == ["ab.toml", "cd.toml"] assert ensure_a_list("ab.toml;cd.toml") == ["ab.toml", "cd.toml"] # other types get wrapped in a list assert ensure_a_list(1) == [1]
def load(self, filename=None, key=None, silent=True): """ Reads and loads in to `self.obj` a single key or all keys from source :param filename: Optional filename to load :param key: if provided load a single key :param silent: if load erros should be silenced """ filename = filename or self.obj.get(self.identifier.upper()) if not filename: return if not isinstance(filename, (list, tuple)): split_files = ensure_a_list(filename) if all([f.endswith(self.extensions) for f in split_files]): # noqa files = split_files # it is a ['file.ext', ...] else: # it is a single config as string files = [filename] else: # it is already a list/tuple files = filename self.obj._loaded_files.extend(files) # add the [default] env env_list = [self.obj.get("DEFAULT_ENV_FOR_DYNACONF")] # compatibility with older versions that still uses [dynaconf] as # [default] env global_env = self.obj.get("ENVVAR_PREFIX_FOR_DYNACONF") or "DYNACONF" if global_env not in env_list: env_list.append(global_env) # add the current [env] if self.env not in env_list: env_list.append(self.env) # add the [global] env env_list.append("GLOBAL") # load all envs self._read(files, env_list, silent, key)
def settings_loader(obj, settings_module=None, env=None, silent=True, key=None, filename=None): """Loads from defined settings module :param obj: A dynaconf instance :param settings_module: A path or a list of paths e.g settings.toml :param env: Env to look for data defaults: development :param silent: Boolean to raise loading errors :param key: Load a single key if provided :param filename: optional filename to override the settings_module """ if filename is None: settings_module = settings_module or obj.settings_module if not settings_module: # pragma: no cover return files = ensure_a_list(settings_module) else: files = ensure_a_list(filename) files.extend(ensure_a_list(obj.get("SECRETS_FOR_DYNACONF", None))) found_files = [] modules_names = [] for item in files: if item.endswith(ct.ALL_EXTENSIONS + (".py", )): p_root = obj._root_path or (os.path.dirname(found_files[0]) if found_files else None) found = obj.find_file(item, project_root=p_root) if found: found_files.append(found) else: # a bare python module name w/o extension modules_names.append(item) enabled_core_loaders = obj.get("CORE_LOADERS_FOR_DYNACONF") for mod_file in modules_names + found_files: # can be set to multiple files settings.py,settings.yaml,... # Cascade all loaders loaders = [ { "ext": ct.YAML_EXTENSIONS, "name": "YAML", "loader": yaml_loader }, { "ext": ct.TOML_EXTENSIONS, "name": "TOML", "loader": toml_loader }, { "ext": ct.INI_EXTENSIONS, "name": "INI", "loader": ini_loader }, { "ext": ct.JSON_EXTENSIONS, "name": "JSON", "loader": json_loader }, ] for loader in loaders: if loader["name"] not in enabled_core_loaders: continue if mod_file.endswith(loader["ext"]): loader["loader"].load(obj, filename=mod_file, env=env, silent=silent, key=key) continue if mod_file.endswith(ct.ALL_EXTENSIONS): continue if "PY" not in enabled_core_loaders: # pyloader is disabled continue # must be Python file or module # load from default defined module settings.py or .secrets.py if exists py_loader.load(obj, mod_file, key=key) # load from the current env e.g: development_settings.py env = env or obj.current_env if mod_file.endswith(".py"): if ".secrets.py" == mod_file: tmpl = ".{0}_{1}{2}" mod_file = "secrets.py" else: tmpl = "{0}_{1}{2}" dirname = os.path.dirname(mod_file) filename, extension = os.path.splitext(os.path.basename(mod_file)) new_filename = tmpl.format(env.lower(), filename, extension) env_mod_file = os.path.join(dirname, new_filename) global_filename = tmpl.format("global", filename, extension) global_mod_file = os.path.join(dirname, global_filename) else: env_mod_file = "{0}_{1}".format(env.lower(), mod_file) global_mod_file = "{0}_{1}".format("global", mod_file) py_loader.load( obj, env_mod_file, identifier="py_{0}".format(env.upper()), silent=True, key=key, ) # load from global_settings.py py_loader.load(obj, global_mod_file, identifier="py_global", silent=True, key=key)