1 2
import inspect
2 2
import io
3 2
import os
4

5 2
from dynaconf.utils import deduplicate
6

7

8 2
def _walk_to_root(path, break_at=None):
9
    """
10
    Directories starting from the given directory up to the root or break_at
11
    """
12
    if not os.path.exists(path):  # pragma: no cover
13
        raise IOError("Starting path not found")
14

15
    if os.path.isfile(path):  # pragma: no cover
16
        path = os.path.dirname(path)
17

18 2
    last_dir = None
19 2
    current_dir = os.path.abspath(path)
20 2
    paths = []
21 2
    while last_dir != current_dir:
22 2
        paths.append(current_dir)
23 2
        paths.append(os.path.join(current_dir, "config"))
24 2
        if break_at and current_dir == os.path.abspath(break_at):  # noqa
25 2
            break
26 2
        parent_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir))
27 2
        last_dir, current_dir = current_dir, parent_dir
28 2
    return paths
29

30

31 2
SEARCHTREE = []
32

33

34 2
def find_file(filename=".env", project_root=None, skip_files=None, **kwargs):
35
    """Search in increasingly higher folders for the given file
36
    Returns path to the file if found, or an empty string otherwise.
37

38
    This function will build a `search_tree` based on:
39

40
    - Project_root if specified
41
    - Invoked script location and its parents until root
42
    - Current working directory
43

44
    For each path in the `search_tree` it will also look for an
45
    aditional `./config` folder.
46
    """
47 2
    search_tree = []
48 2
    work_dir = os.getcwd()
49 2
    skip_files = skip_files or []
50

51 2
    if project_root is not None:
52 2
        search_tree.extend(_walk_to_root(project_root, break_at=work_dir))
53

54 2
    script_dir = os.path.dirname(os.path.abspath(inspect.stack()[-1].filename))
55

56
    # Path to invoked script and recursively to root with its ./config dirs
57 2
    search_tree.extend(_walk_to_root(script_dir))
58

59
    # Path to where Python interpreter was invoked and recursively to root
60 2
    search_tree.extend(_walk_to_root(work_dir))
61

62
    # Don't look the same place twice
63 2
    search_tree = deduplicate(search_tree)
64

65
    global SEARCHTREE
66 2
    SEARCHTREE[:] = search_tree
67

68 2
    for dirname in search_tree:
69 2
        check_path = os.path.join(dirname, filename)
70 2
        if check_path in skip_files:
71 2
            continue
72 2
        if os.path.exists(check_path):
73 2
            return check_path  # First found will return
74

75
    # return empty string if not found so it can still be joined in os.path
76 2
    return ""
77

78

79 2
def read_file(path, **kwargs):
80 2
    content = ""
81 2
    with io.open(path, **kwargs) as open_file:
82 2
        content = open_file.read().strip()
83 2
    return content
84

85

86 2
def get_local_filename(filename):
87
    """Takes a filename like `settings.toml` and returns `settings.local.toml`
88

89
    Arguments:
90
        filename {str} -- The filename or complete path
91

92
    Returns:
93
        [str] -- The same name or path with `.local.` added.
94
    """
95 2
    name, _, extension = os.path.basename(str(filename)).rpartition(
96
        os.path.extsep
97
    )
98

99 2
    return os.path.join(
100
        os.path.dirname(str(filename)), f"{name}.local.{extension}"
101
    )

Read our documentation on viewing source code .

Loading