From 93563b01a282f3431604c069e9e427a4b0b062e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Smith?= Date: Wed, 12 Nov 2025 13:11:42 -0500 Subject: [PATCH 1/5] fix: Prometheus client missing time argument --- slo_generator/backends/prometheus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slo_generator/backends/prometheus.py b/slo_generator/backends/prometheus.py index fb679d6..da9912a 100644 --- a/slo_generator/backends/prometheus.py +++ b/slo_generator/backends/prometheus.py @@ -163,7 +163,7 @@ def query( # noqa: PLR0913 labels = {} filter = PrometheusBackend._fmt_query(filter, window, operators, labels) LOGGER.debug(f"Query: {filter}") - response = self.client.query(metric=filter) + response = self.client.query(metric=filter, time=timestamp) response = json.loads(response) LOGGER.debug(pprint.pformat(response)) return response From fd48fccac1cbf706c2ae8660cf29d9ccf7b6ef2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Smith?= Date: Wed, 12 Nov 2025 15:10:09 -0500 Subject: [PATCH 2/5] chore: linting --- slo_generator/api/main.py | 2 +- slo_generator/backends/cloud_monitoring_mql.py | 8 +++----- .../backends/cloud_service_monitoring.py | 15 ++++++--------- slo_generator/backends/prometheus.py | 11 +++++------ slo_generator/cli.py | 2 +- slo_generator/compute.py | 3 +-- slo_generator/utils.py | 15 ++++++--------- 7 files changed, 23 insertions(+), 33 deletions(-) diff --git a/slo_generator/api/main.py b/slo_generator/api/main.py index 67cc8e4..4144f51 100644 --- a/slo_generator/api/main.py +++ b/slo_generator/api/main.py @@ -211,7 +211,7 @@ def process_batch_req(request, data, config): for url in urls: if "pubsub_batch_handler" in config: LOGGER.info(f"Sending {url} to pubsub batch handler.") - from google.cloud import pubsub_v1 + from google.cloud import pubsub_v1 # noqa: PLC0415 # pytype: disable=attribute-error diff --git a/slo_generator/backends/cloud_monitoring_mql.py b/slo_generator/backends/cloud_monitoring_mql.py index 392f7a7..1545218 100644 --- a/slo_generator/backends/cloud_monitoring_mql.py +++ b/slo_generator/backends/cloud_monitoring_mql.py @@ -18,11 +18,9 @@ import logging import pprint -import typing import warnings from collections import OrderedDict from datetime import datetime, timezone -from typing import Optional from google.api.distribution_pb2 import Distribution from google.cloud.monitoring_v3 import QueryTimeSeriesRequest @@ -74,8 +72,8 @@ def good_bad_ratio( """ measurement: dict = slo_config["spec"]["service_level_indicator"] filter_good: str = measurement["filter_good"] - filter_bad: Optional[str] = measurement.get("filter_bad") - filter_valid: Optional[str] = measurement.get("filter_valid") + filter_bad: str | None = measurement.get("filter_bad") + filter_valid: str | None = measurement.get("filter_valid") # Query 'good events' timeseries good_ts: list[TimeSeries] = self.query(timestamp, window, filter_good) @@ -115,7 +113,7 @@ def distribution_cut( measurement: dict = slo_config["spec"]["service_level_indicator"] filter_valid: str = measurement["filter_valid"] threshold_bucket: int = int(measurement["threshold_bucket"]) - good_below_threshold: typing.Optional[bool] = measurement.get( + good_below_threshold: bool | None = measurement.get( "good_below_threshold", True ) diff --git a/slo_generator/backends/cloud_service_monitoring.py b/slo_generator/backends/cloud_service_monitoring.py index bdd26e2..a999a48 100644 --- a/slo_generator/backends/cloud_service_monitoring.py +++ b/slo_generator/backends/cloud_service_monitoring.py @@ -22,7 +22,6 @@ import os import warnings from collections.abc import Sequence -from typing import Optional, Union import google.api_core.exceptions from google.cloud.monitoring_v3 import ServiceMonitoringServiceClient @@ -119,7 +118,7 @@ def window(self, timestamp: int, window: int, slo_config: dict) -> tuple: """ return self.retrieve_slo(timestamp, window, slo_config) - def delete(self, timestamp: int, window: int, slo_config: dict) -> Optional[dict]: + def delete(self, timestamp: int, window: int, slo_config: dict) -> dict | None: """Delete method. Args: @@ -221,7 +220,7 @@ def create_service(self, slo_config: dict) -> dict: ) return SSM.to_json(service) - def get_service(self, slo_config: dict) -> Optional[dict]: + def get_service(self, slo_config: dict) -> dict | None: """Get Service object from Cloud Service Monitoring API. Args: @@ -282,7 +281,7 @@ def build_service(self, slo_config: dict) -> dict: def build_service_id( self, slo_config: dict, - dest_project_id: Optional[str] = None, + dest_project_id: str | None = None, full: bool = False, ): """Build service id from SLO configuration. @@ -479,7 +478,7 @@ def build_slo(window: int, slo_config: dict) -> dict: # noqa: PLR0912, PLR0915 raise ValueError(f'Method "{method}" is not supported.') return slo - def get_slo(self, window: int, slo_config: dict) -> Optional[dict]: + def get_slo(self, window: int, slo_config: dict) -> dict | None: """Get SLO object from Cloud Service Monssitoring API. Args: @@ -555,7 +554,7 @@ def list_slos(self, service_path: str) -> list: # LOGGER.debug(slos) return [SSM.to_json(slo) for slo in slos] - def delete_slo(self, window: int, slo_config: dict) -> Optional[dict]: + def delete_slo(self, window: int, slo_config: dict) -> dict | None: """Delete SLO from Cloud Service Monitoring API. Args: @@ -634,9 +633,7 @@ def compare_slo(slo1: dict, slo2: dict) -> bool: return local_json == remote_json @staticmethod - def string_diff( - string1: Union[str, Sequence[str]], string2: Union[str, Sequence[str]] - ) -> list: + def string_diff(string1: str | Sequence[str], string2: str | Sequence[str]) -> list: """Diff 2 strings. Used to print comparison of JSONs for debugging. Args: diff --git a/slo_generator/backends/prometheus.py b/slo_generator/backends/prometheus.py index da9912a..31c2656 100644 --- a/slo_generator/backends/prometheus.py +++ b/slo_generator/backends/prometheus.py @@ -20,7 +20,6 @@ import logging import os import pprint -from typing import Optional, Union from prometheus_http_client import Prometheus @@ -141,9 +140,9 @@ def query( # noqa: PLR0913 self, filter: str, window: int, - timestamp: Optional[int] = None, - operators: Union[list, None] = None, - labels: Union[dict, None] = None, + timestamp: int | None = None, + operators: list | None = None, + labels: dict | None = None, ) -> dict: """Query Prometheus server. @@ -189,8 +188,8 @@ def count(response: dict) -> float: def _fmt_query( query: str, window: int, - operators: Union[list[str], None] = None, - labels: Union[dict[str, str], None] = None, + operators: list[str] | None = None, + labels: dict[str, str] | None = None, ) -> str: """Format Prometheus query: diff --git a/slo_generator/cli.py b/slo_generator/cli.py index 2958eae..d8cbb1e 100644 --- a/slo_generator/cli.py +++ b/slo_generator/cli.py @@ -166,7 +166,7 @@ def compute(slo_config, config, export, delete, timestamp): def api(ctx, config, exporters, signature_type, target, port): # noqa: PLR0913 """Run an API that can receive requests (supports both 'http' and 'cloudevents' signature types).""" - from functions_framework._cli import _cli + from functions_framework._cli import _cli # noqa: PLC0415 os.environ["EXPORTERS"] = exporters os.environ["CONFIG_PATH"] = config diff --git a/slo_generator/compute.py b/slo_generator/compute.py index 8a770bb..58982bc 100644 --- a/slo_generator/compute.py +++ b/slo_generator/compute.py @@ -19,7 +19,6 @@ import logging import pprint import time -from typing import Optional from slo_generator import constants, utils from slo_generator.migrations.migrator import report_v2tov1 @@ -31,7 +30,7 @@ def compute( # noqa: PLR0913 slo_config: dict, config: dict, - timestamp: Optional[float] = None, + timestamp: float | None = None, client=None, do_export: bool = False, delete: bool = False, diff --git a/slo_generator/utils.py b/slo_generator/utils.py index b88534f..0c4f812 100644 --- a/slo_generator/utils.py +++ b/slo_generator/utils.py @@ -28,7 +28,6 @@ from collections.abc import Mapping from datetime import datetime from pathlib import Path -from typing import Optional import yaml from dateutil import tz @@ -47,7 +46,7 @@ def load_configs( - path: str, ctx: os._Environ = os.environ, kind: Optional[str] = None + path: str, ctx: os._Environ = os.environ, kind: str | None = None ) -> list: """Load multiple slo-generator configs from a folder path. @@ -67,8 +66,8 @@ def load_configs( def load_config( - path: str, ctx: os._Environ = os.environ, kind: Optional[str] = None -) -> Optional[dict]: + path: str, ctx: os._Environ = os.environ, kind: str | None = None +) -> dict | None: """Load any slo-generator config, from a local path, a GCS URL, or directly from a string content. @@ -110,9 +109,7 @@ def load_config( raise -def parse_config( - path: Optional[str] = None, content=None, ctx: os._Environ = os.environ -): +def parse_config(path: str | None = None, content=None, ctx: os._Environ = os.environ): """Load a yaml configuration file and resolve environment variables in it. Args: @@ -188,14 +185,14 @@ def setup_logging(): # Ignore Cloud SDK warning when using a user instead of service account try: - from google.auth._default import _CLOUD_SDK_CREDENTIALS_WARNING + from google.auth._default import _CLOUD_SDK_CREDENTIALS_WARNING # noqa: PLC0415 warnings.filterwarnings("ignore", message=_CLOUD_SDK_CREDENTIALS_WARNING) except ImportError: pass -def get_human_time(timestamp: int, timezone: Optional[str] = None) -> str: +def get_human_time(timestamp: int, timezone: str | None = None) -> str: """Get human-readable timestamp from UNIX UTC timestamp. Args: From 5df0b75ff2ebd5ca671358995bc5c920f4208a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Smith?= Date: Wed, 12 Nov 2025 15:17:30 -0500 Subject: [PATCH 3/5] Revert "chore: linting" This reverts commit fd48fccac1cbf706c2ae8660cf29d9ccf7b6ef2f. --- slo_generator/api/main.py | 2 +- slo_generator/backends/cloud_monitoring_mql.py | 8 +++++--- .../backends/cloud_service_monitoring.py | 15 +++++++++------ slo_generator/backends/prometheus.py | 11 ++++++----- slo_generator/cli.py | 2 +- slo_generator/compute.py | 3 ++- slo_generator/utils.py | 15 +++++++++------ 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/slo_generator/api/main.py b/slo_generator/api/main.py index 4144f51..67cc8e4 100644 --- a/slo_generator/api/main.py +++ b/slo_generator/api/main.py @@ -211,7 +211,7 @@ def process_batch_req(request, data, config): for url in urls: if "pubsub_batch_handler" in config: LOGGER.info(f"Sending {url} to pubsub batch handler.") - from google.cloud import pubsub_v1 # noqa: PLC0415 + from google.cloud import pubsub_v1 # pytype: disable=attribute-error diff --git a/slo_generator/backends/cloud_monitoring_mql.py b/slo_generator/backends/cloud_monitoring_mql.py index 1545218..392f7a7 100644 --- a/slo_generator/backends/cloud_monitoring_mql.py +++ b/slo_generator/backends/cloud_monitoring_mql.py @@ -18,9 +18,11 @@ import logging import pprint +import typing import warnings from collections import OrderedDict from datetime import datetime, timezone +from typing import Optional from google.api.distribution_pb2 import Distribution from google.cloud.monitoring_v3 import QueryTimeSeriesRequest @@ -72,8 +74,8 @@ def good_bad_ratio( """ measurement: dict = slo_config["spec"]["service_level_indicator"] filter_good: str = measurement["filter_good"] - filter_bad: str | None = measurement.get("filter_bad") - filter_valid: str | None = measurement.get("filter_valid") + filter_bad: Optional[str] = measurement.get("filter_bad") + filter_valid: Optional[str] = measurement.get("filter_valid") # Query 'good events' timeseries good_ts: list[TimeSeries] = self.query(timestamp, window, filter_good) @@ -113,7 +115,7 @@ def distribution_cut( measurement: dict = slo_config["spec"]["service_level_indicator"] filter_valid: str = measurement["filter_valid"] threshold_bucket: int = int(measurement["threshold_bucket"]) - good_below_threshold: bool | None = measurement.get( + good_below_threshold: typing.Optional[bool] = measurement.get( "good_below_threshold", True ) diff --git a/slo_generator/backends/cloud_service_monitoring.py b/slo_generator/backends/cloud_service_monitoring.py index a999a48..bdd26e2 100644 --- a/slo_generator/backends/cloud_service_monitoring.py +++ b/slo_generator/backends/cloud_service_monitoring.py @@ -22,6 +22,7 @@ import os import warnings from collections.abc import Sequence +from typing import Optional, Union import google.api_core.exceptions from google.cloud.monitoring_v3 import ServiceMonitoringServiceClient @@ -118,7 +119,7 @@ def window(self, timestamp: int, window: int, slo_config: dict) -> tuple: """ return self.retrieve_slo(timestamp, window, slo_config) - def delete(self, timestamp: int, window: int, slo_config: dict) -> dict | None: + def delete(self, timestamp: int, window: int, slo_config: dict) -> Optional[dict]: """Delete method. Args: @@ -220,7 +221,7 @@ def create_service(self, slo_config: dict) -> dict: ) return SSM.to_json(service) - def get_service(self, slo_config: dict) -> dict | None: + def get_service(self, slo_config: dict) -> Optional[dict]: """Get Service object from Cloud Service Monitoring API. Args: @@ -281,7 +282,7 @@ def build_service(self, slo_config: dict) -> dict: def build_service_id( self, slo_config: dict, - dest_project_id: str | None = None, + dest_project_id: Optional[str] = None, full: bool = False, ): """Build service id from SLO configuration. @@ -478,7 +479,7 @@ def build_slo(window: int, slo_config: dict) -> dict: # noqa: PLR0912, PLR0915 raise ValueError(f'Method "{method}" is not supported.') return slo - def get_slo(self, window: int, slo_config: dict) -> dict | None: + def get_slo(self, window: int, slo_config: dict) -> Optional[dict]: """Get SLO object from Cloud Service Monssitoring API. Args: @@ -554,7 +555,7 @@ def list_slos(self, service_path: str) -> list: # LOGGER.debug(slos) return [SSM.to_json(slo) for slo in slos] - def delete_slo(self, window: int, slo_config: dict) -> dict | None: + def delete_slo(self, window: int, slo_config: dict) -> Optional[dict]: """Delete SLO from Cloud Service Monitoring API. Args: @@ -633,7 +634,9 @@ def compare_slo(slo1: dict, slo2: dict) -> bool: return local_json == remote_json @staticmethod - def string_diff(string1: str | Sequence[str], string2: str | Sequence[str]) -> list: + def string_diff( + string1: Union[str, Sequence[str]], string2: Union[str, Sequence[str]] + ) -> list: """Diff 2 strings. Used to print comparison of JSONs for debugging. Args: diff --git a/slo_generator/backends/prometheus.py b/slo_generator/backends/prometheus.py index 31c2656..da9912a 100644 --- a/slo_generator/backends/prometheus.py +++ b/slo_generator/backends/prometheus.py @@ -20,6 +20,7 @@ import logging import os import pprint +from typing import Optional, Union from prometheus_http_client import Prometheus @@ -140,9 +141,9 @@ def query( # noqa: PLR0913 self, filter: str, window: int, - timestamp: int | None = None, - operators: list | None = None, - labels: dict | None = None, + timestamp: Optional[int] = None, + operators: Union[list, None] = None, + labels: Union[dict, None] = None, ) -> dict: """Query Prometheus server. @@ -188,8 +189,8 @@ def count(response: dict) -> float: def _fmt_query( query: str, window: int, - operators: list[str] | None = None, - labels: dict[str, str] | None = None, + operators: Union[list[str], None] = None, + labels: Union[dict[str, str], None] = None, ) -> str: """Format Prometheus query: diff --git a/slo_generator/cli.py b/slo_generator/cli.py index d8cbb1e..2958eae 100644 --- a/slo_generator/cli.py +++ b/slo_generator/cli.py @@ -166,7 +166,7 @@ def compute(slo_config, config, export, delete, timestamp): def api(ctx, config, exporters, signature_type, target, port): # noqa: PLR0913 """Run an API that can receive requests (supports both 'http' and 'cloudevents' signature types).""" - from functions_framework._cli import _cli # noqa: PLC0415 + from functions_framework._cli import _cli os.environ["EXPORTERS"] = exporters os.environ["CONFIG_PATH"] = config diff --git a/slo_generator/compute.py b/slo_generator/compute.py index 58982bc..8a770bb 100644 --- a/slo_generator/compute.py +++ b/slo_generator/compute.py @@ -19,6 +19,7 @@ import logging import pprint import time +from typing import Optional from slo_generator import constants, utils from slo_generator.migrations.migrator import report_v2tov1 @@ -30,7 +31,7 @@ def compute( # noqa: PLR0913 slo_config: dict, config: dict, - timestamp: float | None = None, + timestamp: Optional[float] = None, client=None, do_export: bool = False, delete: bool = False, diff --git a/slo_generator/utils.py b/slo_generator/utils.py index 0c4f812..b88534f 100644 --- a/slo_generator/utils.py +++ b/slo_generator/utils.py @@ -28,6 +28,7 @@ from collections.abc import Mapping from datetime import datetime from pathlib import Path +from typing import Optional import yaml from dateutil import tz @@ -46,7 +47,7 @@ def load_configs( - path: str, ctx: os._Environ = os.environ, kind: str | None = None + path: str, ctx: os._Environ = os.environ, kind: Optional[str] = None ) -> list: """Load multiple slo-generator configs from a folder path. @@ -66,8 +67,8 @@ def load_configs( def load_config( - path: str, ctx: os._Environ = os.environ, kind: str | None = None -) -> dict | None: + path: str, ctx: os._Environ = os.environ, kind: Optional[str] = None +) -> Optional[dict]: """Load any slo-generator config, from a local path, a GCS URL, or directly from a string content. @@ -109,7 +110,9 @@ def load_config( raise -def parse_config(path: str | None = None, content=None, ctx: os._Environ = os.environ): +def parse_config( + path: Optional[str] = None, content=None, ctx: os._Environ = os.environ +): """Load a yaml configuration file and resolve environment variables in it. Args: @@ -185,14 +188,14 @@ def setup_logging(): # Ignore Cloud SDK warning when using a user instead of service account try: - from google.auth._default import _CLOUD_SDK_CREDENTIALS_WARNING # noqa: PLC0415 + from google.auth._default import _CLOUD_SDK_CREDENTIALS_WARNING warnings.filterwarnings("ignore", message=_CLOUD_SDK_CREDENTIALS_WARNING) except ImportError: pass -def get_human_time(timestamp: int, timezone: str | None = None) -> str: +def get_human_time(timestamp: int, timezone: Optional[str] = None) -> str: """Get human-readable timestamp from UNIX UTC timestamp. Args: From 127a665dfdd771edd408ab5e0aa1f469192d2bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Smith?= Date: Wed, 12 Nov 2025 15:42:00 -0500 Subject: [PATCH 4/5] chore: backward-compatible linting --- slo_generator/api/main.py | 2 +- slo_generator/backends/cloud_monitoring_mql.py | 1 + slo_generator/backends/cloud_service_monitoring.py | 1 + slo_generator/backends/prometheus.py | 1 + slo_generator/cli.py | 2 +- slo_generator/compute.py | 1 + slo_generator/utils.py | 3 ++- 7 files changed, 8 insertions(+), 3 deletions(-) diff --git a/slo_generator/api/main.py b/slo_generator/api/main.py index 67cc8e4..4144f51 100644 --- a/slo_generator/api/main.py +++ b/slo_generator/api/main.py @@ -211,7 +211,7 @@ def process_batch_req(request, data, config): for url in urls: if "pubsub_batch_handler" in config: LOGGER.info(f"Sending {url} to pubsub batch handler.") - from google.cloud import pubsub_v1 + from google.cloud import pubsub_v1 # noqa: PLC0415 # pytype: disable=attribute-error diff --git a/slo_generator/backends/cloud_monitoring_mql.py b/slo_generator/backends/cloud_monitoring_mql.py index 392f7a7..79fc718 100644 --- a/slo_generator/backends/cloud_monitoring_mql.py +++ b/slo_generator/backends/cloud_monitoring_mql.py @@ -15,6 +15,7 @@ `cloud_monitoring_mql.py` Cloud Monitoring backend implementation with MQL (Monitoring Query Language). """ +# ruff: noqa: UP045 import logging import pprint diff --git a/slo_generator/backends/cloud_service_monitoring.py b/slo_generator/backends/cloud_service_monitoring.py index bdd26e2..96c4246 100644 --- a/slo_generator/backends/cloud_service_monitoring.py +++ b/slo_generator/backends/cloud_service_monitoring.py @@ -15,6 +15,7 @@ `cloud_service_monitoring.py` Cloud Service Monitoring exporter class. """ +# ruff: noqa: UP045,UP007 import difflib import json diff --git a/slo_generator/backends/prometheus.py b/slo_generator/backends/prometheus.py index da9912a..d1da8ad 100644 --- a/slo_generator/backends/prometheus.py +++ b/slo_generator/backends/prometheus.py @@ -15,6 +15,7 @@ `prometheus.py` Prometheus backend implementation. """ +# ruff: noqa: UP045,UP007 import json import logging diff --git a/slo_generator/cli.py b/slo_generator/cli.py index 2958eae..d8cbb1e 100644 --- a/slo_generator/cli.py +++ b/slo_generator/cli.py @@ -166,7 +166,7 @@ def compute(slo_config, config, export, delete, timestamp): def api(ctx, config, exporters, signature_type, target, port): # noqa: PLR0913 """Run an API that can receive requests (supports both 'http' and 'cloudevents' signature types).""" - from functions_framework._cli import _cli + from functions_framework._cli import _cli # noqa: PLC0415 os.environ["EXPORTERS"] = exporters os.environ["CONFIG_PATH"] = config diff --git a/slo_generator/compute.py b/slo_generator/compute.py index 8a770bb..12ef9cb 100644 --- a/slo_generator/compute.py +++ b/slo_generator/compute.py @@ -15,6 +15,7 @@ `compute.py` Compute utilities. """ +# ruff: noqa: UP045 import logging import pprint diff --git a/slo_generator/utils.py b/slo_generator/utils.py index b88534f..f463da7 100644 --- a/slo_generator/utils.py +++ b/slo_generator/utils.py @@ -15,6 +15,7 @@ `utils.py` Utility functions. """ +# ruff: noqa: UP045 import argparse import errno @@ -188,7 +189,7 @@ def setup_logging(): # Ignore Cloud SDK warning when using a user instead of service account try: - from google.auth._default import _CLOUD_SDK_CREDENTIALS_WARNING + from google.auth._default import _CLOUD_SDK_CREDENTIALS_WARNING # noqa: PLC0415 warnings.filterwarnings("ignore", message=_CLOUD_SDK_CREDENTIALS_WARNING) except ImportError: From e27bfbbe714995c85eeb5e6df977fa007e512416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Smith?= Date: Wed, 12 Nov 2025 16:23:23 -0500 Subject: [PATCH 5/5] fix: Prometheus distribution cut ignores timestamp --- slo_generator/backends/prometheus.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slo_generator/backends/prometheus.py b/slo_generator/backends/prometheus.py index d1da8ad..2c05790 100644 --- a/slo_generator/backends/prometheus.py +++ b/slo_generator/backends/prometheus.py @@ -118,6 +118,7 @@ def distribution_cut( res_good = self.query( expr, window, + timestamp=timestamp, operators=["increase", "sum"], labels=labels, ) @@ -131,6 +132,7 @@ def distribution_cut( res_valid = self.query( expr_count, window, + timestamp=timestamp, operators=["increase", "sum"], ) valid_count = PrometheusBackend.count(res_valid)