Exemplo n.º 1
0
def import_from_filename(filename, silent=False):  # pragma: no cover
    """If settings_module is a filename path import it."""
    if not filename.endswith('.py'):
        filename = '{0}.py'.format(filename)

    if filename in default_settings.SETTINGS_MODULE_FOR_DYNACONF:
        silent = True
    mod = types.ModuleType(filename.rstrip('.py'))
    mod.__file__ = filename
    mod._is_error = False
    try:
        with io.open(
            find_file(filename),
            encoding=default_settings.ENCODING_FOR_DYNACONF
        ) as config_file:
            exec(
                compile(config_file.read(), filename, 'exec'),
                mod.__dict__
            )
    except IOError as e:
        e.strerror = (
            'py_loader: error loading file (%s %s)\n'
        ) % (e.strerror, filename)
        if silent and e.errno in (errno.ENOENT, errno.EISDIR):
            return
        raw_logger().debug(e.strerror)
        mod._is_error = True
    return mod
Exemplo n.º 2
0
    def import_from_filename(filename, silent=False):  # pragma: no cover
        """If settings_module is a path use this."""
        if not filename.endswith('.py'):
            filename = '{0}.py'.format(filename)

        if filename in default_settings.SETTINGS_MODULE_FOR_DYNACONF:
            silent = True
        mod = types.ModuleType('config')
        mod.__file__ = filename
        mod._is_error = False
        try:
            with open(find_file(filename)) as config_file:
                exec(
                    compile(config_file.read(), filename, 'exec'),
                    mod.__dict__
                )
        except IOError as e:
            e.strerror = (
                'Unable to load configuration file (%s %s)\n'
            ) % (e.strerror, filename)
            if silent and e.errno in (errno.ENOENT, errno.EISDIR):
                return
            raw_logger().debug(e.strerror)
            mod._is_error = True
        return mod
Exemplo n.º 3
0
def test_find_file(tmpdir):
    """
    Create a temporary folder structure like the following:
        tmpXiWxa5/
        └── child1
            └── child2
                └── child3
                    └── child4
                       └── .env
                       └── app.py

    1) Then try to automatically `find_dotenv` starting in `child4`
    """

    curr_dir = tmpdir
    dirs = []
    for f in ["child1", "child2", "child3", "child4"]:
        curr_dir = os.path.join(str(curr_dir), f)
        dirs.append(curr_dir)
        os.mkdir(curr_dir)

    child4 = dirs[-1]

    assert find_file("file-does-not-exist") == ""
    assert find_file("/abs-file-does-not-exist") == ""

    for _dir in dirs:
        # search for abspath return the same path
        assert os.path.isabs(_dir)
        assert find_file(_dir) == _dir

    # now place a .env file a few levels up and make sure it's found
    filename = os.path.join(str(child4), ".env")
    with io.open(
        filename, "w", encoding=default_settings.ENCODING_FOR_DYNACONF
    ) as f:
        f.write("TEST=test\n")

    assert find_file(project_root=str(child4)) == filename

    # skip the inner child4/.env and force the find of /tmp.../.env
    assert find_file(
        project_root=str(child4), skip_files=[filename]
    ) == os.path.join(str(tmpdir), ".env")
Exemplo n.º 4
0
def test_find_file():
    """
    Create a temporary folder structure like the following:
        tmpXiWxa5/
        └── child1
            ├── child2
            │   └── child3
            │       └── child4
            └── .env
    Then try to automatically `find_dotenv` starting in `child4`
    """
    tmpdir = os.path.realpath(tempfile.mkdtemp())

    curr_dir = tmpdir
    dirs = []
    for f in ['child1', 'child2', 'child3', 'child4']:
        curr_dir = os.path.join(curr_dir, f)
        dirs.append(curr_dir)
        os.mkdir(curr_dir)

    child1, child4 = dirs[0], dirs[-1]

    # change the working directory for testing
    os.chdir(child4)

    # try without a .env file and force error
    with pytest.raises(IOError):
        find_file(raise_error_if_not_found=True, usecwd=True)

    # try without a .env file and fail silently
    assert find_file(usecwd=True) == ''

    # now place a .env file a few levels up and make sure it's found
    filename = os.path.join(child1, '.env')
    with io.open(filename,
                 'w',
                 encoding=default_settings.ENCODING_FOR_DYNACONF) as f:
        f.write("TEST=test\n")
    assert find_file(usecwd=True) == filename
Exemplo n.º 5
0
 def find_file(self, *args, **kwargs):
     kwargs.setdefault("project_root", self._root_path)
     kwargs.setdefault("skip_files", self.get("SKIP_FILES_FOR_DYNACONF",
                                              []))
     return find_file(*args, **kwargs)
Exemplo n.º 6
0
def load(obj, namespace=None, silent=True, key=None, filename=None):
    """
    Reads and loads in to "settings" a single key or all keys from yaml file
    :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
    """
    if yaml is None:  # pragma: no cover
        obj.logger.warning(
            "PyYAML package is not installed in your environment.\n"
            "To use this loader you have to install it with\n"
            "pip install PyYAML\n"
            "or\n"
            "pip install dynaconf[yaml]")
        return

    filename = filename or obj.get('YAML')
    if not filename:
        return

    namespace = namespace or obj.get('NAMESPACE_FOR_DYNACONF')

    # clean(obj, namespace, identifier=filename)

    # can be a filename settings.yml
    # can be a multiple fileset settings1.yml, settings2.yaml etc
    # and also a list of strings ['aaa:a', 'bbb:c']
    # and can also be a single string 'aa:a'
    if not isinstance(filename, (list, tuple)):
        split_files = filename.split(',')
        if all([f.endswith(YAML_EXTENSIONS) for f in split_files]):
            files = split_files  # it is a ['file.yml', ...]
        else:  # it is a single YAML string
            files = [filename]
    else:  # it is already a list/tuple
        files = filename

    for yaml_file in files:
        if yaml_file.endswith(YAML_EXTENSIONS):  # pragma: no cover
            try:
                yaml_data = yaml.load(open(find_file(yaml_file, usecwd=True)))
            except IOError as e:
                obj.logger.debug("Unable to load YAML file {}".format(str(e)))
                yaml_data = None
            else:
                obj.logger.debug('YAML {} has been loaded'.format(yaml_file))
        else:
            # for tests it is possible to pass YAML string
            yaml_data = yaml.load(yaml_file)

        if not yaml_data:
            continue

        yaml_data = {key.lower(): value for key, value in yaml_data.items()}

        # ---->
        # Load from namespace_filename.yaml

        data = {}
        try:
            data = yaml_data[namespace.lower()]
        except KeyError:
            if silent:
                obj.logger.debug('%s namespace not defined in yaml source' %
                                 namespace)
            else:
                raise KeyError('%s namespace not defined in %s' %
                               (namespace, filename))

        if namespace and namespace != obj.get('NAMESPACE_FOR_DYNACONF'):
            identifier = "{0}_{1}".format(IDENTIFIER, namespace.lower())
        else:
            identifier = IDENTIFIER

        if not key:
            obj.update(data, loader_identifier=identifier)
        else:
            obj.set(key, data.get(key), loader_identifier=identifier)
Exemplo n.º 7
0
def load(obj, namespace=None, silent=True, key=None, filename=None):
    """
    Reads and loads in to "settings" a single key or all keys from json file
    :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
    """
    filename = filename or obj.get('JSON')
    if not filename:
        return

    namespace = namespace or obj.get('NAMESPACE_FOR_DYNACONF')

    # clean(obj, namespace, identifier=filename)

    # can be a filename settings.yml
    # can be a multiple fileset settings1.json, settings2.json etc
    # and also a list of strings ['aaa:a', 'bbb:c']
    # and can also be a single string 'aa:a'
    if not isinstance(filename, (list, tuple)):
        split_files = filename.split(',')
        if all([f.endswith(JSON_EXTENSIONS) for f in split_files]):  # noqa
            files = split_files  # it is a ['file.json', ...]
        else:  # it is a single json string
            files = [filename]
    else:  # it is already a list/tuple
        files = filename

    for json_file in files:
        if json_file.endswith(JSON_EXTENSIONS):  # pragma: no cover
            obj.logger.debug('Trying to load json {}'.format(json_file))
            try:
                json_data = json.load(open(find_file(json_file, usecwd=True)))
            except (IOError, json.decoder.JSONDecodeError) as e:
                obj.logger.debug("Unable to load json {} file {}".format(
                    json_file, str(e)))
                json_data = None
        else:
            # for tests it is possible to pass json string
            json_data = json.loads(json_file)

        if not json_data:
            continue

        json_data = {key.lower(): value for key, value in json_data.items()}

        # ---->
        # Load from namespace_filename.json

        data = {}
        try:
            data = json_data[namespace.lower()]
        except KeyError:
            if silent:
                obj.logger.debug('%s namespace not defined in json source' %
                                 namespace)
            else:
                raise KeyError('%s namespace not defined in %s' %
                               (namespace, filename))

        if namespace and namespace != obj.get('NAMESPACE_FOR_DYNACONF'):
            identifier = "{0}_{1}".format(IDENTIFIER, namespace.lower())
        else:
            identifier = IDENTIFIER

        if not key:
            obj.update(data, loader_identifier=identifier)
        else:
            obj.set(key, data.get(key), loader_identifier=identifier)
Exemplo n.º 8
0
    def _read(self, files, envs, silent=True, key=None):
        for source_file in files:
            if source_file.endswith(self.extensions):  # pragma: no cover
                try:
                    source_data = self.file_reader(
                        io.open(
                            find_file(
                                source_file,
                                project_root=self.obj.get(
                                    'PROJECT_ROOT_FOR_DYNACONF'
                                )
                            ),
                            encoding=self.obj.get(
                                'ENCODING_FOR_DYNACONF', 'utf-8'
                            )
                        )
                    )
                    self.obj.logger.debug('{}_loader: {}'.format(
                        self.identifier, source_file))
                except IOError:
                    self.obj.logger.debug(
                        '{}_loader: {} (Ignored, file not Found)'.format(
                            self.identifier, source_file)
                    )
                    source_data = None
            else:
                # for tests it is possible to pass string
                source_data = self.string_reader(source_file)

            if not source_data:
                continue

            source_data = {
                k.lower(): value
                for k, value
                in source_data.items()
            }

            for env in envs:

                data = {}
                try:
                    data = source_data[env.lower()]
                except KeyError:
                    if env not in (self.obj.get('GLOBAL_ENV_FOR_DYNACONF'),
                                   'GLOBAL'):
                        message = '%s_loader: %s env not defined in %s' % (
                            self.identifier, env, source_file)
                        if silent:
                            self.obj.logger.warning(message)
                        else:
                            raise KeyError(message)
                    continue

                if env != self.obj.get('DEFAULT_ENV_FOR_DYNACONF'):
                    identifier = "{0}_{1}".format(self.identifier, env.lower())
                else:
                    identifier = self.identifier

                if not key:
                    self.obj.update(data, loader_identifier=identifier)
                elif key in data:
                    self.obj.set(key, data.get(key),
                                 loader_identifier=identifier)

                self.obj.logger.debug(
                    '{}_loader: {}: {}'.format(
                        self.identifier,
                        env.lower(),
                        list(data.keys()) if 'secret' in source_file else data
                    )
                )
Exemplo n.º 9
0
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
    """
    settings_module = settings_module or obj.settings_module
    if not settings_module:  # pragma: no cover
        return

    if not isinstance(settings_module, (list, tuple)):
        files = settings_module.split(',')
    else:
        files = [settings_module]

    obj.logger.debug("Looking for %s", files)

    if filename is not None:
        files.append(filename)

    found_files = []
    modules_names = []
    for item in files:
        if item.endswith(ct.ALL_EXTENSIONS + ('.py', )):
            found = find_file(item)
            if found:
                found_files.append(found)
        else:
            # a bare python module name w/o extension
            modules_names.append(item)

    obj.logger.debug("Found files %s", found_files)

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

        # 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)