From afb03f4c9a5cedb8a889412c37eb66f05d684109 Mon Sep 17 00:00:00 2001 From: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Date: Mon, 19 Aug 2024 06:38:16 -0500 Subject: [PATCH 1/2] refactor(typing): enable TCH, UP and FA100 ruff rules --- aws_lambda_powertools/__init__.py | 2 -- aws_lambda_powertools/event_handler/api_gateway.py | 2 +- .../event_handler/bedrock_agent.py | 2 +- .../event_handler/openapi/params.py | 2 +- .../event_handler/openapi/types.py | 6 ++++-- aws_lambda_powertools/logging/types.py | 5 +++-- .../metrics/provider/cloudwatch_emf/types.py | 5 +++-- aws_lambda_powertools/shared/cache_dict.py | 2 +- aws_lambda_powertools/shared/lazy_import.py | 2 +- aws_lambda_powertools/utilities/__init__.py | 2 -- aws_lambda_powertools/utilities/batch/__init__.py | 2 -- aws_lambda_powertools/utilities/batch/base.py | 2 +- aws_lambda_powertools/utilities/batch/exceptions.py | 2 +- .../utilities/feature_flags/feature_flags.py | 3 +-- .../utilities/idempotency/persistence/dynamodb.py | 2 +- .../utilities/idempotency/persistence/redis.py | 2 +- .../utilities/parameters/__init__.py | 2 -- aws_lambda_powertools/utilities/typing/__init__.py | 2 -- .../utilities/typing/lambda_client_context.py | 3 +-- .../typing/lambda_client_context_mobile_client.py | 5 +---- .../utilities/typing/lambda_cognito_identity.py | 5 +---- .../utilities/typing/lambda_context.py | 3 +-- docs/utilities/batch.md | 2 +- .../batch_processing/src/context_manager_access.py | 3 +-- .../src/bring_your_own_persistent_store.py | 2 +- ruff.toml | 11 ++++++++--- tests/e2e/parser/handlers/handler_with_union_tag.py | 2 -- .../data_masking/test_aws_encryption_sdk.py | 6 ++---- .../event_handler/test_openapi_serialization.py | 2 +- .../idempotency/persistence/test_redis_layer.py | 2 +- tests/functional/idempotency/test_idempotency.py | 2 +- tests/functional/idempotency/utils.py | 6 ++---- .../metrics/test_metrics_cloudwatch_emf.py | 10 ++++------ tests/functional/metrics/test_metrics_provider.py | 2 -- tests/functional/parser/test_parser.py | 4 ++-- .../functional/test_logger_powertools_formatter.py | 2 +- tests/functional/test_utilities_parameters.py | 13 +++++++------ tests/functional/validator/test_validator.py | 2 +- tests/unit/parser/test_vpc_latticev2.py | 2 +- tests/unit/test_tracing.py | 2 +- 40 files changed, 59 insertions(+), 79 deletions(-) diff --git a/aws_lambda_powertools/__init__.py b/aws_lambda_powertools/__init__.py index 14237bc7119..dbec3d35635 100644 --- a/aws_lambda_powertools/__init__.py +++ b/aws_lambda_powertools/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """Top-level package for Lambda Python Powertools.""" from pathlib import Path diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 16255cce749..372a4704944 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -1870,7 +1870,7 @@ def route( def register_resolver(func: Callable): methods = (method,) if isinstance(method, str) else method - logger.debug(f"Adding route using rule {rule} and methods: {','.join((m.upper() for m in methods))}") + logger.debug(f"Adding route using rule {rule} and methods: {','.join(m.upper() for m in methods)}") cors_enabled = self._cors_enabled if cors is None else cors diff --git a/aws_lambda_powertools/event_handler/bedrock_agent.py b/aws_lambda_powertools/event_handler/bedrock_agent.py index 6b71f742b11..faf551d1646 100644 --- a/aws_lambda_powertools/event_handler/bedrock_agent.py +++ b/aws_lambda_powertools/event_handler/bedrock_agent.py @@ -109,7 +109,7 @@ def get( # type: ignore[override] ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: security = None - return super(BedrockAgentResolver, self).get( + return super().get( rule, cors, compress, diff --git a/aws_lambda_powertools/event_handler/openapi/params.py b/aws_lambda_powertools/event_handler/openapi/params.py index 3374e228096..ffcef8b5096 100644 --- a/aws_lambda_powertools/event_handler/openapi/params.py +++ b/aws_lambda_powertools/event_handler/openapi/params.py @@ -328,7 +328,7 @@ def __init__( if default is not ...: raise AssertionError("Path parameters cannot have a default value") - super(Path, self).__init__( + super().__init__( default=default, default_factory=default_factory, annotation=annotation, diff --git a/aws_lambda_powertools/event_handler/openapi/types.py b/aws_lambda_powertools/event_handler/openapi/types.py index ef6b096aad0..59cf91f3567 100644 --- a/aws_lambda_powertools/event_handler/openapi/types.py +++ b/aws_lambda_powertools/event_handler/openapi/types.py @@ -2,10 +2,12 @@ import types from enum import Enum -from typing import Any, Callable, Dict, Set, Type, TypedDict, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, Set, Type, TypedDict, Union from pydantic import BaseModel -from typing_extensions import NotRequired + +if TYPE_CHECKING: + from typing_extensions import NotRequired CacheKey = Union[Callable[..., Any], None] IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]] diff --git a/aws_lambda_powertools/logging/types.py b/aws_lambda_powertools/logging/types.py index 20f993a0a01..25f094bc755 100644 --- a/aws_lambda_powertools/logging/types.py +++ b/aws_lambda_powertools/logging/types.py @@ -1,8 +1,9 @@ from __future__ import annotations -from typing import Any, Dict, TypedDict, Union +from typing import TYPE_CHECKING, Any, Dict, TypedDict, Union -from typing_extensions import NotRequired, TypeAlias +if TYPE_CHECKING: + from typing_extensions import NotRequired, TypeAlias class PowertoolsLogRecord(TypedDict): diff --git a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py index 6c94af94cf4..30ac9dba480 100644 --- a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py +++ b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py @@ -1,8 +1,9 @@ from __future__ import annotations -from typing import TypedDict +from typing import TYPE_CHECKING, TypedDict -from typing_extensions import NotRequired +if TYPE_CHECKING: + from typing_extensions import NotRequired class CloudWatchEMFMetric(TypedDict): diff --git a/aws_lambda_powertools/shared/cache_dict.py b/aws_lambda_powertools/shared/cache_dict.py index d7184cc1e2b..c45d704655a 100644 --- a/aws_lambda_powertools/shared/cache_dict.py +++ b/aws_lambda_powertools/shared/cache_dict.py @@ -25,7 +25,7 @@ def __setitem__(self, key, value): del self[oldest] def get(self, key, *args, **kwargs): - item = super(LRUDict, self).get(key, *args, **kwargs) + item = super().get(key, *args, **kwargs) if item: self.move_to_end(key=key) return item diff --git a/aws_lambda_powertools/shared/lazy_import.py b/aws_lambda_powertools/shared/lazy_import.py index e860a650f31..2aa5599ca8e 100644 --- a/aws_lambda_powertools/shared/lazy_import.py +++ b/aws_lambda_powertools/shared/lazy_import.py @@ -32,7 +32,7 @@ def __init__(self, local_name, parent_module_globals, name): # pylint: disable= self._local_name = local_name self._parent_module_globals = parent_module_globals - super(LazyLoader, self).__init__(name) + super().__init__(name) def _load(self): # Import the target module and insert it into the parent's namespace diff --git a/aws_lambda_powertools/utilities/__init__.py b/aws_lambda_powertools/utilities/__init__.py index 67be909187a..c81602a0599 100644 --- a/aws_lambda_powertools/utilities/__init__.py +++ b/aws_lambda_powertools/utilities/__init__.py @@ -1,3 +1 @@ -# -*- coding: utf-8 -*- - """General utilities for Powertools""" diff --git a/aws_lambda_powertools/utilities/batch/__init__.py b/aws_lambda_powertools/utilities/batch/__init__.py index e135655ef61..6073a0e325b 100644 --- a/aws_lambda_powertools/utilities/batch/__init__.py +++ b/aws_lambda_powertools/utilities/batch/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ Batch processing utility """ diff --git a/aws_lambda_powertools/utilities/batch/base.py b/aws_lambda_powertools/utilities/batch/base.py index b4756db8b72..cefc368763e 100644 --- a/aws_lambda_powertools/utilities/batch/base.py +++ b/aws_lambda_powertools/utilities/batch/base.py @@ -1,7 +1,7 @@ -# -*- coding: utf-8 -*- """ Batch processing utilities """ + from __future__ import annotations import asyncio diff --git a/aws_lambda_powertools/utilities/batch/exceptions.py b/aws_lambda_powertools/utilities/batch/exceptions.py index 2a501e034ce..c93b96a8f34 100644 --- a/aws_lambda_powertools/utilities/batch/exceptions.py +++ b/aws_lambda_powertools/utilities/batch/exceptions.py @@ -34,7 +34,7 @@ def __init__(self, msg="", child_exceptions: list[ExceptionInfo] | None = None): super().__init__(msg, child_exceptions) def __str__(self): - parent_exception_str = super(BatchProcessingError, self).__str__() + parent_exception_str = super().__str__() return self.format_exceptions(parent_exception_str) diff --git a/aws_lambda_powertools/utilities/feature_flags/feature_flags.py b/aws_lambda_powertools/utilities/feature_flags/feature_flags.py index 5ef21aff2f3..ae0cae6d31c 100644 --- a/aws_lambda_powertools/utilities/feature_flags/feature_flags.py +++ b/aws_lambda_powertools/utilities/feature_flags/feature_flags.py @@ -14,12 +14,11 @@ compare_time_range, ) from aws_lambda_powertools.utilities.feature_flags.exceptions import ConfigurationStoreError -from aws_lambda_powertools.utilities.feature_flags.types import P, T if TYPE_CHECKING: from aws_lambda_powertools.logging import Logger from aws_lambda_powertools.utilities.feature_flags.base import StoreProvider - from aws_lambda_powertools.utilities.feature_flags.types import JSONType + from aws_lambda_powertools.utilities.feature_flags.types import JSONType, P, T RULE_ACTION_MAPPING = { diff --git a/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py b/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py index 78b672385ca..23ef222b5c8 100644 --- a/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py +++ b/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py @@ -123,7 +123,7 @@ def __init__( self._deserializer = TypeDeserializer() - super(DynamoDBPersistenceLayer, self).__init__() + super().__init__() def _get_key(self, idempotency_key: str) -> dict: """Build primary key attribute simple or composite based on params. diff --git a/aws_lambda_powertools/utilities/idempotency/persistence/redis.py b/aws_lambda_powertools/utilities/idempotency/persistence/redis.py index 7226245a9b5..06a6548080b 100644 --- a/aws_lambda_powertools/utilities/idempotency/persistence/redis.py +++ b/aws_lambda_powertools/utilities/idempotency/persistence/redis.py @@ -310,7 +310,7 @@ def lambda_handler(event: dict, context: LambdaContext): self.validation_key_attr = validation_key_attr self._json_serializer = json.dumps self._json_deserializer = json.loads - super(RedisCachePersistenceLayer, self).__init__() + super().__init__() self._orphan_lock_timeout = min(10, self.expires_after_seconds) def _get_expiry_second(self, expiry_timestamp: int | None = None) -> int: diff --git a/aws_lambda_powertools/utilities/parameters/__init__.py b/aws_lambda_powertools/utilities/parameters/__init__.py index 9f8827ed9b6..71f57ab7c08 100644 --- a/aws_lambda_powertools/utilities/parameters/__init__.py +++ b/aws_lambda_powertools/utilities/parameters/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ Parameter retrieval and caching utility """ diff --git a/aws_lambda_powertools/utilities/typing/__init__.py b/aws_lambda_powertools/utilities/typing/__init__.py index 79e3ba3d6bf..a6c80395a88 100644 --- a/aws_lambda_powertools/utilities/typing/__init__.py +++ b/aws_lambda_powertools/utilities/typing/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ Typing for developer ease in the IDE """ diff --git a/aws_lambda_powertools/utilities/typing/lambda_client_context.py b/aws_lambda_powertools/utilities/typing/lambda_client_context.py index 25276f8eb90..d7753801e1d 100644 --- a/aws_lambda_powertools/utilities/typing/lambda_client_context.py +++ b/aws_lambda_powertools/utilities/typing/lambda_client_context.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from __future__ import annotations from typing import TYPE_CHECKING, Any @@ -9,7 +8,7 @@ ) -class LambdaClientContext(object): +class LambdaClientContext: _client: LambdaClientContextMobileClient _custom: dict[str, Any] _env: dict[str, Any] diff --git a/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py b/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py index bd204891d2b..b9063d4b319 100644 --- a/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py +++ b/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py @@ -1,7 +1,4 @@ -# -*- coding: utf-8 -*- - - -class LambdaClientContextMobileClient(object): +class LambdaClientContextMobileClient: """Mobile Client context that's provided to Lambda by the client application.""" _installation_id: str diff --git a/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py b/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py index 06679269330..664bf23ecb5 100644 --- a/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py +++ b/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py @@ -1,7 +1,4 @@ -# -*- coding: utf-8 -*- - - -class LambdaCognitoIdentity(object): +class LambdaCognitoIdentity: """Information about the Amazon Cognito identity that authorized the request.""" _cognito_identity_id: str diff --git a/aws_lambda_powertools/utilities/typing/lambda_context.py b/aws_lambda_powertools/utilities/typing/lambda_context.py index 3ee8739f710..e3ea837d4d5 100644 --- a/aws_lambda_powertools/utilities/typing/lambda_context.py +++ b/aws_lambda_powertools/utilities/typing/lambda_context.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from __future__ import annotations from typing import TYPE_CHECKING @@ -12,7 +11,7 @@ ) -class LambdaContext(object): +class LambdaContext: """The LambdaContext static object can be used to ease the development by providing the IDE type hints. Example diff --git a/docs/utilities/batch.md b/docs/utilities/batch.md index 56dd74bf110..491773e392c 100644 --- a/docs/utilities/batch.md +++ b/docs/utilities/batch.md @@ -502,7 +502,7 @@ Use the context manager to access a list of all returned values from your `recor === "Accessing raw processed messages" - ```python hl_lines="29-36" + ```python hl_lines="28-35" --8<-- "examples/batch_processing/src/context_manager_access.py" ``` diff --git a/examples/batch_processing/src/context_manager_access.py b/examples/batch_processing/src/context_manager_access.py index dea3f881a48..c70b005e81e 100644 --- a/examples/batch_processing/src/context_manager_access.py +++ b/examples/batch_processing/src/context_manager_access.py @@ -1,7 +1,6 @@ from __future__ import annotations import json -from typing import List, Tuple from typing_extensions import Literal @@ -28,7 +27,7 @@ def record_handler(record: SQSRecord): def lambda_handler(event, context: LambdaContext): batch = event["Records"] # (1)! with processor(records=batch, handler=record_handler): - processed_messages: List[Tuple] = processor.process() + processed_messages: list[tuple] = processor.process() for message in processed_messages: status: Literal["success", "fail"] = message[0] diff --git a/examples/idempotency/src/bring_your_own_persistent_store.py b/examples/idempotency/src/bring_your_own_persistent_store.py index 1619f73f5c2..83ab27b8c4e 100644 --- a/examples/idempotency/src/bring_your_own_persistent_store.py +++ b/examples/idempotency/src/bring_your_own_persistent_store.py @@ -36,7 +36,7 @@ def __init__( self.status_attr = status_attr self.data_attr = data_attr self.validation_key_attr = validation_key_attr - super(MyOwnPersistenceLayer, self).__init__() + super().__init__() def _item_to_data_record(self, item: Dict[str, Any]) -> DataRecord: """ diff --git a/ruff.toml b/ruff.toml index 264870c35df..2207ea982f1 100644 --- a/ruff.toml +++ b/ruff.toml @@ -23,7 +23,9 @@ lint.select = [ "Q", # flake8-quotes - https://beta.ruff.rs/docs/rules/#flake8-quotes-q "PTH", # flake8-use-pathlib - https://beta.ruff.rs/docs/rules/#flake8-use-pathlib-pth "T10", # flake8-debugger https://beta.ruff.rs/docs/rules/#flake8-debugger-t10 + "TCH", # flake8-type-checking - https://docs.astral.sh/ruff/rules/#flake8-type-checking-tch "TD", # flake8-todo - https://beta.ruff.rs/docs/rules/#flake8-todos-td + "UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up "W", # pycodestyle warning - https://beta.ruff.rs/docs/rules/#warning-w ] @@ -36,7 +38,6 @@ lint.ignore = [ "B904", # raise-without-from-inside-except - disabled temporarily "PLC1901", # Compare-to-empty-string - disabled temporarily "PYI024", - "FA100", # Enable this rule when drop support to Python 3.7 ] # Exclude files and directories @@ -58,6 +59,7 @@ exclude = [ # Maximum line length line-length = 120 +target-version = "py38" fix = true lint.fixable = ["I", "COM812", "W"] @@ -81,6 +83,9 @@ max-statements = 70 [lint.isort] split-on-trailing-comma = true +[lint.flake8-type-checking] +runtime-evaluated-base-classes = ["pydantic.BaseModel"] + [lint.per-file-ignores] # Ignore specific rules for specific files "tests/e2e/utils/data_builder/__init__.py" = ["F401"] @@ -90,6 +95,6 @@ split-on-trailing-comma = true "aws_lambda_powertools/event_handler/openapi/compat.py" = ["F401"] # Maintenance: we're keeping EphemeralMetrics code in case of Hyrum's law so we can quickly revert it "aws_lambda_powertools/metrics/metrics.py" = ["ERA001"] -"examples/*" = ["FA100"] -"tests/*" = ["FA100"] +"examples/*" = ["FA100", "TCH"] +"tests/*" = ["FA100", "TCH"] "aws_lambda_powertools/utilities/parser/models/*" = ["FA100"] \ No newline at end of file diff --git a/tests/e2e/parser/handlers/handler_with_union_tag.py b/tests/e2e/parser/handlers/handler_with_union_tag.py index 5240a902db0..e2013251d8f 100644 --- a/tests/e2e/parser/handlers/handler_with_union_tag.py +++ b/tests/e2e/parser/handlers/handler_with_union_tag.py @@ -1,5 +1,3 @@ -from __future__ import annotations - from typing import Literal, Union from pydantic import BaseModel, Field diff --git a/tests/functional/data_masking/test_aws_encryption_sdk.py b/tests/functional/data_masking/test_aws_encryption_sdk.py index c1dfd22c6b9..63aca871e44 100644 --- a/tests/functional/data_masking/test_aws_encryption_sdk.py +++ b/tests/functional/data_masking/test_aws_encryption_sdk.py @@ -1,9 +1,7 @@ -from __future__ import annotations - import base64 import functools import json -from typing import Any, Callable +from typing import Any, Callable, Union import pytest from aws_encryption_sdk.identifiers import Algorithm @@ -24,7 +22,7 @@ def __init__( ) -> None: super().__init__(json_serializer, json_deserializer) - def encrypt(self, data: bytes | str, **kwargs) -> str: + def encrypt(self, data: Union[bytes, str], **kwargs) -> str: encoded_data: str = self.json_serializer(data) ciphertext = base64.b64encode(encoded_data.encode("utf-8")).decode() return ciphertext diff --git a/tests/functional/event_handler/test_openapi_serialization.py b/tests/functional/event_handler/test_openapi_serialization.py index 91e345260e8..7d70488c021 100644 --- a/tests/functional/event_handler/test_openapi_serialization.py +++ b/tests/functional/event_handler/test_openapi_serialization.py @@ -48,7 +48,7 @@ def serializer(_): app = APIGatewayRestResolver(enable_validation=True, serializer=serializer) # GIVEN a custom class - class CustomClass(object): + class CustomClass: __slots__ = [] # GIVEN a handler that returns an instance of that class diff --git a/tests/functional/idempotency/persistence/test_redis_layer.py b/tests/functional/idempotency/persistence/test_redis_layer.py index 13df84b559a..b2cec340ed2 100644 --- a/tests/functional/idempotency/persistence/test_redis_layer.py +++ b/tests/functional/idempotency/persistence/test_redis_layer.py @@ -100,7 +100,7 @@ def __init__(self, cache: dict = None, mock_latency_ms: int = 0, **kwargs): self.closed = False self.mock_latency_ms = mock_latency_ms self.nx_lock = Lock() - super(MockRedis, self).__init__() + super().__init__() # check_closed is called before every mock redis operation def check_closed(self): diff --git a/tests/functional/idempotency/test_idempotency.py b/tests/functional/idempotency/test_idempotency.py index 4ad179bcb1d..c499d3af7a8 100644 --- a/tests/functional/idempotency/test_idempotency.py +++ b/tests/functional/idempotency/test_idempotency.py @@ -1179,7 +1179,7 @@ def handler(event, context): class MockPersistenceLayer(BasePersistenceLayer): def __init__(self, expected_idempotency_key: str): self.expected_idempotency_key = expected_idempotency_key - super(MockPersistenceLayer, self).__init__() + super().__init__() def _put_record(self, data_record: DataRecord) -> None: assert data_record.idempotency_key == self.expected_idempotency_key diff --git a/tests/functional/idempotency/utils.py b/tests/functional/idempotency/utils.py index c396e40957c..4efaee624b5 100644 --- a/tests/functional/idempotency/utils.py +++ b/tests/functional/idempotency/utils.py @@ -1,8 +1,6 @@ -from __future__ import annotations - import hashlib import json -from typing import Any, Dict +from typing import Any, Dict, Optional from botocore import stub from pytest import FixtureRequest @@ -90,7 +88,7 @@ def build_idempotency_put_item_response_stub( expiration: int, status: str, request: FixtureRequest, - validation_data: Any | None, + validation_data: Optional[Any], ): response = { "Item": { diff --git a/tests/functional/metrics/test_metrics_cloudwatch_emf.py b/tests/functional/metrics/test_metrics_cloudwatch_emf.py index a3dfa518400..c09660b4f9a 100644 --- a/tests/functional/metrics/test_metrics_cloudwatch_emf.py +++ b/tests/functional/metrics/test_metrics_cloudwatch_emf.py @@ -1,10 +1,8 @@ -from __future__ import annotations - import datetime import json import warnings from collections import namedtuple -from typing import Dict, List +from typing import Dict, List, Optional, Union import pytest @@ -34,7 +32,7 @@ def serialize_metrics( metrics: List[Dict], dimensions: List[Dict], namespace: str, - metadatas: List[Dict] | None = None, + metadatas: Optional[List[Dict]] = None, ) -> CloudWatchEMFOutput: """Helper function to build EMF object from a list of metrics, dimensions""" my_metrics = AmazonCloudWatchEMFProvider(namespace=namespace) @@ -56,8 +54,8 @@ def serialize_single_metric( metric: Dict, dimension: Dict, namespace: str, - metadata: Dict | None = None, - timestamp: int | datetime.datetime | None = None, + metadata: Optional[Dict] = None, + timestamp: Union[int, datetime.datetime, None] = None, ) -> CloudWatchEMFOutput: """Helper function to build EMF object from a given metric, dimension and namespace""" my_metrics = AmazonCloudWatchEMFProvider(namespace=namespace) diff --git a/tests/functional/metrics/test_metrics_provider.py b/tests/functional/metrics/test_metrics_provider.py index c9b627c1709..e5ff08f3e96 100644 --- a/tests/functional/metrics/test_metrics_provider.py +++ b/tests/functional/metrics/test_metrics_provider.py @@ -1,5 +1,3 @@ -from __future__ import annotations - import json from typing import Any, List diff --git a/tests/functional/parser/test_parser.py b/tests/functional/parser/test_parser.py index 6b34d9d664a..15ac834256b 100644 --- a/tests/functional/parser/test_parser.py +++ b/tests/functional/parser/test_parser.py @@ -12,7 +12,7 @@ from aws_lambda_powertools.utilities.typing import LambdaContext -@pytest.mark.parametrize("invalid_value", [None, bool(), [], (), object]) +@pytest.mark.parametrize("invalid_value", [None, False, [], (), object]) def test_parser_unsupported_event(dummy_schema, invalid_value): @event_parser(model=dummy_schema) def handle_no_envelope(event: Dict, _: LambdaContext): @@ -75,7 +75,7 @@ def validate_field(cls, value): assert event_parsed.version == int(event_raw["version"]) -@pytest.mark.parametrize("invalid_schema", [str, bool(), [], ()]) +@pytest.mark.parametrize("invalid_schema", [str, False, [], ()]) def test_parser_with_invalid_schema_type(dummy_event, invalid_schema): @event_parser(model=invalid_schema) def handle_no_envelope(event: Dict, _: LambdaContext): diff --git a/tests/functional/test_logger_powertools_formatter.py b/tests/functional/test_logger_powertools_formatter.py index b9113485a47..fe47e72d596 100644 --- a/tests/functional/test_logger_powertools_formatter.py +++ b/tests/functional/test_logger_powertools_formatter.py @@ -257,7 +257,7 @@ def test_log_dict_xray_is_updated_when_tracing_id_changes(stdout, monkeypatch, s logger.info("foo bar") - log_dict, log_dict_2 = [json.loads(line.strip()) for line in stdout.getvalue().split("\n") if line] + log_dict, log_dict_2 = (json.loads(line.strip()) for line in stdout.getvalue().split("\n") if line) # THEN `xray_trace_id`` key should be different in both invocations assert log_dict["xray_trace_id"] == trace_id diff --git a/tests/functional/test_utilities_parameters.py b/tests/functional/test_utilities_parameters.py index 22d24f9a058..fc4d869472e 100644 --- a/tests/functional/test_utilities_parameters.py +++ b/tests/functional/test_utilities_parameters.py @@ -1,5 +1,3 @@ -from __future__ import annotations - import base64 import json import random @@ -7,7 +5,7 @@ import uuid from datetime import datetime, timedelta from io import BytesIO -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Optional, Tuple, Union import boto3 import pytest @@ -53,7 +51,10 @@ def mock_binary_value() -> str: return "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lhV0YwSWpveE5URTJNak01TURJeWZRLlNmbEt4d1JKU01lS0tGMlFUNGZ3cE1lSmYzNlBPazZ5SlZfYWRRc3N3NWMK" # noqa: E501 -def build_get_parameters_stub(params: Dict[str, Any], invalid_parameters: List[str] | None = None) -> Dict[str, List]: +def build_get_parameters_stub( + params: Dict[str, Any], + invalid_parameters: Optional[List[str]] = None, +) -> Dict[str, List]: invalid_parameters = invalid_parameters or [] version = random.randrange(1, 1000) return { @@ -2217,7 +2218,7 @@ class TestProvider(SSMProvider): def __init__(self, boto_config: Config = config, **kwargs): super().__init__(boto_config=boto_config, **kwargs) - def get_parameters_by_name(self, *args, **kwargs) -> Dict[str, str] | Dict[str, bytes] | Dict[str, dict]: + def get_parameters_by_name(self, *args, **kwargs) -> Union[Dict[str, str], Dict[str, bytes], Dict[str, dict]]: return {mock_name: mock_value} monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "ssm", TestProvider()) @@ -2453,7 +2454,7 @@ class TestProvider(SSMProvider): def __init__(self, boto_config: Config = config, **kwargs): super().__init__(boto_config=boto_config, **kwargs) - def get_parameters_by_name(self, *args, **kwargs) -> Dict[str, str] | Dict[str, bytes] | Dict[str, dict]: + def get_parameters_by_name(self, *args, **kwargs) -> Union[Dict[str, str], Dict[str, bytes], Dict[str, dict]]: return {mock_name: mock_value} monkeypatch.setattr(parameters.ssm, "DEFAULT_PROVIDERS", {}) diff --git a/tests/functional/validator/test_validator.py b/tests/functional/validator/test_validator.py index 23b4943223a..ab465288430 100644 --- a/tests/functional/validator/test_validator.py +++ b/tests/functional/validator/test_validator.py @@ -69,7 +69,7 @@ def test_validate_accept_schema_custom_format( ) -@pytest.mark.parametrize("invalid_format", [None, bool(), {}, [], object]) +@pytest.mark.parametrize("invalid_format", [None, False, {}, [], object]) def test_validate_invalid_custom_format( eventbridge_schema_registry_cloudtrail_v2_s3, eventbridge_cloudtrail_s3_head_object_event, diff --git a/tests/unit/parser/test_vpc_latticev2.py b/tests/unit/parser/test_vpc_latticev2.py index 78d93fde041..d0cb8d1d7d8 100644 --- a/tests/unit/parser/test_vpc_latticev2.py +++ b/tests/unit/parser/test_vpc_latticev2.py @@ -34,7 +34,7 @@ def test_vpc_lattice_v2_event(): assert model.request_context.service_arn == raw_event["requestContext"]["serviceArn"] assert model.request_context.target_group_arn == raw_event["requestContext"]["targetGroupArn"] assert model.request_context.time_epoch == float(raw_event["requestContext"]["timeEpoch"]) - convert_time = int((model.request_context.time_epoch_as_datetime.timestamp() * 1000)) + convert_time = int(model.request_context.time_epoch_as_datetime.timestamp() * 1000) event_converted_time = round(int(raw_event["requestContext"]["timeEpoch"]) / 1000) assert convert_time == event_converted_time assert model.request_context.identity.source_vpc_arn == raw_event["requestContext"]["identity"]["sourceVpcArn"] diff --git a/tests/unit/test_tracing.py b/tests/unit/test_tracing.py index 0d12afa629b..209533bfab4 100644 --- a/tests/unit/test_tracing.py +++ b/tests/unit/test_tracing.py @@ -447,7 +447,7 @@ def test_tracer_yield_from_nested_context_manager(mocker, provider_stub, in_subs tracer = Tracer(provider=provider, service="booking") # WHEN capture_method decorator is used on a context manager nesting another context manager - class NestedContextManager(object): + class NestedContextManager: def __enter__(self): self._value = {"result": "test result"} return self._value From 203a4b50d5e4b0cf7d108c0fcccb2ad06e106cf8 Mon Sep 17 00:00:00 2001 From: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Date: Mon, 19 Aug 2024 06:51:34 -0500 Subject: [PATCH 2/2] Fix missing ruff error TCH002 from data_classes --- .../utilities/data_classes/kinesis_firehose_event.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py b/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py index 720bfa89eee..85e75e198f6 100644 --- a/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py +++ b/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py @@ -5,12 +5,13 @@ import warnings from dataclasses import dataclass, field from functools import cached_property -from typing import Any, Callable, ClassVar, Iterator - -from typing_extensions import Literal +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterator from aws_lambda_powertools.utilities.data_classes.common import DictWrapper +if TYPE_CHECKING: + from typing_extensions import Literal + @dataclass(repr=False, order=False, frozen=True) class KinesisFirehoseDataTransformationRecordMetadata: