From 9eb525b22bd8564cd4ba0f9a27cdc6661e604e12 Mon Sep 17 00:00:00 2001 From: Mohammed Alkindi Date: Mon, 14 Sep 2026 17:03:13 +0400 Subject: [PATCH 1/2] fix(shared): keep LAMBDA_TASK_ROOT POSIX-shaped off Linux abs_lambda_path joined LAMBDA_TASK_ROOT with pathlib.Path, which is WindowsPath off Linux, so str(Path("/var/task", "")) returned "\var\task". The docstring promises the environment variable is used as given, and the repo's own test_abs_lambda_path_empty_envvar fails on an unmodified Windows checkout. CI is ubuntu-latest only, so it never surfaced there. The Lambda runtime is always Linux, so use PurePosixPath when LAMBDA_TASK_ROOT is set and keep the existing Path behaviour for the unset local case. Behaviour on Linux is unchanged. test_abs_lambda_path_w_filename_envvar built its expected value with the same platform-dependent Path call, so it passed either way and masked the bug; it now asserts the POSIX result directly. --- aws_lambda_powertools/shared/functions.py | 17 ++++++++++++----- tests/unit/test_shared_functions.py | 6 ++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/aws_lambda_powertools/shared/functions.py b/aws_lambda_powertools/shared/functions.py index b02f99d7665..0192786861b 100644 --- a/aws_lambda_powertools/shared/functions.py +++ b/aws_lambda_powertools/shared/functions.py @@ -7,7 +7,7 @@ import re import warnings from binascii import Error as BinAsciiError -from pathlib import Path +from pathlib import Path, PurePosixPath from typing import TYPE_CHECKING, Any, TypeGuard, overload from aws_lambda_powertools.shared import constants @@ -280,10 +280,17 @@ def abs_lambda_path(relative_path: str = "") -> str: Otherwise, it will use the current working directory. If the path is empty, it will return the current working directory. """ - # Retrieve the LAMBDA_TASK_ROOT environment variable or default to an empty string - current_working_directory = os.environ.get("LAMBDA_TASK_ROOT", "") or str(Path.cwd()) - - return str(Path(current_working_directory, relative_path)) + # The Lambda runtime is Linux, so LAMBDA_TASK_ROOT is always a POSIX path. Joining it with + # pathlib.Path rewrites it with the separators of whatever platform this code runs on, so a + # developer running the suite on Windows would get "\var\task" instead of "/var/task". + # PurePosixPath keeps the value the runtime gave us intact on every platform. + lambda_task_root = os.environ.get("LAMBDA_TASK_ROOT", "") + if lambda_task_root: + return str(PurePosixPath(lambda_task_root, relative_path)) + + # Off Lambda there is no task root, so fall back to the current working directory and let + # pathlib use the local platform's separators. + return str(Path(Path.cwd(), relative_path)) def sanitize_xray_segment_name(name: str) -> str: diff --git a/tests/unit/test_shared_functions.py b/tests/unit/test_shared_functions.py index 7f9effdb5e7..843d5b3028b 100644 --- a/tests/unit/test_shared_functions.py +++ b/tests/unit/test_shared_functions.py @@ -177,8 +177,10 @@ def test_abs_lambda_path_w_filename_envvar(default_lambda_path): # Given Env is set and relative_path provided relative_path = "cert/pub.cert" os.environ["LAMBDA_TASK_ROOT"] = default_lambda_path - # Then path = env + relative_path - assert abs_lambda_path(relative_path="cert/pub.cert") == str(Path(os.environ["LAMBDA_TASK_ROOT"], relative_path)) + # Then path = env + relative_path, joined with POSIX separators on every platform because the + # Lambda runtime is Linux. Building the expectation with Path() would hide a native-separator + # rewrite, since both sides would be rewritten the same way. + assert abs_lambda_path(relative_path=relative_path) == f"{default_lambda_path}/{relative_path}" def test_sanitize_xray_segment_name(): From 0d89c9fbcc9c93815f7a8c63ba2b9e5849bebe0a Mon Sep 17 00:00:00 2001 From: Leandro Date: Mon, 14 Sep 2026 14:25:27 +0100 Subject: [PATCH 2/2] test(shared): use native path expectation --- aws_lambda_powertools/shared/functions.py | 17 +++++------------ tests/unit/test_shared_functions.py | 8 +++----- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/aws_lambda_powertools/shared/functions.py b/aws_lambda_powertools/shared/functions.py index 0192786861b..b02f99d7665 100644 --- a/aws_lambda_powertools/shared/functions.py +++ b/aws_lambda_powertools/shared/functions.py @@ -7,7 +7,7 @@ import re import warnings from binascii import Error as BinAsciiError -from pathlib import Path, PurePosixPath +from pathlib import Path from typing import TYPE_CHECKING, Any, TypeGuard, overload from aws_lambda_powertools.shared import constants @@ -280,17 +280,10 @@ def abs_lambda_path(relative_path: str = "") -> str: Otherwise, it will use the current working directory. If the path is empty, it will return the current working directory. """ - # The Lambda runtime is Linux, so LAMBDA_TASK_ROOT is always a POSIX path. Joining it with - # pathlib.Path rewrites it with the separators of whatever platform this code runs on, so a - # developer running the suite on Windows would get "\var\task" instead of "/var/task". - # PurePosixPath keeps the value the runtime gave us intact on every platform. - lambda_task_root = os.environ.get("LAMBDA_TASK_ROOT", "") - if lambda_task_root: - return str(PurePosixPath(lambda_task_root, relative_path)) - - # Off Lambda there is no task root, so fall back to the current working directory and let - # pathlib use the local platform's separators. - return str(Path(Path.cwd(), relative_path)) + # Retrieve the LAMBDA_TASK_ROOT environment variable or default to an empty string + current_working_directory = os.environ.get("LAMBDA_TASK_ROOT", "") or str(Path.cwd()) + + return str(Path(current_working_directory, relative_path)) def sanitize_xray_segment_name(name: str) -> str: diff --git a/tests/unit/test_shared_functions.py b/tests/unit/test_shared_functions.py index 843d5b3028b..0c93a5996da 100644 --- a/tests/unit/test_shared_functions.py +++ b/tests/unit/test_shared_functions.py @@ -162,7 +162,7 @@ def test_abs_lambda_path_empty_envvar(default_lambda_path): # Given Env is set os.environ["LAMBDA_TASK_ROOT"] = default_lambda_path # Then path = Env/ - assert abs_lambda_path() == default_lambda_path + assert abs_lambda_path() == str(Path(default_lambda_path)) def test_abs_lambda_path_w_filename(): @@ -177,10 +177,8 @@ def test_abs_lambda_path_w_filename_envvar(default_lambda_path): # Given Env is set and relative_path provided relative_path = "cert/pub.cert" os.environ["LAMBDA_TASK_ROOT"] = default_lambda_path - # Then path = env + relative_path, joined with POSIX separators on every platform because the - # Lambda runtime is Linux. Building the expectation with Path() would hide a native-separator - # rewrite, since both sides would be rewritten the same way. - assert abs_lambda_path(relative_path=relative_path) == f"{default_lambda_path}/{relative_path}" + # Then path = env + relative_path + assert abs_lambda_path(relative_path="cert/pub.cert") == str(Path(os.environ["LAMBDA_TASK_ROOT"], relative_path)) def test_sanitize_xray_segment_name():