add more ruff linter
Jörg Thalheim committed
Nov 2, 2024 at 10:49 UTC
8e5be8674f19dd0d38d25ef1cb64b24582e237c3
6 files changed
+180
-86
build/datadog/hydra.py
+5
-4
@@ -1,11 +1,12 @@
1
-#! /usr/bin/env python
2
-import checks
3
-import requests
1
import json
2
3
+import requests
4
+
5
+import checks
6
+
7
8
class HydraCheck(checks.AgentCheck):
8
- def check(self, instance):
9
+ def check(self, instance) -> None:
10
r = requests.get(
11
"http://localhost:3000/status", headers={"Content-Type": "application/json"}
12
)
build/pluto/prometheus/exporters/channel-exporter.py
+7
-7
@@ -1,14 +1,14 @@
1
#!/usr/bin/env python3
2
3
-import requests
4
-from dateutil.parser import parse
5
-from prometheus_client import Counter, Histogram, Gauge, start_http_server
6
-import time
7
-import sys
3
+import json
4
import logging
5
+import sys
6
+import time
7
from pprint import pprint
10
-import json
8
9
+import requests
10
+from dateutil.parser import parse
11
+from prometheus_client import Counter, Gauge, Histogram, start_http_server
12
13
CHANNEL_REVISION = Gauge(
14
"channel_revision",
@@ -87,7 +87,7 @@ if __name__ == "__main__":
87
current=current,
88
).set(1)
89
CHANNEL_CURRENT.labels(channel=channel).set(current)
90
- print("updated {}".format(channel))
90
+ print(f"updated {channel}")
91
previous_revision = revisions.pop(channel, None)
92
revisions[channel] = revision
93
if previous_revision and previous_revision != revision:
build/pluto/prometheus/exporters/hydra-queue-runner-reexporter.py
+23
-30
@@ -1,20 +1,22 @@
1
#!/usr/bin/env nix-shell
2
#!nix-shell -i python3 -p python3 -p python3Packages.requests -p python3Packages.prometheus_client
3
4
-import requests
4
+import contextlib
5
import json
6
-from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily
7
-from prometheus_client import CollectorRegistry, start_http_server
6
import time
7
8
+import requests
9
+from prometheus_client import CollectorRegistry, start_http_server
10
+from prometheus_client.core import CounterMetricFamily, GaugeMetricFamily
11
+
12
11
-def debug_remaining_state(edict):
13
+def debug_remaining_state(edict) -> None:
14
# pprint(edict.remaining_state())
15
pass
16
17
18
class EvaporatingDict:
17
- def __init__(self, state):
19
+ def __init__(self, state) -> None:
20
self._state = state
21
22
def preserving_read(self, key):
@@ -22,13 +24,11 @@ class EvaporatingDict:
24
25
if isinstance(val, dict):
26
return EvaporatingDict(val)
25
- else:
26
- return val
27
+ return val
28
29
def preserving_read_default(self, key, default):
30
try:
30
- val = self.preserving_read(key)
31
- return val
31
+ return self.preserving_read(key)
32
except KeyError:
33
return default
34
@@ -47,7 +47,7 @@ class EvaporatingDict:
47
# todo: log bad reads?
48
return default
49
50
- def unused_read(self, key):
50
+ def unused_read(self, key) -> None:
51
self.destructive_read_default(key, default=None)
52
53
def remaining_state(self):
@@ -60,7 +60,7 @@ class EvaporatingDict:
60
61
62
class HydraScrapeImporter:
63
- def __init__(self, status):
63
+ def __init__(self, status) -> None:
64
self._status = EvaporatingDict(status)
65
66
def collect(self):
@@ -328,7 +328,6 @@ class HydraScrapeImporter:
328
except KeyError:
329
# no key, no metrics
330
s3 = None
331
- pass
331
if s3:
332
# Not in the above try to avoid the try catching mistakes
333
# in the following code
@@ -382,7 +381,7 @@ class HydraScrapeImporter:
381
c.add_metric([], value)
382
return c
383
385
- def unused_metric(self, key):
384
+ def unused_metric(self, key) -> None:
385
self._status.unused_read(key)
386
387
def preserving_read(self, key):
@@ -401,12 +400,12 @@ class HydraScrapeImporter:
400
return self._status.remaining_state()
401
402
404
-def blackhole(*args, **kwargs):
403
+def blackhole(*args, **kwargs) -> None:
404
return None
405
406
407
class MachineScrapeImporter:
409
- def __init__(self):
408
+ def __init__(self) -> None:
409
labels = ["host"]
410
self.consective_failures = GaugeMetricFamily(
411
"hydra_machine_consecutive_failures",
@@ -450,7 +449,7 @@ class MachineScrapeImporter:
449
labels=labels,
450
)
451
453
- def load_machine(self, name, report):
452
+ def load_machine(self, name, report) -> None:
453
report.unused_read("mandatoryFeatures")
454
report.unused_read("supportedFeatures")
455
report.unused_read("systemTypes")
@@ -461,10 +460,8 @@ class MachineScrapeImporter:
460
labels, report.destructive_read("consecutiveFailures")
461
)
462
self.current_jobs.add_metric(labels, report.destructive_read("currentJobs"))
464
- try:
463
+ with contextlib.suppress(KeyError):
464
self.idle_since.add_metric(labels, report.destructive_read("idleSince"))
466
- except KeyError:
467
- pass
465
self.disabled_until.add_metric(labels, report.destructive_read("disabledUntil"))
466
self.enabled.add_metric(labels, 1 if report.destructive_read("enabled") else 0)
467
self.last_failure.add_metric(labels, report.destructive_read("lastFailure"))
@@ -492,7 +489,7 @@ class MachineScrapeImporter:
489
490
491
class JobsetScrapeImporter:
495
- def __init__(self):
492
+ def __init__(self) -> None:
493
self.seconds = CounterMetricFamily(
494
"hydra_jobset_seconds_total",
495
"Total number of seconds the jobset has been building",
@@ -504,7 +501,7 @@ class JobsetScrapeImporter:
501
labels=["name"],
502
)
503
507
- def load_jobset(self, name, report):
504
+ def load_jobset(self, name, report) -> None:
505
self.seconds.add_metric([name], report.destructive_read("seconds"))
506
self.shares_used.add_metric([name], report.destructive_read("shareUsed"))
507
debug_remaining_state(report)
@@ -515,7 +512,7 @@ class JobsetScrapeImporter:
512
513
514
class MachineTypeScrapeImporter:
518
- def __init__(self):
515
+ def __init__(self) -> None:
516
self.runnable = GaugeMetricFamily(
517
"hydra_machine_type_runnable",
518
"Number of currently runnable builds",
@@ -537,17 +534,13 @@ class MachineTypeScrapeImporter:
534
labels=["machineType"],
535
)
536
540
- def load_machine_type(self, name, report):
537
+ def load_machine_type(self, name, report) -> None:
538
self.runnable.add_metric([name], report.destructive_read("runnable"))
539
self.running.add_metric([name], report.destructive_read("running"))
543
- try:
540
+ with contextlib.suppress(KeyError):
541
self.wait_time.add_metric([name], report.destructive_read("waitTime"))
545
- except KeyError:
546
- pass
547
- try:
542
+ with contextlib.suppress(KeyError):
543
self.last_active.add_metric([name], report.destructive_read("lastActive"))
549
- except KeyError:
550
- pass
544
545
debug_remaining_state(report)
546
@@ -559,7 +552,7 @@ class MachineTypeScrapeImporter:
552
553
554
class ScrapeCollector:
562
- def __init__(self):
555
+ def __init__(self) -> None:
556
pass
557
558
def collect(self):
hydra-packet-importer/import.py
+27
-31
@@ -1,22 +1,22 @@
1
#!/usr/bin/env python3
2
3
-import json
4
-import packet # type: ignore
3
import base64
4
+import json
5
import sys
7
-from typing import Dict, Any, List, Optional
8
-from typing import TypedDict
6
+from typing import Any, TypedDict
7
+
8
+import packet
9
10
-DeviceKeys = List[Dict[str, Any]]
10
+DeviceKeys = list[dict[str, Any]]
11
12
13
class Metadata(TypedDict):
14
- user: Optional[str]
15
- features: List[str]
16
- mandatory_features: List[str]
14
+ user: str | None
15
+ features: list[str]
16
+ mandatory_features: list[str]
17
max_jobs: int
18
- system_types: List[str]
19
- speed_factor: Optional[int]
18
+ system_types: list[str]
19
+ speed_factor: int | None
20
21
22
class RemoteBuilder(TypedDict):
@@ -50,25 +50,22 @@ class Device(TypedDict):
50
51
52
class ProjectDeviceList(TypedDict):
53
- meta: Dict[str, Any]
54
- devices: List[Device]
53
+ meta: dict[str, Any]
54
+ devices: list[Device]
55
56
57
def debug(*args: Any, **kwargs: Any) -> None:
58
print(*args, file=sys.stderr, **kwargs)
59
60
61
-def get_builders(manager: Any) -> List[Builder]:
62
- builders: List[Builder] = []
61
+def get_builders(manager: Any) -> list[Builder]:
62
+ builders: list[Builder] = []
63
64
- page: Optional[str] = "projects/{}/devices?page={}".format(config["project_id"], 1)
64
+ page: str | None = "projects/{}/devices?page={}".format(config["project_id"], 1)
65
while page is not None:
66
debug(page)
67
data: ProjectDeviceList = manager.call_api(page)
68
- if data["meta"]["next"] is None:
69
- page = None
70
- else:
71
- page = data["meta"]["next"]["href"]
68
+ page = None if data["meta"]["next"] is None else data["meta"]["next"]["href"]
69
70
for device in data["devices"]:
71
if device["state"] != "active":
@@ -95,19 +92,19 @@ def get_builders(manager: Any) -> List[Builder]:
92
return builders
93
94
98
-def get_remote_builder_info(manager, device_id: str) -> Optional[RemoteBuilder]:
95
+def get_remote_builder_info(manager, device_id: str) -> RemoteBuilder | None:
96
# ... 50 is probably enough.
97
try:
101
- events_url = "devices/{}/events?per_page=50".format(device_id)
98
+ events_url = f"devices/{device_id}/events?per_page=50"
99
debug(events_url)
100
data = manager.call_api(events_url)
101
except Exception:
102
# 404 probably
103
return None
104
108
- host_key: Optional[HostKey] = None
109
- ssh_key: Optional[str] = None
110
- metadata: Optional[Metadata] = None
105
+ host_key: HostKey | None = None
106
+ ssh_key: str | None = None
107
+ metadata: Metadata | None = None
108
for event in data["events"]:
109
if event["type"] == "provisioning.104.01":
110
# we reached a "Device connected to DHCP system" event,
@@ -126,7 +123,7 @@ def get_remote_builder_info(manager, device_id: str) -> Optional[RemoteBuilder]:
123
return None
124
if event["type"] == "user.1001":
125
try:
129
- host_keys: List[HostKey] = [
126
+ host_keys: list[HostKey] = [
127
key for key in json.loads(event["body"]) if key["port"] == 22
128
]
129
host_key = host_keys[0]
@@ -138,16 +135,15 @@ def get_remote_builder_info(manager, device_id: str) -> Optional[RemoteBuilder]:
135
return None
136
137
141
-def strip_ssh_key_comment(key: str) -> Optional[str]:
138
+def strip_ssh_key_comment(key: str) -> str | None:
139
ssh_key_parts = key.rsplit(" ", 1)
140
if len(ssh_key_parts) == 2:
141
return ssh_key_parts[0]
145
- else:
146
- debug("# Skipped due keyscan failed to split on ' '")
147
- return None
142
+ debug("# Skipped due keyscan failed to split on ' '")
143
+ return None
144
145
150
-def main(config: Dict[str, Any]) -> None:
146
+def main(config: dict[str, Any]) -> None:
147
rows = []
148
manager = packet.Manager(auth_token=config["token"])
149
found = 0
@@ -176,7 +172,7 @@ def main(config: Dict[str, Any]) -> None:
172
)
173
)
174
179
- debug("# {} / {}".format(len(rows), found))
175
+ debug(f"# {len(rows)} / {found}")
176
print("\n".join(rows))
177
178
modules/prometheus/nixos-exporter/prometheus_nixos_exporter/__main__.py
+18
-14
@@ -2,34 +2,37 @@
2
#!nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ prometheus-client packaging ])"
3
4
5
-import subprocess
5
import json
6
import os
7
+import subprocess
8
import sys
9
import time
10
+from collections.abc import Iterator
11
+
12
from packaging.version import Version
11
-from prometheus_client.core import GaugeMetricFamily
13
from prometheus_client import CollectorRegistry, start_http_server
14
+from prometheus_client.core import GaugeMetricFamily
15
16
17
class NixosSystemCollector:
16
- def __init__(self):
18
+ def __init__(self) -> None:
19
nix_version = self.get_nix_version()
20
21
# https://github.com/NixOS/nix/pull/9242
22
self.nix_path_info_returns_object = nix_version >= Version("2.19.0")
23
22
- def get_nix_version(self):
23
- result = subprocess.run(["nix", "--version"], stdout=subprocess.PIPE)
24
+ def get_nix_version(self) -> Version:
25
+ result = subprocess.run(
26
+ ["nix", "--version"], stdout=subprocess.PIPE, check=False
27
+ )
28
29
if result.returncode == 0:
30
response = result.stdout.decode().strip()
31
return Version(response.split()[-1])
28
- else:
29
- print("Failed to determine nix version", file=sys.stderr)
30
- sys.exit(1)
32
+ print("Failed to determine nix version", file=sys.stderr)
33
+ sys.exit(1)
34
32
- def collect(self):
35
+ def collect(self) -> Iterator[GaugeMetricFamily]:
36
# note: Gauges because of rollbacks.
37
current_system = GaugeMetricFamily(
38
"nixos_current_system_time_seconds",
@@ -64,22 +67,23 @@ class NixosSystemCollector:
67
current_system_kernel_booted.add_metric([], booted_kernel == current_kernel)
68
yield current_system_kernel_booted
69
67
- def get_version_id(self, path):
70
+ def get_version_id(self, path: str) -> str:
71
result = subprocess.run(
72
["bash", "-c", f"source {path}/etc/os-release; echo $VERSION_ID"],
73
stdout=subprocess.PIPE,
74
+ check=False,
75
)
76
if result.returncode == 0:
77
return result.stdout.decode("utf-8").strip()
78
79
return None
80
77
- def get_kernel_out(self, path):
81
+ def get_kernel_out(self, path: str) -> str:
82
return os.path.dirname(os.readlink(os.path.join(path, "kernel")))
83
80
- def get_time(self, path):
84
+ def get_time(self, path: str) -> int:
85
result = subprocess.run(
82
- ["nix", "path-info", "--json", path], stdout=subprocess.PIPE
86
+ ["nix", "path-info", "--json", path], stdout=subprocess.PIPE, check=False
87
)
88
if result.returncode == 0:
89
parsed = json.loads(result.stdout)
@@ -95,7 +99,7 @@ class NixosSystemCollector:
99
return 0
100
101
98
-def main():
102
+def main() -> None:
103
registry = CollectorRegistry()
104
registry.register(NixosSystemCollector())
105
pyproject.toml
new
+100
@@ -0,0 +1,100 @@
1
+[tool.ruff]
2
+line-length = 88
3
+target-version = "py312"
4
+
5
+lint.select = ["ALL"]
6
+
7
+lint.ignore = [
8
+ # pydocstyle
9
+ "D",
10
+ # todo comments
11
+ "TD",
12
+ # fixmes
13
+ "FIX",
14
+
15
+ # Unused function argument
16
+ "ARG001",
17
+
18
+ ## breaks with nix-shell
19
+ # Shebang should be at the beginning of the file
20
+ "EXE005",
21
+ "EXE003",
22
+ "EXE001",
23
+
24
+ # Missing type annotation for `self` in method
25
+ "ANN101",
26
+ # Dynamically typed expressions (typing.Any)
27
+ "ANN401",
28
+ # Trailing comma missing
29
+ "COM812",
30
+ # Unnecessary `dict` call (rewrite as a literal)
31
+ "C408",
32
+ # Found commented-out code
33
+ "ERA001",
34
+ # Boolean-typed positional argument in function definition
35
+ "FBT001",
36
+ # Logging statement uses f-string
37
+ "G004",
38
+ # disabled on ruff's recommendation as causes problems with the formatter
39
+ "ISC001",
40
+ # Use of `assert` detected
41
+ "S101",
42
+ # `subprocess` call: check for execution of untrusted input
43
+ "S603",
44
+ # Starting a process with a partial executable path
45
+ "S607",
46
+ # Boolean default positional argument in function definition
47
+ "FBT002",
48
+
49
+ # Too many statements
50
+ "PLR0915",
51
+ # Too many arguments in function definition
52
+ "PLR0913",
53
+ "PLR0912", # Too many branches
54
+ # $X is too complex
55
+ "C901",
56
+
57
+ "E501", # line too long
58
+ "T201", # `print` found
59
+ "T203", # `pprint` found
60
+ "PLR2004", # Magic value used in comparison
61
+]
62
+
63
+# TODO fixes
64
+[tool.ruff.lint.per-file-ignores]
65
+"modules/prometheus/nixos-exporter/prometheus_nixos_exporter/__main__.py" = [
66
+ "PTH115",
67
+ "PTH118",
68
+ "PTH120"
69
+]
70
+"hydra-packet-importer/import.py" = [
71
+ "ANN001",
72
+ "PTH123",
73
+ "BLE001",
74
+ "S110"
75
+]
76
+"build/pluto/prometheus/exporters/**.py" = [
77
+ "ANN"
78
+]
79
+"build/datadog/hydra.py" = [
80
+ "ANN001",
81
+ "ARG002",
82
+ "INP001",
83
+ "S113",
84
+]
85
+"build/pluto/prometheus/exporters/channel-exporter.py" = [
86
+ "BLE001",
87
+ "PTH123"
88
+]
89
+"build/pluto/prometheus/exporters/hydra-queue-runner-reexporter.py" = [
90
+ "TRY300",
91
+ "N806",
92
+ "A002",
93
+ "PTH123",
94
+ "S113"
95
+]
96
+
97
+[[tool.mypy.overrides]]
98
+module = "packet.*"
99
+ignore_missing_imports = true
100
+