From 11ecae241946496702b73139f2167b3bc6dea7d5 Mon Sep 17 00:00:00 2001 From: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Date: Mon, 12 Aug 2024 19:14:53 -0500 Subject: [PATCH 1/3] refactor(logging): add from __future__ import annotations and update code according to ruff rules TCH, UP006, UP007, UP037 and FA100. --- aws_lambda_powertools/logging/formatter.py | 36 ++++--- .../logging/formatters/datadog.py | 8 +- aws_lambda_powertools/logging/logger.py | 100 +++++++++--------- aws_lambda_powertools/logging/types.py | 15 +-- aws_lambda_powertools/logging/utils.py | 31 +++--- 5 files changed, 98 insertions(+), 92 deletions(-) diff --git a/aws_lambda_powertools/logging/formatter.py b/aws_lambda_powertools/logging/formatter.py index ac623303ab1..48797f51e2a 100644 --- a/aws_lambda_powertools/logging/formatter.py +++ b/aws_lambda_powertools/logging/formatter.py @@ -9,12 +9,14 @@ from abc import ABCMeta, abstractmethod from datetime import datetime, timezone from functools import partial -from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, Callable, Iterable -from aws_lambda_powertools.logging.types import LogRecord, LogStackTrace from aws_lambda_powertools.shared import constants from aws_lambda_powertools.shared.functions import powertools_dev_is_set +if TYPE_CHECKING: + from aws_lambda_powertools.logging.types import LogRecord, LogStackTrace + RESERVED_LOG_ATTRS = ( "name", "msg", @@ -48,7 +50,7 @@ class BasePowertoolsFormatter(logging.Formatter, metaclass=ABCMeta): def append_keys(self, **additional_keys) -> None: raise NotImplementedError() - def get_current_keys(self) -> Dict[str, Any]: + def get_current_keys(self) -> dict[str, Any]: return {} def remove_keys(self, keys: Iterable[str]) -> None: @@ -74,11 +76,11 @@ class LambdaPowertoolsFormatter(BasePowertoolsFormatter): def __init__( self, json_serializer: Callable[[LogRecord], str] | None = None, - json_deserializer: Callable[[Dict | str | bool | int | float], str] | None = None, + json_deserializer: Callable[[dict | str | bool | int | float], str] | None = None, json_default: Callable[[Any], Any] | None = None, datefmt: str | None = None, use_datetime_directive: bool = False, - log_record_order: List[str] | None = None, + log_record_order: list[str] | None = None, utc: bool = False, use_rfc3339: bool = False, serialize_stacktrace: bool = True, @@ -182,7 +184,7 @@ def format(self, record: logging.LogRecord) -> str: # noqa: A003 return self.serialize(log=formatted_log) - def formatTime(self, record: logging.LogRecord, datefmt: Optional[str] = None) -> str: + def formatTime(self, record: logging.LogRecord, datefmt: str | None = None) -> str: # As of Py3.7, we can infer milliseconds directly from any datetime # saving processing time as we can shortcircuit early # Maintenance: In V3, we (and Java) should move to this format by default @@ -234,7 +236,7 @@ def formatTime(self, record: logging.LogRecord, datefmt: Optional[str] = None) - def append_keys(self, **additional_keys) -> None: self.log_format.update(additional_keys) - def get_current_keys(self) -> Dict[str, Any]: + def get_current_keys(self) -> dict[str, Any]: return self.log_format def remove_keys(self, keys: Iterable[str]) -> None: @@ -246,14 +248,14 @@ def clear_state(self) -> None: self.log_format.update(**self.keys_combined) @staticmethod - def _build_default_keys() -> Dict[str, str]: + def _build_default_keys() -> dict[str, str]: return { "level": "%(levelname)s", "location": "%(funcName)s:%(lineno)d", "timestamp": "%(asctime)s", } - def _get_latest_trace_id(self) -> Optional[str]: + def _get_latest_trace_id(self) -> str | None: xray_trace_id_key = self.log_format.get("xray_trace_id", "") if xray_trace_id_key is None: # key is explicitly disabled; ignore it. e.g., Logger(xray_trace_id=None) @@ -262,7 +264,7 @@ def _get_latest_trace_id(self) -> Optional[str]: xray_trace_id = os.getenv(constants.XRAY_TRACE_ID_ENV) return xray_trace_id.split(";")[0].replace("Root=", "") if xray_trace_id else None - def _extract_log_message(self, log_record: logging.LogRecord) -> Union[Dict[str, Any], str, bool, Iterable]: + def _extract_log_message(self, log_record: logging.LogRecord) -> dict[str, Any] | str | bool | Iterable: """Extract message from log record and attempt to JSON decode it if str Parameters @@ -272,7 +274,7 @@ def _extract_log_message(self, log_record: logging.LogRecord) -> Union[Dict[str, Returns ------- - message: Union[Dict, str, bool, Iterable] + message: dict[str, Any] | str | bool | Iterable Extracted message """ message = log_record.msg @@ -308,7 +310,7 @@ def _serialize_stacktrace(self, log_record: logging.LogRecord) -> LogStackTrace return None - def _extract_log_exception(self, log_record: logging.LogRecord) -> Union[Tuple[str, str], Tuple[None, None]]: + def _extract_log_exception(self, log_record: logging.LogRecord) -> tuple[str, str] | tuple[None, None]: """Format traceback information, if available Parameters @@ -318,7 +320,7 @@ def _extract_log_exception(self, log_record: logging.LogRecord) -> Union[Tuple[s Returns ------- - log_record: Optional[Tuple[str, str]] + log_record: tuple[str, str] | tuple[None, None] Log record with constant traceback info and exception name """ if log_record.exc_info: @@ -326,7 +328,7 @@ def _extract_log_exception(self, log_record: logging.LogRecord) -> Union[Tuple[s return None, None - def _extract_log_keys(self, log_record: logging.LogRecord) -> Dict[str, Any]: + def _extract_log_keys(self, log_record: logging.LogRecord) -> dict[str, Any]: """Extract and parse custom and reserved log keys Parameters @@ -336,7 +338,7 @@ def _extract_log_keys(self, log_record: logging.LogRecord) -> Dict[str, Any]: Returns ------- - formatted_log: Dict + formatted_log: dict[str, Any] Structured log as dictionary """ record_dict = log_record.__dict__.copy() @@ -358,7 +360,7 @@ def _extract_log_keys(self, log_record: logging.LogRecord) -> Dict[str, Any]: return formatted_log @staticmethod - def _strip_none_records(records: Dict[str, Any]) -> Dict[str, Any]: + def _strip_none_records(records: dict[str, Any]) -> dict[str, Any]: """Remove any key with None as value""" return {k: v for k, v in records.items() if v is not None} @@ -367,4 +369,4 @@ def _strip_none_records(records: Dict[str, Any]) -> Dict[str, Any]: # Fetch current and future parameters from PowertoolsFormatter that should be reserved -RESERVED_FORMATTER_CUSTOM_KEYS: List[str] = inspect.getfullargspec(LambdaPowertoolsFormatter).args[1:] +RESERVED_FORMATTER_CUSTOM_KEYS: list[str] = inspect.getfullargspec(LambdaPowertoolsFormatter).args[1:] diff --git a/aws_lambda_powertools/logging/formatters/datadog.py b/aws_lambda_powertools/logging/formatters/datadog.py index 15218302250..4f140d93683 100644 --- a/aws_lambda_powertools/logging/formatters/datadog.py +++ b/aws_lambda_powertools/logging/formatters/datadog.py @@ -1,16 +1,18 @@ from __future__ import annotations -from typing import Any, Callable, Dict +from typing import TYPE_CHECKING, Any, Callable from aws_lambda_powertools.logging.formatter import LambdaPowertoolsFormatter -from aws_lambda_powertools.logging.types import LogRecord + +if TYPE_CHECKING: + from aws_lambda_powertools.logging.types import LogRecord class DatadogLogFormatter(LambdaPowertoolsFormatter): def __init__( self, json_serializer: Callable[[LogRecord], str] | None = None, - json_deserializer: Callable[[Dict | str | bool | int | float], str] | None = None, + json_deserializer: Callable[[dict | str | bool | int | float], str] | None = None, json_default: Callable[[Any], Any] | None = None, datefmt: str | None = None, use_datetime_directive: bool = False, diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index 4d9691ab792..8dff22eecd7 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -12,13 +12,9 @@ TYPE_CHECKING, Any, Callable, - Dict, Iterable, - List, Mapping, - Optional, TypeVar, - Union, overload, ) @@ -33,7 +29,6 @@ ) from aws_lambda_powertools.utilities import jmespath_utils -from ..shared.types import AnyCallableT from .exceptions import InvalidLoggerSamplingRateError from .filters import SuppressFilter from .formatter import ( @@ -43,6 +38,9 @@ ) from .lambda_context import build_lambda_context_model +if TYPE_CHECKING: + from aws_lambda_powertools.shared.types import AnyCallableT + logger = logging.getLogger(__name__) is_cold_start = True @@ -206,20 +204,20 @@ class Logger: def __init__( self, - service: Optional[str] = None, - level: Union[str, int, None] = None, + service: str | None = None, + level: str | int | None = None, child: bool = False, - sampling_rate: Optional[float] = None, - stream: Optional[IO[str]] = None, - logger_formatter: Optional[PowertoolsFormatter] = None, - logger_handler: Optional[logging.Handler] = None, + sampling_rate: float | None = None, + stream: IO[str] | None = None, + logger_formatter: PowertoolsFormatter | None = None, + logger_handler: logging.Handler | None = None, log_uncaught_exceptions: bool = False, - json_serializer: Optional[Callable[[Dict], str]] = None, - json_deserializer: Optional[Callable[[Union[Dict, str, bool, int, float]], str]] = None, - json_default: Optional[Callable[[Any], Any]] = None, - datefmt: Optional[str] = None, + json_serializer: Callable[[dict], str] | None = None, + json_deserializer: Callable[[dict | str | bool | int | float], str] | None = None, + json_default: Callable[[Any], Any] | None = None, + datefmt: str | None = None, use_datetime_directive: bool = False, - log_record_order: Optional[List[str]] = None, + log_record_order: list[str] | None = None, utc: bool = False, use_rfc3339: bool = False, serialize_stacktrace: bool = True, @@ -284,8 +282,8 @@ def _get_logger(self) -> logging.Logger: def _init_logger( self, - formatter_options: Optional[Dict] = None, - log_level: Union[str, int, None] = None, + formatter_options: dict | None = None, + log_level: str | int | None = None, **kwargs, ) -> None: """Configures new logger""" @@ -345,26 +343,26 @@ def _configure_sampling(self) -> None: def inject_lambda_context( self, lambda_handler: AnyCallableT, - log_event: Optional[bool] = None, - correlation_id_path: Optional[str] = None, - clear_state: Optional[bool] = False, + log_event: bool | None = None, + correlation_id_path: str | None = None, + clear_state: bool | None = False, ) -> AnyCallableT: ... @overload def inject_lambda_context( self, lambda_handler: None = None, - log_event: Optional[bool] = None, - correlation_id_path: Optional[str] = None, - clear_state: Optional[bool] = False, + log_event: bool | None = None, + correlation_id_path: str | None = None, + clear_state: bool | None = False, ) -> Callable[[AnyCallableT], AnyCallableT]: ... def inject_lambda_context( self, - lambda_handler: Optional[AnyCallableT] = None, - log_event: Optional[bool] = None, - correlation_id_path: Optional[str] = None, - clear_state: Optional[bool] = False, + lambda_handler: AnyCallableT | None = None, + log_event: bool | None = None, + correlation_id_path: str | None = None, + clear_state: bool | None = False, ) -> Any: """Decorator to capture Lambda contextual info and inject into logger @@ -458,7 +456,7 @@ def info( exc_info: logging._ExcInfoType = None, stack_info: bool = False, stacklevel: int = 2, - extra: Optional[Mapping[str, object]] = None, + extra: Mapping[str, object] | None = None, **kwargs: object, ) -> None: extra = extra or {} @@ -480,7 +478,7 @@ def error( exc_info: logging._ExcInfoType = None, stack_info: bool = False, stacklevel: int = 2, - extra: Optional[Mapping[str, object]] = None, + extra: Mapping[str, object] | None = None, **kwargs: object, ) -> None: extra = extra or {} @@ -502,7 +500,7 @@ def exception( exc_info: logging._ExcInfoType = True, stack_info: bool = False, stacklevel: int = 2, - extra: Optional[Mapping[str, object]] = None, + extra: Mapping[str, object] | None = None, **kwargs: object, ) -> None: extra = extra or {} @@ -524,7 +522,7 @@ def critical( exc_info: logging._ExcInfoType = None, stack_info: bool = False, stacklevel: int = 2, - extra: Optional[Mapping[str, object]] = None, + extra: Mapping[str, object] | None = None, **kwargs: object, ) -> None: extra = extra or {} @@ -546,7 +544,7 @@ def warning( exc_info: logging._ExcInfoType = None, stack_info: bool = False, stacklevel: int = 2, - extra: Optional[Mapping[str, object]] = None, + extra: Mapping[str, object] | None = None, **kwargs: object, ) -> None: extra = extra or {} @@ -568,7 +566,7 @@ def debug( exc_info: logging._ExcInfoType = None, stack_info: bool = False, stacklevel: int = 2, - extra: Optional[Mapping[str, object]] = None, + extra: Mapping[str, object] | None = None, **kwargs: object, ) -> None: extra = extra or {} @@ -586,13 +584,13 @@ def debug( def append_keys(self, **additional_keys: object) -> None: self.registered_formatter.append_keys(**additional_keys) - def get_current_keys(self) -> Dict[str, Any]: + def get_current_keys(self) -> dict[str, Any]: return self.registered_formatter.get_current_keys() def remove_keys(self, keys: Iterable[str]) -> None: self.registered_formatter.remove_keys(keys) - def structure_logs(self, append: bool = False, formatter_options: Optional[Dict] = None, **keys) -> None: + def structure_logs(self, append: bool = False, formatter_options: dict | None = None, **keys) -> None: """Sets logging formatting to JSON. Optionally, it can append keyword arguments @@ -638,7 +636,7 @@ def structure_logs(self, append: bool = False, formatter_options: Optional[Dict] self.registered_formatter.clear_state() self.registered_formatter.append_keys(**log_keys) - def set_correlation_id(self, value: Optional[str]) -> None: + def set_correlation_id(self, value: str | None) -> None: """Sets the correlation_id in the logging json Parameters @@ -648,7 +646,7 @@ def set_correlation_id(self, value: Optional[str]) -> None: """ self.append_keys(correlation_id=value) - def get_correlation_id(self) -> Optional[str]: + def get_correlation_id(self) -> str | None: """Gets the correlation_id in the logging json Returns @@ -660,7 +658,7 @@ def get_correlation_id(self) -> Optional[str]: return self.registered_formatter.log_format.get("correlation_id") return None - def setLevel(self, level: Union[str, int, None]) -> None: + def setLevel(self, level: str | int | None) -> None: return self._logger.setLevel(self._determine_log_level(level)) def addHandler(self, handler: logging.Handler) -> None: @@ -694,7 +692,7 @@ def name(self) -> str: return self._logger.name @property - def handlers(self) -> List[logging.Handler]: + def handlers(self) -> list[logging.Handler]: """List of registered logging handlers Notes @@ -704,22 +702,22 @@ def handlers(self) -> List[logging.Handler]: """ return self._logger.handlers - def _get_aws_lambda_log_level(self) -> Optional[str]: + def _get_aws_lambda_log_level(self) -> str | None: """ Retrieve the log level for AWS Lambda from the Advanced Logging Controls feature. Returns: - Optional[str]: The corresponding logging level. + str | None: The corresponding logging level. """ return constants.LAMBDA_ADVANCED_LOGGING_LEVELS.get(os.getenv(constants.LAMBDA_LOG_LEVEL_ENV)) - def _get_powertools_log_level(self, level: Union[str, int, None]) -> Optional[str]: + def _get_powertools_log_level(self, level: str | int | None) -> str | None: """Retrieve the log level for Powertools from the environment variable or level parameter. If log level is an integer, we convert to its respective string level `logging.getLevelName()`. If no log level is provided, we check env vars for the log level: POWERTOOLS_LOG_LEVEL_ENV and POWERTOOLS_LOG_LEVEL_LEGACY_ENV. Parameters: ----------- - level : Union[str, int, None] + level : str | int | None The specified log level as a string, integer, or None. Environment variables --------------------- @@ -729,7 +727,7 @@ def _get_powertools_log_level(self, level: Union[str, int, None]) -> Optional[st log level (e.g: INFO, DEBUG, WARNING, ERROR, CRITICAL) Returns: -------- - Optional[str]: + str | None: The corresponding logging level. Returns None if the log level is not explicitly specified. """ # noqa E501 @@ -743,16 +741,16 @@ def _get_powertools_log_level(self, level: Union[str, int, None]) -> Optional[st return level or log_level_env - def _determine_log_level(self, level: Union[str, int, None]) -> Union[str, int]: + def _determine_log_level(self, level: str | int | None) -> str | int: """Determine the effective log level considering Lambda and Powertools preferences. It emits an UserWarning if Lambda ALC log level is lower than Logger log level. Parameters: ----------- - level: Union[str, int, None] + level: str | int | None The specified log level as a string, integer, or None. Returns: ---------- - Union[str, int]: The effective logging level. + str | int: The effective logging level. """ # This function consider the following order of precedence: @@ -789,9 +787,9 @@ def _determine_log_level(self, level: Union[str, int, None]) -> Union[str, int]: def set_package_logger( - level: Union[str, int] = logging.DEBUG, - stream: Optional[IO[str]] = None, - formatter: Optional[logging.Formatter] = None, + level: str | int = logging.DEBUG, + stream: IO[str] | None = None, + formatter: logging.Formatter | None = None, ) -> None: """Set an additional stream handler, formatter, and log level for aws_lambda_powertools package logger. diff --git a/aws_lambda_powertools/logging/types.py b/aws_lambda_powertools/logging/types.py index fcfec998ac2..07b44aa9eed 100644 --- a/aws_lambda_powertools/logging/types.py +++ b/aws_lambda_powertools/logging/types.py @@ -1,18 +1,15 @@ from __future__ import annotations -from typing import Any, Dict, List, TypedDict, Union +from typing import Any, TypedDict from typing_extensions import NotRequired, TypeAlias -LogRecord: TypeAlias = Union[Dict[str, Any], "PowertoolsLogRecord"] -LogStackTrace: TypeAlias = Union[Dict[str, Any], "PowertoolsStackTrace"] - class PowertoolsLogRecord(TypedDict): # Base fields (required) level: str location: str - message: Dict[str, Any] | str | bool | List[Any] + message: dict[str, Any] | str | bool | list[Any] timestamp: str | int service: str @@ -34,11 +31,15 @@ class PowertoolsLogRecord(TypedDict): # Fields from logger.exception exception_name: NotRequired[str] exception: NotRequired[str] - stack_trace: NotRequired[Dict[str, Any]] + stack_trace: NotRequired[dict[str, Any]] class PowertoolsStackTrace(TypedDict): type: str value: str module: str - frames: List[Dict[str, Any]] + frames: list[dict[str, Any]] + + +LogRecord: TypeAlias = dict[str, Any] | PowertoolsLogRecord +LogStackTrace: TypeAlias = dict[str, Any] | PowertoolsStackTrace diff --git a/aws_lambda_powertools/logging/utils.py b/aws_lambda_powertools/logging/utils.py index 3e1c3c69aed..470328559b7 100644 --- a/aws_lambda_powertools/logging/utils.py +++ b/aws_lambda_powertools/logging/utils.py @@ -1,17 +1,20 @@ +from __future__ import annotations + import logging -from typing import Callable, List, Optional, Set, Union +from typing import TYPE_CHECKING, Callable -from .logger import Logger +if TYPE_CHECKING: + from aws_lambda_powertools.logging.logger import Logger PACKAGE_LOGGER = "aws_lambda_powertools" def copy_config_to_registered_loggers( source_logger: Logger, - log_level: Optional[Union[int, str]] = None, + log_level: int | str | None = None, ignore_log_level=False, - exclude: Optional[Set[str]] = None, - include: Optional[Set[str]] = None, + exclude: set[str] | None = None, + include: set[str] | None = None, ) -> None: """Copies source Logger level and handler to all registered loggers for consistent formatting. @@ -20,13 +23,13 @@ def copy_config_to_registered_loggers( ignore_log_level source_logger : Logger Powertools for AWS Lambda (Python) Logger to copy configuration from - log_level : Union[int, str], optional + log_level : int | str, optional Logging level to set to registered loggers, by default uses source_logger logging level ignore_log_level: bool Whether to not touch log levels for discovered loggers. log_level param is disregarded when this is set. - include : Optional[Set[str]], optional + include : set[str] | None, optional List of logger names to include, by default all registered loggers are included - exclude : Optional[Set[str]], optional + exclude : set[str] | None, optional List of logger names to exclude, by default None """ level = log_level or source_logger.log_level @@ -61,11 +64,11 @@ def copy_config_to_registered_loggers( _configure_logger(source_logger=source_logger, logger=logger, level=level, ignore_log_level=ignore_log_level) -def _include_registered_loggers_filter(loggers: Set[str]): +def _include_registered_loggers_filter(loggers: set[str]): return [logging.getLogger(name) for name in logging.root.manager.loggerDict if "." not in name and name in loggers] -def _exclude_registered_loggers_filter(loggers: Set[str]) -> List[logging.Logger]: +def _exclude_registered_loggers_filter(loggers: set[str]) -> list[logging.Logger]: return [ logging.getLogger(name) for name in logging.root.manager.loggerDict if "." not in name and name not in loggers ] @@ -73,9 +76,9 @@ def _exclude_registered_loggers_filter(loggers: Set[str]) -> List[logging.Logger def _find_registered_loggers( source_logger: Logger, - loggers: Set[str], - filter_func: Callable[[Set[str]], List[logging.Logger]], -) -> List[logging.Logger]: + loggers: set[str], + filter_func: Callable[[set[str]], list[logging.Logger]], +) -> list[logging.Logger]: """Filter root loggers based on provided parameters.""" root_loggers = filter_func(loggers) source_logger.debug(f"Filtered root loggers: {root_loggers}") @@ -85,7 +88,7 @@ def _find_registered_loggers( def _configure_logger( source_logger: Logger, logger: logging.Logger, - level: Union[int, str], + level: int | str, ignore_log_level: bool = False, ) -> None: # customers may not want to copy the same log level from Logger to discovered loggers From 6ff58afa3b98e6b79cb4fab4f901fcf63c72276a Mon Sep 17 00:00:00 2001 From: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Date: Tue, 13 Aug 2024 10:18:50 -0500 Subject: [PATCH 2/3] Prefer absolute imports --- aws_lambda_powertools/logging/logger.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index 8dff22eecd7..75a14c6ea2b 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -21,6 +21,14 @@ from aws_lambda_powertools.logging.constants import ( LOGGER_ATTRIBUTE_PRECONFIGURED, ) +from aws_lambda_powertools.logging.exceptions import InvalidLoggerSamplingRateError +from aws_lambda_powertools.logging.filters import SuppressFilter +from aws_lambda_powertools.logging.formatter import ( + RESERVED_FORMATTER_CUSTOM_KEYS, + BasePowertoolsFormatter, + LambdaPowertoolsFormatter, +) +from aws_lambda_powertools.logging.lambda_context import build_lambda_context_model from aws_lambda_powertools.shared import constants from aws_lambda_powertools.shared.functions import ( extract_event_from_common_models, @@ -29,15 +37,6 @@ ) from aws_lambda_powertools.utilities import jmespath_utils -from .exceptions import InvalidLoggerSamplingRateError -from .filters import SuppressFilter -from .formatter import ( - RESERVED_FORMATTER_CUSTOM_KEYS, - BasePowertoolsFormatter, - LambdaPowertoolsFormatter, -) -from .lambda_context import build_lambda_context_model - if TYPE_CHECKING: from aws_lambda_powertools.shared.types import AnyCallableT From fa04ffa6c8f64c63b6502dadd4001500e87c7e2c Mon Sep 17 00:00:00 2001 From: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:16:20 -0500 Subject: [PATCH 3/3] Fix type alias with Python 3.8 See https://bugs.python.org/issue45117 --- aws_lambda_powertools/logging/types.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws_lambda_powertools/logging/types.py b/aws_lambda_powertools/logging/types.py index 07b44aa9eed..20f993a0a01 100644 --- a/aws_lambda_powertools/logging/types.py +++ b/aws_lambda_powertools/logging/types.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, TypedDict +from typing import Any, Dict, TypedDict, Union from typing_extensions import NotRequired, TypeAlias @@ -41,5 +41,5 @@ class PowertoolsStackTrace(TypedDict): frames: list[dict[str, Any]] -LogRecord: TypeAlias = dict[str, Any] | PowertoolsLogRecord -LogStackTrace: TypeAlias = dict[str, Any] | PowertoolsStackTrace +LogRecord: TypeAlias = Union[Dict[str, Any], PowertoolsLogRecord] +LogStackTrace: TypeAlias = Union[Dict[str, Any], PowertoolsStackTrace]