Skip to content

Commit 4cfd0ca

Browse files
committed
task: lint and doc
1 parent 157321f commit 4cfd0ca

File tree

7 files changed

+37
-29
lines changed

7 files changed

+37
-29
lines changed

alpacloud/promls/cli.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""CLI interface for promls."""
2+
13
import enum
24
import itertools
35
import json
@@ -13,13 +15,16 @@
1315

1416

1517
class PrintMode(enum.StrEnum):
18+
"""Output format"""
19+
1620
flat = "flat"
1721
tree = "tree"
1822
full = "full"
1923
json = "json"
2024

2125
@staticmethod
2226
def parse(ctx, param, value):
27+
"""Parse from click"""
2328
# Normalize and map to the enum so command handlers receive PrintMode
2429
if value is None:
2530
return None
@@ -39,6 +44,8 @@ def parse(ctx, param, value):
3944

4045

4146
def common_args():
47+
"""Common arguments for search commands"""
48+
4249
def decorator(f):
4350
f = opt_filter(f)
4451
f = opt_mode(f)
@@ -49,14 +56,17 @@ def decorator(f):
4956

5057

5158
def do_fetch(url: str):
59+
"""Do the fetch and parse."""
5260
return MetricsTree(Parser().parse(FetcherURL(url).fetch()))
5361

5462

5563
def mk_indent(i: int, s: str) -> str:
64+
"""Indent a line"""
5665
return "\t" * i + s
5766

5867

5968
def render_metric(m: Metric) -> str:
69+
"""Render a metric in a human-readable format."""
6070
return f"{m.name} ({m.type}) {m.help or ''}"
6171

6272

alpacloud/promls/fetch.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def fetch(self):
2929

3030

3131
class ParseError(Exception):
32+
"""Error parsing Prometheus metrics endpoint."""
33+
3234
def __init__(self, value, line: str):
3335
self.line = line
3436
super().__init__(value)
@@ -40,10 +42,6 @@ def __str__(self) -> str:
4042
class Parser:
4143
"""Parse metrics from Prometheus metrics endpoint."""
4244

43-
class State(Enum):
44-
metadata = "metadata"
45-
data = "data"
46-
4745
@dataclass
4846
class DataLine:
4947
"""Data line from Prometheus metrics endpoint."""
@@ -54,6 +52,8 @@ class DataLine:
5452
timestamp: int | None = None
5553

5654
class MetaKind(Enum):
55+
"""Kind of the line of metadata."""
56+
5757
HELP = "HELP"
5858
TYPE = "TYPE"
5959
COMMENT = "COMMENT"
@@ -72,6 +72,7 @@ def parse(self, lines: list[str]) -> dict[str, Metric]:
7272
return {k: self.parse_metric(k, v) for k, v in name2data.items()}
7373

7474
def group_lines(self, lines: list[str]):
75+
"""Group lines by the metric name."""
7576
name2data = defaultdict(list)
7677
for line in lines:
7778
# escape empty lines
@@ -90,6 +91,7 @@ def group_lines(self, lines: list[str]):
9091

9192
@staticmethod
9293
def parse_data_line(line: str) -> DataLine:
94+
"""Subparser for a line of data."""
9395
# TODO: handle escaping in lines
9496
x = line.split(" ", 1)
9597
if len(x) != 2:
@@ -125,6 +127,7 @@ def parse_data_line(line: str) -> DataLine:
125127

126128
@staticmethod
127129
def parse_meta_line(line: str) -> MetaLine:
130+
"""Subparser for a line of metadata."""
128131
if not line.startswith("#"):
129132
raise ParseError(r"Invalid metadata line, did not start with #")
130133

@@ -145,6 +148,7 @@ def parse_meta_line(line: str) -> MetaLine:
145148

146149
@staticmethod
147150
def parse_metric(name, statements: list[Parser.DataLine | Parser.MetaLine]) -> Metric:
151+
"""Subpaarser for an actual metric."""
148152
# TODO: label sets
149153
# TODO: sample values
150154

alpacloud/promls/filter.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Filter metrics."""
2+
13
from __future__ import annotations
24

35
import logging
@@ -14,33 +16,44 @@
1416

1517
@dataclass
1618
class MetricsTree:
19+
"""A tree of metrics."""
20+
1721
metrics: dict[str, Metric]
1822

1923
@classmethod
2024
def mk_tree(cls, metrics: list[Metric]) -> MetricsTree:
25+
"""
26+
Construct a metrics tree from a list of metrics.
27+
"""
2128
return cls(
2229
{e.name: e for e in metrics},
2330
)
2431

2532
def filter(self, predicate: Predicate) -> MetricsTree:
33+
"""Filter this metrics tree."""
2634
return MetricsTree({k: v for k, v in self.metrics.items() if predicate(v)})
2735

2836

2937
def filter_name(pattern: re.Pattern) -> Predicate:
38+
"""Filter metrics for name"""
39+
3040
def predicate(metric: Metric) -> bool:
3141
return pattern.search(metric.name) is not None
3242

3343
return predicate
3444

3545

3646
def filter_any(pattern: re.Pattern) -> Predicate:
47+
"""Filter metrics for any field"""
48+
3749
def predicate(metric: Metric) -> bool:
3850
return pattern.search(metric.name) is not None or pattern.search(metric.help) is not None
3951

4052
return predicate
4153

4254

4355
def filter_path(path: list[str]) -> Predicate:
56+
"""Filter metrics for path components."""
4457
pattern = re.compile("^" + "_".join(path))
4558

4659
def predicate(metric: Metric) -> bool:

alpacloud/promls/filter_test.py

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import re
22

3-
from alpacloud.promls.filter import filter_name
3+
from alpacloud.promls.filter import filter_any, filter_name, filter_path
44
from alpacloud.promls.metrics import Metric
55

66

@@ -48,69 +48,47 @@ def test_search_ignores_helptext(self):
4848

4949
class TestFilterAny:
5050
def test_matches_when_pattern_in_name(self):
51-
from filter import filter_any
52-
5351
predicate = filter_any(re.compile("latency"))
5452
assert predicate(Metric("http_latency_seconds", "HTTP request latency", "histogram")) is True
5553

5654
def test_matches_when_pattern_in_help(self):
57-
from filter import filter_any
58-
5955
predicate = filter_any(re.compile(r"request latency"))
6056
assert predicate(Metric("http_seconds", "HTTP request latency", "histogram")) is True
6157

6258
def test_does_not_match_when_neither_name_nor_help_match(self):
63-
from filter import filter_any
64-
6559
predicate = filter_any(re.compile("throughput"))
6660
assert predicate(Metric("http_latency_seconds", "HTTP request latency", "histogram")) is False
6761

6862
def test_case_insensitive_with_flag(self):
69-
from filter import filter_any
70-
7163
predicate = filter_any(re.compile("LATENCY", re.IGNORECASE))
7264
assert predicate(Metric("http_latency_seconds", "HTTP request latency", "histogram")) is True
7365

7466
def test_empty_pattern_matches_everything(self):
75-
from filter import filter_any
76-
7767
predicate = filter_any(re.compile(""))
7868
assert predicate(Metric("anything", "and everything", "counter")) is True
7969

8070

8171
class TestFilterPath:
8272
def test_matches_prefix_path(self):
83-
from filter import filter_path
84-
8573
predicate = filter_path(["http", "server"])
8674
assert predicate(Metric("http_server_requests_total", "Total HTTP server requests", "counter")) is True
8775

8876
def test_does_not_match_when_prefix_not_at_start(self):
89-
from filter import filter_path
90-
9177
predicate = filter_path(["http", "server"])
9278
assert predicate(Metric("xhttp_server_requests_total", "prefixed with x", "counter")) is False
9379

9480
def test_does_not_match_different_prefix(self):
95-
from filter import filter_path
96-
9781
predicate = filter_path(["http", "server"])
9882
assert predicate(Metric("http_client_requests_total", "client metric", "counter")) is False
9983

10084
def test_exact_match(self):
101-
from filter import filter_path
102-
10385
predicate = filter_path(["http", "server"])
10486
assert predicate(Metric("http_server", "exact match", "gauge")) is True
10587

10688
def test_longer_path_matches(self):
107-
from filter import filter_path
108-
10989
predicate = filter_path(["a", "b", "c"])
11090
assert predicate(Metric("a_b_c_d", "longer metric name", "counter")) is True
11191

11292
def test_case_sensitive_by_default(self):
113-
from filter import filter_path
114-
11593
predicate = filter_path(["HTTP", "server"])
11694
assert predicate(Metric("http_server_requests_total", "lowercase name", "counter")) is False

alpacloud/promls/metrics.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Definitions for Prometheus metrics."""
2+
13
from dataclasses import dataclass
24

35

alpacloud/promls/util.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
"""Generic utilities."""
2+
13
import functools
24
from typing import Any, Dict, Mapping, Optional, TypeVar
35

46

57
def compose(*funcs):
8+
"""Sequentially compose functions."""
69
return functools.reduce(lambda f, g: lambda x: f(g(x)), funcs)
710

811

alpacloud/promls/vis.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import re
2-
from typing import Callable
32

43
from textual.app import App, ComposeResult
54
from textual.binding import Binding
@@ -96,7 +95,6 @@ async def action_goto(self):
9695
self.load_metrics(self.metrics)
9796
self.focus_findbox()
9897

99-
10098
def action_expand_all(self) -> None:
10199
"""Expand all nodes in the tree."""
102100
tree = self.query_one(Tree)

0 commit comments

Comments
 (0)