Skip to content

Commit 29497d4

Browse files
author
Michael Brewer
authored
fix(metrics): AttributeError raised by MediaManager and Typing and docs (#357)
* chore(data-classes): Typing and docs Changes: - Correct typing to make mypy happier - Correct highlighted lines * fix(metrics): AttributeError raises when setting metadata_set * chore: Correct the typing as suggested by mypy * chore: Set boto types as Any * chore(batch): Correct typing for processor * fix(parser): Check python version_info for typing Changes: - Use sys.version_info to determine where we need typing_extensions Reference: https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-new-additions-to-the-typing-module * docs(validation): Correct typing for parameters * chore: Code review changes
1 parent 4211796 commit 29497d4

File tree

22 files changed

+87
-71
lines changed

22 files changed

+87
-71
lines changed

aws_lambda_powertools/logging/lambda_context.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from typing import Any
2+
3+
14
class LambdaContextModel:
25
"""A handful of Lambda Runtime Context fields
36
@@ -31,7 +34,7 @@ def __init__(
3134
self.function_request_id = function_request_id
3235

3336

34-
def build_lambda_context_model(context: object) -> LambdaContextModel:
37+
def build_lambda_context_model(context: Any) -> LambdaContextModel:
3538
"""Captures Lambda function runtime info to be used across all log statements
3639
3740
Parameters

aws_lambda_powertools/logging/logger.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
import random
66
import sys
7-
from typing import Any, Callable, Dict, Union
7+
from typing import Any, Callable, Dict, Optional, Union
88

99
import jmespath
1010

@@ -318,12 +318,12 @@ def set_correlation_id(self, value: str):
318318
self.structure_logs(append=True, correlation_id=value)
319319

320320
@staticmethod
321-
def _get_log_level(level: Union[str, int]) -> Union[str, int]:
321+
def _get_log_level(level: Union[str, int, None]) -> Union[str, int]:
322322
""" Returns preferred log level set by the customer in upper case """
323323
if isinstance(level, int):
324324
return level
325325

326-
log_level: str = level or os.getenv("LOG_LEVEL")
326+
log_level: Optional[str] = level or os.getenv("LOG_LEVEL")
327327
if log_level is None:
328328
return logging.INFO
329329

aws_lambda_powertools/metrics/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def __init__(
8888
self.service = resolve_env_var_choice(choice=service, env=os.getenv(constants.SERVICE_NAME_ENV))
8989
self._metric_units = [unit.value for unit in MetricUnit]
9090
self._metric_unit_options = list(MetricUnit.__members__)
91-
self.metadata_set = self.metadata_set if metadata_set is not None else {}
91+
self.metadata_set = metadata_set if metadata_set is not None else {}
9292

9393
def add_metric(self, name: str, unit: Union[MetricUnit, str], value: float):
9494
"""Adds given metric

aws_lambda_powertools/metrics/metric.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
import logging
33
from contextlib import contextmanager
4-
from typing import Dict
4+
from typing import Dict, Optional, Union
55

66
from .base import MetricManager, MetricUnit
77

@@ -42,7 +42,7 @@ class SingleMetric(MetricManager):
4242
Inherits from `aws_lambda_powertools.metrics.base.MetricManager`
4343
"""
4444

45-
def add_metric(self, name: str, unit: MetricUnit, value: float):
45+
def add_metric(self, name: str, unit: Union[MetricUnit, str], value: float):
4646
"""Method to prevent more than one metric being created
4747
4848
Parameters
@@ -109,11 +109,11 @@ def single_metric(name: str, unit: MetricUnit, value: float, namespace: str = No
109109
SchemaValidationError
110110
When metric object fails EMF schema validation
111111
"""
112-
metric_set = None
112+
metric_set: Optional[Dict] = None
113113
try:
114114
metric: SingleMetric = SingleMetric(namespace=namespace)
115115
metric.add_metric(name=name, unit=unit, value=value)
116116
yield metric
117-
metric_set: Dict = metric.serialize_metric_set()
117+
metric_set = metric.serialize_metric_set()
118118
finally:
119119
print(json.dumps(metric_set, separators=(",", ":")))

aws_lambda_powertools/metrics/metrics.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import json
33
import logging
44
import warnings
5-
from typing import Any, Callable
5+
from typing import Any, Callable, Dict, Optional
66

77
from .base import MetricManager, MetricUnit
88
from .metric import single_metric
@@ -71,15 +71,15 @@ def do_something():
7171
When metric object fails EMF schema validation
7272
"""
7373

74-
_metrics = {}
75-
_dimensions = {}
76-
_metadata = {}
74+
_metrics: Dict[str, Any] = {}
75+
_dimensions: Dict[str, str] = {}
76+
_metadata: Dict[str, Any] = {}
7777

7878
def __init__(self, service: str = None, namespace: str = None):
7979
self.metric_set = self._metrics
8080
self.dimension_set = self._dimensions
8181
self.service = service
82-
self.namespace = namespace
82+
self.namespace: Optional[str] = namespace
8383
self.metadata_set = self._metadata
8484

8585
super().__init__(

aws_lambda_powertools/shared/functions.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from distutils.util import strtobool
2-
from typing import Any, Union
2+
from typing import Any, Optional, Union
33

44

55
def resolve_truthy_env_var_choice(env: Any, choice: bool = None) -> bool:
@@ -22,7 +22,7 @@ def resolve_truthy_env_var_choice(env: Any, choice: bool = None) -> bool:
2222
return choice if choice is not None else strtobool(env)
2323

2424

25-
def resolve_env_var_choice(env: Any, choice: bool = None) -> Union[bool, Any]:
25+
def resolve_env_var_choice(env: Any, choice: Optional[Any] = None) -> Union[bool, Any]:
2626
"""Pick explicit choice over env, if available, otherwise return env value received
2727
2828
NOTE: Environment variable should be resolved by the caller.

aws_lambda_powertools/utilities/batch/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def failure_handler(self, record: Any, exception: Tuple):
104104

105105
@lambda_handler_decorator
106106
def batch_processor(
107-
handler: Callable, event: Dict, context: Dict, record_handler: Callable, processor: BasePartialProcessor = None
107+
handler: Callable, event: Dict, context: Dict, record_handler: Callable, processor: BasePartialProcessor
108108
):
109109
"""
110110
Middleware to handle batch event processing

aws_lambda_powertools/utilities/batch/sqs.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def _get_queue_url(self) -> Optional[str]:
7171
Format QueueUrl from first records entry
7272
"""
7373
if not getattr(self, "records", None):
74-
return
74+
return None
7575

7676
*_, account_id, queue_name = self.records[0]["eventSourceARN"].split(":")
7777
return f"{self.client._endpoint.host}/{account_id}/{queue_name}"

aws_lambda_powertools/utilities/data_classes/appsync/resolver_utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ def register_resolver(func):
2727

2828
return register_resolver
2929

30-
def resolve(self, event: dict, context: LambdaContext) -> Any:
31-
event = AppSyncResolverEvent(event)
30+
def resolve(self, _event: dict, context: LambdaContext) -> Any:
31+
event = AppSyncResolverEvent(_event)
3232
resolver, config = self._resolver(event.type_name, event.field_name)
3333
kwargs = self._kwargs(event, context, config)
3434
return resolver(**kwargs)

aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py

+33-33
Original file line numberDiff line numberDiff line change
@@ -292,26 +292,26 @@ class CustomMessageTriggerEventResponse(DictWrapper):
292292
def sms_message(self) -> str:
293293
return self["response"]["smsMessage"]
294294

295-
@property
296-
def email_message(self) -> str:
297-
return self["response"]["emailMessage"]
298-
299-
@property
300-
def email_subject(self) -> str:
301-
return self["response"]["emailSubject"]
302-
303295
@sms_message.setter
304296
def sms_message(self, value: str):
305297
"""The custom SMS message to be sent to your users.
306298
Must include the codeParameter value received in the request."""
307299
self["response"]["smsMessage"] = value
308300

301+
@property
302+
def email_message(self) -> str:
303+
return self["response"]["emailMessage"]
304+
309305
@email_message.setter
310306
def email_message(self, value: str):
311307
"""The custom email message to be sent to your users.
312308
Must include the codeParameter value received in the request."""
313309
self["response"]["emailMessage"] = value
314310

311+
@property
312+
def email_subject(self) -> str:
313+
return self["response"]["emailSubject"]
314+
315315
@email_subject.setter
316316
def email_subject(self, value: str):
317317
"""The subject line for the custom message."""
@@ -471,26 +471,26 @@ class ClaimsOverrideDetails(DictWrapper):
471471
def claims_to_add_or_override(self) -> Optional[Dict[str, str]]:
472472
return self.get("claimsToAddOrOverride")
473473

474-
@property
475-
def claims_to_suppress(self) -> Optional[List[str]]:
476-
return self.get("claimsToSuppress")
477-
478-
@property
479-
def group_configuration(self) -> Optional[GroupOverrideDetails]:
480-
group_override_details = self.get("groupOverrideDetails")
481-
return None if group_override_details is None else GroupOverrideDetails(group_override_details)
482-
483474
@claims_to_add_or_override.setter
484475
def claims_to_add_or_override(self, value: Dict[str, str]):
485476
"""A map of one or more key-value pairs of claims to add or override.
486477
For group related claims, use groupOverrideDetails instead."""
487478
self._data["claimsToAddOrOverride"] = value
488479

480+
@property
481+
def claims_to_suppress(self) -> Optional[List[str]]:
482+
return self.get("claimsToSuppress")
483+
489484
@claims_to_suppress.setter
490485
def claims_to_suppress(self, value: List[str]):
491486
"""A list that contains claims to be suppressed from the identity token."""
492487
self._data["claimsToSuppress"] = value
493488

489+
@property
490+
def group_configuration(self) -> Optional[GroupOverrideDetails]:
491+
group_override_details = self.get("groupOverrideDetails")
492+
return None if group_override_details is None else GroupOverrideDetails(group_override_details)
493+
494494
@group_configuration.setter
495495
def group_configuration(self, value: Dict[str, Any]):
496496
"""The output object containing the current group configuration.
@@ -609,25 +609,25 @@ class DefineAuthChallengeTriggerEventResponse(DictWrapper):
609609
def challenge_name(self) -> str:
610610
return self["response"]["challengeName"]
611611

612-
@property
613-
def fail_authentication(self) -> bool:
614-
return bool(self["response"]["failAuthentication"])
615-
616-
@property
617-
def issue_tokens(self) -> bool:
618-
return bool(self["response"]["issueTokens"])
619-
620612
@challenge_name.setter
621613
def challenge_name(self, value: str):
622614
"""A string containing the name of the next challenge.
623615
If you want to present a new challenge to your user, specify the challenge name here."""
624616
self["response"]["challengeName"] = value
625617

618+
@property
619+
def fail_authentication(self) -> bool:
620+
return bool(self["response"]["failAuthentication"])
621+
626622
@fail_authentication.setter
627623
def fail_authentication(self, value: bool):
628624
"""Set to true if you want to terminate the current authentication process, or false otherwise."""
629625
self["response"]["failAuthentication"] = value
630626

627+
@property
628+
def issue_tokens(self) -> bool:
629+
return bool(self["response"]["issueTokens"])
630+
631631
@issue_tokens.setter
632632
def issue_tokens(self, value: bool):
633633
"""Set to true if you determine that the user has been sufficiently authenticated by
@@ -695,21 +695,17 @@ class CreateAuthChallengeTriggerEventResponse(DictWrapper):
695695
def public_challenge_parameters(self) -> Dict[str, str]:
696696
return self["response"]["publicChallengeParameters"]
697697

698-
@property
699-
def private_challenge_parameters(self) -> Dict[str, str]:
700-
return self["response"]["privateChallengeParameters"]
701-
702-
@property
703-
def challenge_metadata(self) -> str:
704-
return self["response"]["challengeMetadata"]
705-
706698
@public_challenge_parameters.setter
707699
def public_challenge_parameters(self, value: Dict[str, str]):
708700
"""One or more key-value pairs for the client app to use in the challenge to be presented to the user.
709701
This parameter should contain all of the necessary information to accurately present the challenge to
710702
the user."""
711703
self["response"]["publicChallengeParameters"] = value
712704

705+
@property
706+
def private_challenge_parameters(self) -> Dict[str, str]:
707+
return self["response"]["privateChallengeParameters"]
708+
713709
@private_challenge_parameters.setter
714710
def private_challenge_parameters(self, value: Dict[str, str]):
715711
"""This parameter is only used by the Verify Auth Challenge Response Lambda trigger.
@@ -719,6 +715,10 @@ def private_challenge_parameters(self, value: Dict[str, str]):
719715
for the question."""
720716
self["response"]["privateChallengeParameters"] = value
721717

718+
@property
719+
def challenge_metadata(self) -> str:
720+
return self["response"]["challengeMetadata"]
721+
722722
@challenge_metadata.setter
723723
def challenge_metadata(self, value: str):
724724
"""Your name for the custom challenge, if this is a custom challenge."""

aws_lambda_powertools/utilities/data_classes/common.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ def raw_event(self) -> Dict[str, Any]:
2525
return self._data
2626

2727

28-
def get_header_value(headers: Dict[str, str], name: str, default_value: str, case_sensitive: bool) -> Optional[str]:
28+
def get_header_value(
29+
headers: Dict[str, str], name: str, default_value: Optional[str], case_sensitive: Optional[bool]
30+
) -> Optional[str]:
2931
"""Get header value by name"""
3032
if case_sensitive:
3133
return headers.get(name, default_value)

aws_lambda_powertools/utilities/idempotency/persistence/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def __init__(
4040
idempotency_key,
4141
status: str = "",
4242
expiry_timestamp: int = None,
43-
response_data: str = "",
43+
response_data: Optional[str] = "",
4444
payload_hash: str = None,
4545
) -> None:
4646
"""

aws_lambda_powertools/utilities/parameters/appconfig.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
import os
7-
from typing import Dict, Optional, Union
7+
from typing import Any, Dict, Optional, Union
88
from uuid import uuid4
99

1010
import boto3
@@ -58,7 +58,7 @@ class AppConfigProvider(BaseProvider):
5858
5959
"""
6060

61-
client = None
61+
client: Any = None
6262

6363
def __init__(self, environment: str, application: Optional[str] = None, config: Optional[Config] = None):
6464
"""

aws_lambda_powertools/utilities/parameters/base.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
from abc import ABC, abstractmethod
88
from collections import namedtuple
99
from datetime import datetime, timedelta
10-
from typing import Dict, Optional, Tuple, Union
10+
from typing import Any, Dict, Optional, Tuple, Union
1111

1212
from .exceptions import GetParameterError, TransformParameterError
1313

1414
DEFAULT_MAX_AGE_SECS = 5
1515
ExpirableValue = namedtuple("ExpirableValue", ["value", "ttl"])
1616
# These providers will be dynamically initialized on first use of the helper functions
17-
DEFAULT_PROVIDERS = {}
17+
DEFAULT_PROVIDERS: Dict[str, Any] = {}
1818
TRANSFORM_METHOD_JSON = "json"
1919
TRANSFORM_METHOD_BINARY = "binary"
2020
SUPPORTED_TRANSFORM_METHODS = [TRANSFORM_METHOD_JSON, TRANSFORM_METHOD_BINARY]
@@ -25,7 +25,7 @@ class BaseProvider(ABC):
2525
Abstract Base Class for Parameter providers
2626
"""
2727

28-
store = None
28+
store: Any = None
2929

3030
def __init__(self):
3131
"""

aws_lambda_powertools/utilities/parameters/dynamodb.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55

6-
from typing import Dict, Optional
6+
from typing import Any, Dict, Optional
77

88
import boto3
99
from boto3.dynamodb.conditions import Key
@@ -139,7 +139,7 @@ class DynamoDBProvider(BaseProvider):
139139
c Parameter value c
140140
"""
141141

142-
table = None
142+
table: Any = None
143143
key_attr = None
144144
sort_attr = None
145145
value_attr = None

aws_lambda_powertools/utilities/parameters/secrets.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55

6-
from typing import Dict, Optional, Union
6+
from typing import Any, Dict, Optional, Union
77

88
import boto3
99
from botocore.config import Config
@@ -56,7 +56,7 @@ class SecretsProvider(BaseProvider):
5656
My parameter value
5757
"""
5858

59-
client = None
59+
client: Any = None
6060

6161
def __init__(self, config: Optional[Config] = None):
6262
"""

0 commit comments

Comments
 (0)