-
Notifications
You must be signed in to change notification settings - Fork 60
/
core_config.py
142 lines (117 loc) Β· 4.84 KB
/
core_config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
'''
Bindings for the 'core' HPI configuration
'''
import re
from typing import Sequence, Optional
from . import warnings, PathIsh, Path
try:
from my.config import core as user_config # type: ignore[attr-defined]
except Exception as e:
try:
from my.config import common as user_config # type: ignore[attr-defined, assignment, misc]
warnings.high("'common' config section is deprecated. Please rename it to 'core'.")
except Exception as e2:
# make it defensive, because it's pretty commonly used and would be annoying if it breaks hpi doctor etc.
# this way it'll at least use the defaults
# todo actually not sure if needs a warning? Perhaps it's okay without it, because the defaults are reasonable enough
user_config = object # type: ignore[assignment, misc]
_HPI_CACHE_DIR_DEFAULT = ''
from dataclasses import dataclass
@dataclass
class Config(user_config):
'''
Config for the HPI itself.
To override, add to your config file something like
class config:
cache_dir = '/your/custom/cache/path'
'''
cache_dir: Optional[PathIsh] = _HPI_CACHE_DIR_DEFAULT
'''
Base directory for cachew.
- if None , means cache is disabled
- if '' (empty string), use user cache dir (see https://github.com/ActiveState/appdirs for more info). This is the default.
- otherwise , use the specified directory as base cache directory
NOTE: you shouldn't use this attribute in HPI modules directly, use Config.get_cache_dir()/cachew.cache_dir() instead
'''
enabled_modules : Optional[Sequence[str]] = None
'''
list of regexes/globs
- None means 'rely on disabled_modules'
'''
disabled_modules: Optional[Sequence[str]] = None
'''
list of regexes/globs
- None means 'rely on enabled_modules'
'''
def get_cache_dir(self) -> Optional[Path]:
cdir = self.cache_dir
if cdir is None:
return None
if cdir == _HPI_CACHE_DIR_DEFAULT:
from .cachew import _appdirs_cache_dir
return _appdirs_cache_dir()
else:
return Path(cdir)
def _is_module_active(self, module: str) -> Optional[bool]:
# None means the config doesn't specify anything
# todo might be nice to return the 'reason' too? e.g. which option has matched
def matches(specs: Sequence[str]) -> Optional[str]:
for spec in specs:
# not sure because . (packages separate) matches anything, but I guess unlikely to clash
if re.match(spec, module):
return spec
return None
enabled = self.enabled_modules
disabled = self.disabled_modules
on = matches(self.enabled_modules or [])
off = matches(self.disabled_modules or [])
if on is None:
if off is None:
# user is indifferent
return None
else:
return False
else: # not None
if off is None:
return True
else: # not None
# fallback onto the 'enable everything', then the user will notice
warnings.medium(f"[module]: conflicting regexes '{on}' and '{off}' are set in the config. Please only use one of them.")
return True
from .cfg import make_config
config = make_config(Config)
### tests start
from typing import Iterator
from contextlib import contextmanager as ctx
@ctx
def _reset_config() -> Iterator[Config]:
# todo maybe have this decorator for the whole of my.config?
from .cfg import override_config
with override_config(config) as cc:
cc.enabled_modules = None
cc.disabled_modules = None
cc.cache_dir = None
yield cc
def test_active_modules() -> None:
import pytest
reset = _reset_config
with reset() as cc:
assert cc._is_module_active('my.whatever' ) is None
assert cc._is_module_active('my.core' ) is None
assert cc._is_module_active('my.body.exercise') is None
with reset() as cc:
cc.enabled_modules = ['my.whatever']
cc.disabled_modules = ['my.body.*']
assert cc._is_module_active('my.whatever' ) is True
assert cc._is_module_active('my.core' ) is None
assert not cc._is_module_active('my.body.exercise') is True
with reset() as cc:
# if both are set, enable all
cc.disabled_modules = ['my.body.*']
cc.enabled_modules = ['my.body.exercise']
assert cc._is_module_active('my.whatever' ) is None
assert cc._is_module_active('my.core' ) is None
with pytest.warns(UserWarning, match=r"conflicting regexes") as record_warnings:
assert cc._is_module_active("my.body.exercise") is True
assert len(record_warnings) == 1
### tests end