• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DaveFoss / DAVE_data / 10697820903

04 Sep 2024 08:17AM UTC coverage: 92.357% (+6.0%) from 86.4%
10697820903

Pull #10

github

uvchik
Remove failing code
Pull Request #10: Add basic functions

45 of 48 branches covered (93.75%)

Branch coverage included in aggregate %.

233 of 238 new or added lines in 11 files covered. (97.9%)

390 of 423 relevant lines covered (92.2%)

1.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.56
/src/dave_data/config.py
1
"""
2
Project config reader.
3
Based on Steffen (https://github.com/steffenGit)
4

5
License: MIT
6
"""
7

8
__all__ = [
2✔
9
    "has_option",
10
    "has_section",
11
    "get",
12
    "get_list",
13
    "get_dict",
14
    "tmp_set",
15
    "init",
16
]
17

18
import configparser as cp
2✔
19
import logging
2✔
20
from pathlib import Path
2✔
21

22
BLACKLIST = ["tox.ini", "pytest.ini"]
2✔
23

24
cfg = cp.RawConfigParser()
2✔
25
cfg.optionxform = str
2✔
26
_loaded = False
2✔
27
FILES = []
2✔
28

29

30
def get_ini_filenames():
2✔
31
    """Returns a list of ini files to use."""
32
    paths = []
2✔
33

34
    package_path = Path(__file__).resolve().parent
2✔
35
    files = list(package_path.rglob("*.ini"))
2✔
36

37
    local_path = Path(Path.home(), ".dave")
2✔
38
    if local_path.is_dir():
2✔
NEW
39
        paths.append(local_path)
×
40
    logging.debug(f"Searching for .ini-files in the following paths {paths}")
2✔
41
    for p in paths:
2✔
NEW
42
        files.extend(list(p.glob("*.ini")))
×
43
    files = [f for f in files if f not in BLACKLIST]
2✔
44
    return files
2✔
45

46

47
def init(files=None):
2✔
48
    """Read config file(s).
49

50
    Parameters
51
    ----------
52
    files : list or None
53
        Absolute path to config file (incl. filename)
54
    """
55
    if files is None:
2✔
56
        files = get_ini_filenames()
2✔
57
    global FILES
58
    FILES = files
2✔
59
    cfg.read(files, encoding="utf-8")
2✔
60
    global _loaded
61
    _loaded = True
2✔
62

63

64
def load():
2✔
65
    if not _loaded:
2✔
66
        init()
2✔
67

68

69
def has_option(section, option):
2✔
70
    """
71
    Returns True if the given option exists in the given section.
72

73
    Examples
74
    --------
75
    >>> has_option("test", "gnurpf")
76
    False
77
    >>> has_option("test", "c")
78
    True
79
    """
80
    return cfg.has_option(section, option)
2✔
81

82

83
def has_section(section):
2✔
84
    """
85
    Returns True if the given section exists.
86

87
    Examples
88
    --------
89
    >>> has_section("gnurpf")
90
    False
91
    >>> has_section("test")
92
    True
93
    """
94
    return cfg.has_section(section)
2✔
95

96

97
def get(section, key):
2✔
98
    """Returns the value of a given key in a given section."""
99
    load()
2✔
100
    try:
2✔
101
        return cfg.getint(section, key)
2✔
102
    except ValueError:
2✔
103
        try:
2✔
104
            return cfg.getfloat(section, key)
2✔
105
        except ValueError:
2✔
106
            try:
2✔
107
                return cfg.getboolean(section, key)
2✔
108
            except ValueError:
2✔
109
                value = cfg.get(section, key)
2✔
110
                if value == "None":
2✔
111
                    value = None
2✔
112
                return value
2✔
113

114

115
def get_list(section, parameter, sep=",", string=False):
2✔
116
    """
117
    Returns the values (separated by sep) of a given key in a given
118
    section as a list.
119

120
    Examples
121
    --------
122
    >>> get_list("test", "c")
123
    ['a', 'b', 'c']
124
    """
125
    my_list = get(section, parameter).split(sep)
2✔
126
    return [x.strip() for x in my_list]
2✔
127

128

129
def get_dict(section):
2✔
130
    """
131
    Returns the values of a section as dictionary
132

133
    Examples
134
    --------
135
    >>> my_dict = get_dict("test")
136
    >>> type(my_dict["a"])
137
    <class 'NoneType'>
138
    >>> my_dict["b"]
139
    5
140
    """
141
    load()
2✔
142
    section_keys = dict(cfg.items(section)).keys()
2✔
143
    return {key: get(section, key) for key in section_keys}
2✔
144

145

146
def tmp_set(section, key, value):
2✔
147
    """
148
    Set/Overwrite a value temporarily for the actual section.
149
    """
150
    load()
2✔
151
    return cfg.set(section, key, value)
2✔
152

153

154
def get_base_path(sub_dir=None):
2✔
155
    """
156
    Get the base path of the data storage.
157

158
    A list of allowed names for subdirectories can be found in the config file.
159

160
    Parameters
161
    ----------
162
    sub_dir : str
163

164
    Returns
165
    -------
166
    pathlib.Path
167

168
    Examples
169
    --------
170
    >>> get_list("path", "sub_dirs")
171
    ['lod', 'layer']
172
    >>> get_base_path("my_own")
173
    Traceback (most recent call last):
174
     ...
175
    ValueError: Subdir my_own is not valid.
176
    Use one of the following subdirectories: ['lod', 'layer']
177
    >>> get_base_path("lod").name
178
    'lod'
179

180
    """
181
    if get("path", "base") is None:
2✔
182
        base_path = Path(Path.home(), "dave_data")
2✔
183
        tmp_set("path", "base", str(base_path))
2✔
184
    else:
185
        base_path = Path(get("path", "base"))
2✔
186
    if sub_dir is not None:
2✔
187
        allowed = get_list("path", "sub_dirs")
2✔
188
        if sub_dir in allowed:
2✔
189
            base_path = Path(base_path, sub_dir)
2✔
190
        else:
191
            raise ValueError(
2✔
192
                f"Subdir {sub_dir} is not valid.\nUse one of the following "
193
                f"subdirectories: {allowed}"
194
            )
195
    base_path.mkdir(exist_ok=True, parents=True)
2✔
196
    return base_path
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc