From 971bd288b2b952331f27f3d77b30f1e89250b5ac Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Wed, 9 Aug 2023 12:07:35 +0200 Subject: [PATCH] refactor: type EMF output with TypedDict Signed-off-by: heitorlessa --- aws_lambda_powertools/metrics/metrics.py | 3 ++- .../provider/cloudwatch_emf/cloudwatch.py | 6 +++-- .../metrics/provider/cloudwatch_emf/types.py | 24 +++++++++++++++++ .../metrics/test_metrics_cloudwatch_emf.py | 26 ++++++++++++++----- 4 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py diff --git a/aws_lambda_powertools/metrics/metrics.py b/aws_lambda_powertools/metrics/metrics.py index 66f6fa2c..900e0da7 100644 --- a/aws_lambda_powertools/metrics/metrics.py +++ b/aws_lambda_powertools/metrics/metrics.py @@ -5,6 +5,7 @@ from typing import Any, Callable, Dict, Optional from aws_lambda_powertools.metrics.base import MetricResolution, MetricUnit from aws_lambda_powertools.metrics.provider.cloudwatch_emf.cloudwatch import AmazonCloudWatchEMFProvider +from aws_lambda_powertools.metrics.provider.cloudwatch_emf.types import CloudWatchEMFOutput class Metrics: @@ -115,7 +116,7 @@ class Metrics: metrics: Dict | None = None, dimensions: Dict | None = None, metadata: Dict | None = None, - ) -> Dict: + ) -> CloudWatchEMFOutput: return self.provider.serialize_metric_set(metrics=metrics, dimensions=dimensions, metadata=metadata) def add_metadata(self, key: str, value: Any) -> None: diff --git a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py index fad98e4e..5f1db811 100644 --- a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py +++ b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py @@ -18,6 +18,7 @@ from aws_lambda_powertools.metrics.functions import ( from aws_lambda_powertools.metrics.provider.base import BaseProvider from aws_lambda_powertools.metrics.provider.cloudwatch_emf.constants import MAX_DIMENSIONS, MAX_METRICS from aws_lambda_powertools.metrics.provider.cloudwatch_emf.metric_properties import MetricResolution, MetricUnit +from aws_lambda_powertools.metrics.provider.cloudwatch_emf.types import CloudWatchEMFOutput from aws_lambda_powertools.metrics.types import MetricNameUnitResolution from aws_lambda_powertools.shared import constants from aws_lambda_powertools.shared.functions import resolve_env_var_choice @@ -152,7 +153,7 @@ class AmazonCloudWatchEMFProvider(BaseProvider): metrics: Dict | None = None, dimensions: Dict | None = None, metadata: Dict | None = None, - ) -> Dict: + ) -> CloudWatchEMFOutput: """Serializes metric and dimensions set Parameters @@ -238,7 +239,8 @@ class AmazonCloudWatchEMFProvider(BaseProvider): }, ], }, - **dimensions, # "service": "test_service" + # NOTE: Mypy doesn't recognize splats '** syntax' in TypedDict + **dimensions, # type: ignore[misc] # "service": "test_service" **metadata, # "username": "test" **metric_names_and_values, # "single_metric": 1.0 } diff --git a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py new file mode 100644 index 00000000..bf3a48ea --- /dev/null +++ b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py @@ -0,0 +1,24 @@ +from typing import List + +from typing_extensions import NotRequired, TypedDict + + +class CloudWatchEMFMetric(TypedDict): + Name: str + Unit: str + StorageResolution: NotRequired[int] + + +class CloudWatchEMFMetrics(TypedDict): + Namespace: str + Dimensions: List[List[str]] # [ [ 'test_dimension' ] ] + Metrics: List[CloudWatchEMFMetric] + + +class CloudWatchEMFRoot(TypedDict): + Timestamp: int + CloudWatchMetrics: List[CloudWatchEMFMetrics] + + +class CloudWatchEMFOutput(TypedDict): + _aws: CloudWatchEMFRoot diff --git a/tests/functional/metrics/test_metrics_cloudwatch_emf.py b/tests/functional/metrics/test_metrics_cloudwatch_emf.py index 101c3d86..5c4a1de1 100644 --- a/tests/functional/metrics/test_metrics_cloudwatch_emf.py +++ b/tests/functional/metrics/test_metrics_cloudwatch_emf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import json import warnings from collections import namedtuple @@ -16,16 +18,23 @@ from aws_lambda_powertools.metrics import ( SchemaValidationError, single_metric, ) -from aws_lambda_powertools.metrics.provider.cloudwatch_emf.cloudwatch import AmazonCloudWatchEMFProvider -from aws_lambda_powertools.metrics.provider.cloudwatch_emf.constants import MAX_DIMENSIONS +from aws_lambda_powertools.metrics.provider.cloudwatch_emf.cloudwatch import ( + AmazonCloudWatchEMFProvider, +) +from aws_lambda_powertools.metrics.provider.cloudwatch_emf.constants import ( + MAX_DIMENSIONS, +) +from aws_lambda_powertools.metrics.provider.cloudwatch_emf.types import ( + CloudWatchEMFOutput, +) def serialize_metrics( metrics: List[Dict], dimensions: List[Dict], namespace: str, - metadatas: List[Dict] = None, -) -> Dict: + metadatas: List[Dict] | None = None, +) -> CloudWatchEMFOutput: """Helper function to build EMF object from a list of metrics, dimensions""" my_metrics = AmazonCloudWatchEMFProvider(namespace=namespace) for dimension in dimensions: @@ -42,7 +51,12 @@ def serialize_metrics( return my_metrics.serialize_metric_set() -def serialize_single_metric(metric: Dict, dimension: Dict, namespace: str, metadata: Dict = None) -> Dict: +def serialize_single_metric( + metric: Dict, + dimension: Dict, + namespace: str, + metadata: Dict | None = None, +) -> CloudWatchEMFOutput: """Helper function to build EMF object from a given metric, dimension and namespace""" my_metrics = AmazonCloudWatchEMFProvider(namespace=namespace) my_metrics.add_metric(**metric) @@ -64,7 +78,7 @@ def capture_metrics_output(capsys): return json.loads(capsys.readouterr().out.strip()) -def capture_metrics_output_multiple_emf_objects(capsys): +def capture_metrics_output_multiple_emf_objects(capsys) -> List[CloudWatchEMFOutput]: return [json.loads(line.strip()) for line in capsys.readouterr().out.split("\n") if line] -- 2.39.2 (Apple Git-143)