Skip to content

Commit 213940c

Browse files
author
Hazel
committed
Make remove_by_labels() consistent with remove(): return None
Signed-off-by: Hazel <[email protected]>
1 parent ac8b74e commit 213940c

File tree

2 files changed

+18
-16
lines changed

2 files changed

+18
-16
lines changed

prometheus_client/metrics.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ def remove(self, *labelvalues: Any) -> None:
203203
if labelvalues in self._metrics:
204204
del self._metrics[labelvalues]
205205

206-
def remove_by_labels(self, labels: dict[str, str]) -> int:
206+
def remove_by_labels(self, labels: dict[str, str]) -> None:
207+
"""Remove all series whose labelset partially matches the given labels."""
207208
if 'prometheus_multiproc_dir' in os.environ or 'PROMETHEUS_MULTIPROC_DIR' in os.environ:
208209
warnings.warn(
209210
"Removal of labels has not been implemented in multi-process mode yet.",
@@ -217,7 +218,7 @@ def remove_by_labels(self, labels: dict[str, str]) -> int:
217218
raise TypeError("labels must be a dict of {label_name: label_value}")
218219

219220
if not labels:
220-
return 0
221+
return # no operation
221222

222223
invalid = [k for k in labels.keys() if k not in self._labelnames]
223224
if invalid:
@@ -227,15 +228,12 @@ def remove_by_labels(self, labels: dict[str, str]) -> int:
227228

228229
pos_filter = {self._labelnames.index(k): str(v) for k, v in labels.items()}
229230

230-
deleted = 0
231231
with self._lock:
232+
# list(...) to avoid "dictionary changed size during iteration"
232233
for lv in list(self._metrics.keys()):
233234
if all(lv[pos] == want for pos, want in pos_filter.items()):
234-
if lv in self._metrics:
235-
del self._metrics[lv]
236-
deleted += 1
237-
238-
return deleted
235+
# pop with default avoids KeyError if concurrently removed
236+
self._metrics.pop(lv, None)
239237

240238

241239
def clear(self) -> None:

tests/test_core.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -630,36 +630,40 @@ def test_labels_coerced_to_string(self):
630630
self.counter.remove(None)
631631
self.assertEqual(None, self.registry.get_sample_value('c_total', {'l': 'None'}))
632632

633-
def test_remove_matching(self):
633+
def test_remove_by_labels(self):
634634
from prometheus_client import Counter
635635

636636
c = Counter('c2', 'help', ['tenant', 'endpoint'], registry=self.registry)
637637
c.labels('acme', '/').inc()
638638
c.labels('acme', '/checkout').inc()
639639
c.labels('globex', '/').inc()
640640

641-
642-
deleted = c.remove_by_labels({'tenant': 'acme'})
643-
self.assertEqual(2, deleted)
641+
ret = c.remove_by_labels({'tenant': 'acme'})
642+
self.assertIsNone(ret)
644643

645644
self.assertIsNone(self.registry.get_sample_value('c2_total', {'tenant': 'acme', 'endpoint': '/'}))
646645
self.assertIsNone(self.registry.get_sample_value('c2_total', {'tenant': 'acme', 'endpoint': '/checkout'}))
647646
self.assertEqual(1, self.registry.get_sample_value('c2_total', {'tenant': 'globex', 'endpoint': '/'}))
648647

649-
def test_remove_matching_invalid_label_name(self):
648+
649+
def test_remove_by_labels_invalid_label_name(self):
650650
from prometheus_client import Counter
651651
c = Counter('c3', 'help', ['tenant', 'endpoint'], registry=self.registry)
652652
c.labels('acme', '/').inc()
653653
with self.assertRaises(ValueError):
654654
c.remove_by_labels({'badkey': 'x'})
655655

656-
def test_remove_matching_empty_is_noop(self):
656+
657+
def test_remove_by_labels_empty_is_noop(self):
657658
from prometheus_client import Counter
658659
c = Counter('c4', 'help', ['tenant', 'endpoint'], registry=self.registry)
659660
c.labels('acme', '/').inc()
660-
self.assertEqual(0, c.remove_by_labels({}))
661-
self.assertEqual(1, self.registry.get_sample_value('c4_total', {'tenant': 'acme', 'endpoint': '/'}))
662661

662+
ret = c.remove_by_labels({})
663+
self.assertIsNone(ret)
664+
# Ensure the series is still present
665+
self.assertEqual(1, self.registry.get_sample_value('c4_total', {'tenant': 'acme', 'endpoint': '/'}))
666+
663667
def test_non_string_labels_raises(self):
664668
class Test:
665669
__str__ = None

0 commit comments

Comments
 (0)