-
-
Notifications
You must be signed in to change notification settings - Fork 288
/
boxing.py
90 lines (74 loc) · 2.87 KB
/
boxing.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
import inspect
from functools import wraps
from dynaconf.utils import recursively_evaluate_lazy_format
from dynaconf.utils import upperfy
from dynaconf.utils.functional import empty
from dynaconf.vendor.box import Box
def evaluate_lazy_format(f):
"""Marks a method on Dynabox instance to
lazily evaluate LazyFormat objects upon access."""
@wraps(f)
def evaluate(dynabox, item, *args, **kwargs):
value = f(dynabox, item, *args, **kwargs)
settings = dynabox._box_config["box_settings"]
if getattr(value, "_dynaconf_lazy_format", None):
dynabox._box_config[
f"raw_{item.lower()}"
] = f"@{value.formatter.token} {value.value}"
return recursively_evaluate_lazy_format(value, settings)
return evaluate
class DynaBox(Box):
"""Specialized Box for dynaconf
it allows items/attrs to be found both in upper or lower case"""
@evaluate_lazy_format
def __getattr__(self, item, *args, **kwargs):
try:
return super().__getattr__(item, *args, **kwargs)
except (AttributeError, KeyError):
n_item = item.lower() if item.isupper() else upperfy(item)
return super().__getattr__(n_item, *args, **kwargs)
@evaluate_lazy_format
def __getitem__(self, item, *args, **kwargs):
try:
return super().__getitem__(item, *args, **kwargs)
except (AttributeError, KeyError):
n_item = item.lower() if item.isupper() else upperfy(item)
return super().__getitem__(n_item, *args, **kwargs)
def __copy__(self):
return self.__class__(
super(Box, self).copy(),
box_settings=self._box_config.get("box_settings"),
)
def copy(self):
return self.__class__(
super(Box, self).copy(),
box_settings=self._box_config.get("box_settings"),
)
def _case_insensitive_get(self, item, default=None):
"""adds a bit of overhead but allows case insensitive get
See issue: #486
"""
lower_self = {k.casefold(): v for k, v in self.items()}
return lower_self.get(item.casefold(), default)
@evaluate_lazy_format
def get(self, item, default=None, *args, **kwargs):
if item not in self: # toggle case
item = item.lower() if item.isupper() else upperfy(item)
value = super().get(item, empty, *args, **kwargs)
if value is empty:
# see Issue: #486
return self._case_insensitive_get(item, default)
return value
def __dir__(self):
keys = list(self.keys())
reserved = [
item[0]
for item in inspect.getmembers(DynaBox)
if not item[0].startswith("__")
]
return (
keys
+ [k.lower() for k in keys]
+ [k.upper() for k in keys]
+ reserved
)