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

shanbay / cachext / 13325086907

14 Feb 2025 08:09AM UTC coverage: 96.01% (-1.0%) from 96.962%
13325086907

Pull #28

github

web-flow
Merge fffcc2c87 into 8128cc098
Pull Request #28: fix: handle exceptions on prometheus operations

4 of 8 new or added lines in 1 file covered. (50.0%)

385 of 401 relevant lines covered (96.01%)

1.92 hits per line

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

88.16
/cachext/cache.py
1
import functools
2✔
2

3

4
DEFAULT_KEY_TYPES = (str, int, float, bool)
2✔
5

6

7
def norm_cache_key(v):
2✔
8
    if isinstance(v, type):
2✔
9
        return v.__name__
2✔
10
    if isinstance(v, bytes):
2✔
11
        return v.decode()
2✔
12
    if v is None or isinstance(v, DEFAULT_KEY_TYPES):
2✔
13
        return str(v)
2✔
14
    else:
15
        raise ValueError('only str, int, float, bool can be key')
2✔
16

17

18
def default_key(f, *args, **kwargs):
2✔
19
    keys = [norm_cache_key(v) for v in args]
2✔
20
    keys += sorted(
2✔
21
        ['{}={}'.format(k, norm_cache_key(v)) for k, v in kwargs.items()])
22
    return 'default.{}.{}.{}'.format(f.__module__, f.__name__, '.'.join(keys))
2✔
23

24

25
def default_monitor_label_builder(f, *args, **kwargs):
2✔
26
    return f"{f.__module__}.{f.__name__}"
2✔
27

28

29
class CacheNone:
2✔
30
    pass
2✔
31

32

33
class cached:
2✔
34

35
    client = None
2✔
36

37
    def __init__(self, func=None, ttl=None, cache_key=default_key,
2✔
38
                 cache_version=None, unless=None, fallbacked=None,
39
                 cache_none=False, monitor_label_builder=None):
40
        self.ttl = ttl
2✔
41
        self.cache_key = cache_key
2✔
42
        self.unless = unless
2✔
43
        self.fallbacked = fallbacked
2✔
44
        self.cache_none = cache_none
2✔
45
        self.cache_version = cache_version
2✔
46
        if func is not None:
2✔
47
            func = self.decorator(func)
×
48
        self.func = func
2✔
49
        self.monitor_label_builder = (
2✔
50
                monitor_label_builder or default_monitor_label_builder)
51

52
    def __call__(self, *args, **kwargs):
2✔
53
        if self.func is not None:
2✔
54
            return self.func(*args, **kwargs)
×
55
        f = args[0]
2✔
56
        return self.decorator(f)
2✔
57

58
    def decorator(self, f):
2✔
59
        @functools.wraps(f)
2✔
60
        def wrapper(*args, **kwargs):
2✔
61
            if callable(self.unless) and self.unless(*args, **kwargs):
2✔
62
                return f(*args, **kwargs)
2✔
63
            key = wrapper.make_cache_key(*args, **kwargs)
2✔
64
            rv = self.client.get(key)
2✔
65
            labels = (
2✔
66
                self.client.prefix,
67
                self.monitor_label_builder(f, *args, **kwargs)
68
            )
69
            if self.request_counter:
2✔
70
                try:
2✔
71
                    self.request_counter.labels(*labels).inc()
2✔
NEW
72
                except Exception as e:
×
NEW
73
                    print("request_counter.labels(*labels).inc() error: ", e)
×
74
            if rv is None:
2✔
75
                rv = f(*args, **kwargs)
2✔
76
                if self.cache_none and rv is None:
2✔
77
                    rv = CacheNone
×
78
                if rv is not None:
2✔
79
                    self.client.set(key, rv, ttl=wrapper.ttl)
2✔
80
                if callable(self.fallbacked):
2✔
81
                    self.fallbacked(wrapper, rv, *args, **kwargs)
2✔
82
            elif self.hit_counter:
2✔
83
                try:
2✔
84
                    self.hit_counter.labels(*labels).inc()
2✔
NEW
85
                except Exception as e:
×
NEW
86
                    print("hit_counter.labels(*labels).inc() error: ", e)
×
87
            if self.cache_none and rv is CacheNone:
2✔
88
                return None
×
89
            return rv
2✔
90

91
        def make_cache_key(*args, **kwargs):
2✔
92
            if callable(self.cache_key):
2✔
93
                key = self.cache_key(f, *args, **kwargs)
2✔
94
            else:
95
                key = self.cache_key
2✔
96

97
            return key if not self.cache_version else\
2✔
98
                '{key}.{version}'.format(key=key, version=self.cache_version)
99

100
        wrapper.uncached = f
2✔
101
        wrapper.ttl = self.ttl
2✔
102
        wrapper.make_cache_key = make_cache_key
2✔
103

104
        return wrapper
2✔
105

106
    def __getattr__(self, name):
2✔
107
        return getattr(self.func, name, None)
×
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

© 2025 Coveralls, Inc