repro-lambda 0.5.1__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/CHANGELOG.md +5 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/PKG-INFO +1 -1
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/pyproject.toml +1 -1
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/__init__.py +1 -1
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/docker_runner.py +47 -14
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_docker_runner.py +20 -4
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/uv.lock +1 -1
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/.github/workflows/build.yml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/.github/workflows/ci.yml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/.github/workflows/move-major-tag.yml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/.github/workflows/promote.yml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/.github/workflows/publish.yml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/.gitignore +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/.pre-commit-config.yaml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/LICENSE +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/README.md +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/SETUP.md +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/__main__.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/build.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/catalog.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/cli.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/git_guard.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/hasher.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/manifest.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/promote.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/s3_uploader.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/source_locker.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/source_stager.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/sources.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/verify.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/src/repro_lambda/zip_packager.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/__init__.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/conftest.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_nodejs_lambda/handler/index.js +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_nodejs_lambda/handler/package-lock.json +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_nodejs_lambda/handler/package.json +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_nodejs_lambda/lambdas.toml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_python_lambda/handler/app.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_python_lambda/handler/requirements.arm64.lock +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_python_lambda/handler/requirements.in +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_python_lambda/lambdas.toml +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_build_integration.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_build_nodejs.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_catalog.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_cli_build.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_cli_lock.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_cli_smoke.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_docker_runner_nodejs.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_e2e_nodejs_lambda.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_e2e_python_lambda.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_extra_files.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_git_guard.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_hasher.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_manifest.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_per_lambda_builder.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_promote.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_python_byte_compat_regression.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_s3_uploader.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_source_locker.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_source_stager.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_sources.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_sources_hash.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_sources_schema.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_verify.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_zip_excludes.py +0 -0
- {repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/test_zip_packager.py +0 -0
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.5.2 - 2026-06-21
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Pass the full compatible manylinux range to `pip install` instead of a single `--platform`, so compiled wheels are selected for every package. A single explicit `--platform` matches (close to) that exact tag - it does not broaden across baselines - so `manylinux_2_17` silently dropped compiled wheels tagged only at a higher baseline. Concretely, `wrapt`'s cp313 wheel is tagged `manylinux_2_28` (no `2_17`), so pip fell back to the pure-Python `py3-none-any` build; that broke `aws-xray-sdk`'s runtime boto3 patching and 500'd a Lambda whose package included it. The v0.4.1 change (2_28 -> 2_17, to catch `pydantic-core`'s 2_17-only wheel) had created the opposite failure - a single floor cannot satisfy both. Now `docker_runner.py` emits repeated `--platform` flags from `manylinux_2_34` down to `manylinux1` (x86_64) / `manylinux2014` (aarch64), capped at the AL2023 runtime's glibc 2.34, and pip picks the most-specific compiled wheel each package offers, only using `py3-none-any` when no compiled wheel exists. Verified end to end: a real build now ships `wrapt/_wrappers.*.so` again. The builder version bump re-keys all content hashes, as expected.
|
|
7
|
+
|
|
3
8
|
## v0.5.1 - 2026-06-21
|
|
4
9
|
|
|
5
10
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: repro-lambda
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Build reproducible AWS Lambda packages outside Terraform, optimized for terraform-aws-lambda by serverless.tf.
|
|
5
5
|
Project-URL: Homepage, https://github.com/antonbabenko/repro-lambda
|
|
6
6
|
Project-URL: Repository, https://github.com/antonbabenko/repro-lambda
|
|
@@ -12,17 +12,50 @@ ARCH_TO_DOCKER_PLATFORM: dict[str, str] = {
|
|
|
12
12
|
"x86_64": "linux/amd64",
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# wheels (e.g. pydantic-core)
|
|
19
|
-
#
|
|
20
|
-
# pip
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
# The AWS Lambda base images (Amazon Linux 2023) ship glibc 2.34, so the runtime can load
|
|
16
|
+
# any manylinux wheel up to manylinux_2_34. pip's explicit --platform matches (close to)
|
|
17
|
+
# that exact tag, so a SINGLE platform misses wheels tagged with other baselines in both
|
|
18
|
+
# directions: a 2_28 floor misses 2_17-only wheels (e.g. pydantic-core), and a 2_17 floor
|
|
19
|
+
# misses higher-baseline compiled wheels (e.g. wrapt ships cp313 only as manylinux_2_28 ->
|
|
20
|
+
# pip silently falls back to py3-none-any, which broke aws-xray-sdk's runtime boto3 patching
|
|
21
|
+
# and 500'd a Lambda). A single floor cannot satisfy both. Pass the FULL compatible range as
|
|
22
|
+
# repeated --platform flags, newest -> oldest, capped at 2_34 (the runtime's glibc): pip then
|
|
23
|
+
# selects the most-specific COMPILED wheel each package offers and only falls back to
|
|
24
|
+
# py3-none-any when no compiled wheel exists. Never list a baseline ABOVE 2_34 - that would
|
|
25
|
+
# let pip pick a wheel the runtime cannot load. (arm64 manylinux starts at 2014/2_17; the
|
|
26
|
+
# manylinux1/2010/2_5 legacy aliases are x86_64-only.)
|
|
27
|
+
ARCH_TO_PIP_PLATFORMS: dict[str, list[str]] = {
|
|
28
|
+
"x86_64": [
|
|
29
|
+
"manylinux_2_34_x86_64",
|
|
30
|
+
"manylinux_2_28_x86_64",
|
|
31
|
+
"manylinux_2_24_x86_64",
|
|
32
|
+
"manylinux2014_x86_64",
|
|
33
|
+
"manylinux_2_17_x86_64",
|
|
34
|
+
"manylinux_2_12_x86_64",
|
|
35
|
+
"manylinux2010_x86_64",
|
|
36
|
+
"manylinux_2_5_x86_64",
|
|
37
|
+
"manylinux1_x86_64",
|
|
38
|
+
],
|
|
39
|
+
"arm64": [
|
|
40
|
+
"manylinux_2_34_aarch64",
|
|
41
|
+
"manylinux_2_28_aarch64",
|
|
42
|
+
"manylinux_2_24_aarch64",
|
|
43
|
+
"manylinux2014_aarch64",
|
|
44
|
+
"manylinux_2_17_aarch64",
|
|
45
|
+
],
|
|
24
46
|
}
|
|
25
47
|
|
|
48
|
+
|
|
49
|
+
def pip_platform_flags(arch: str) -> str:
|
|
50
|
+
"""Repeated ``--platform <tag>`` flags (space-joined) for an arch's manylinux range.
|
|
51
|
+
|
|
52
|
+
Word-split UNQUOTED into the pip command in the container so each tag becomes its own
|
|
53
|
+
flag. pip treats a wheel as compatible with ANY listed platform and prefers the
|
|
54
|
+
earliest (newest baseline) match, so compiled wheels win over the py3-none-any fallback.
|
|
55
|
+
"""
|
|
56
|
+
return " ".join(f"--platform {tag}" for tag in ARCH_TO_PIP_PLATFORMS[arch])
|
|
57
|
+
|
|
58
|
+
|
|
26
59
|
ARCH_TO_NPM_CPU: dict[str, str] = {
|
|
27
60
|
"arm64": "arm64",
|
|
28
61
|
"x86_64": "x64",
|
|
@@ -31,9 +64,9 @@ ARCH_TO_NPM_CPU: dict[str, str] = {
|
|
|
31
64
|
# Invariance: keys must match across all arch lookup tables. Adding a new arch
|
|
32
65
|
# to one without the other would cause install_nodejs_dependencies to raise
|
|
33
66
|
# KeyError instead of DockerRunError. Caught at import time.
|
|
34
|
-
assert set(ARCH_TO_DOCKER_PLATFORM) == set(
|
|
67
|
+
assert set(ARCH_TO_DOCKER_PLATFORM) == set(ARCH_TO_PIP_PLATFORMS) == set(ARCH_TO_NPM_CPU), (
|
|
35
68
|
"arch lookup tables must share the same key set; "
|
|
36
|
-
f"DOCKER={set(ARCH_TO_DOCKER_PLATFORM)} PIP={set(
|
|
69
|
+
f"DOCKER={set(ARCH_TO_DOCKER_PLATFORM)} PIP={set(ARCH_TO_PIP_PLATFORMS)} NPM={set(ARCH_TO_NPM_CPU)}"
|
|
37
70
|
)
|
|
38
71
|
|
|
39
72
|
|
|
@@ -49,7 +82,7 @@ cp -R /src/source/. "$PKG/"
|
|
|
49
82
|
|
|
50
83
|
pip install \
|
|
51
84
|
--no-cache-dir --no-compile --require-hashes --only-binary=:all: \
|
|
52
|
-
|
|
85
|
+
$PIP_PLATFORM_FLAGS \
|
|
53
86
|
--abi "$PIP_ABI" \
|
|
54
87
|
--python-version "$PIP_PYVER" \
|
|
55
88
|
--implementation cp \
|
|
@@ -130,7 +163,7 @@ def build_python_lambda(
|
|
|
130
163
|
python_version: str,
|
|
131
164
|
) -> None:
|
|
132
165
|
"""v0.1-compatible: install + pack inside the Python container."""
|
|
133
|
-
if arch not in
|
|
166
|
+
if arch not in ARCH_TO_PIP_PLATFORMS:
|
|
134
167
|
raise DockerRunError(f"unsupported arch {arch!r}")
|
|
135
168
|
if shutil.which("docker") is None:
|
|
136
169
|
raise DockerRunError("docker CLI not found on PATH")
|
|
@@ -158,7 +191,7 @@ def build_python_lambda(
|
|
|
158
191
|
"-e",
|
|
159
192
|
"PYTHONPATH=/builder",
|
|
160
193
|
"-e",
|
|
161
|
-
f"
|
|
194
|
+
f"PIP_PLATFORM_FLAGS={pip_platform_flags(arch)}",
|
|
162
195
|
"-e",
|
|
163
196
|
f"PIP_ABI=cp{pyver_compact}",
|
|
164
197
|
"-e",
|
|
@@ -5,23 +5,39 @@ import pytest
|
|
|
5
5
|
|
|
6
6
|
from repro_lambda.docker_runner import (
|
|
7
7
|
ARCH_TO_DOCKER_PLATFORM,
|
|
8
|
-
|
|
8
|
+
ARCH_TO_PIP_PLATFORMS,
|
|
9
9
|
DockerRunError,
|
|
10
10
|
build_python_lambda,
|
|
11
|
+
pip_platform_flags,
|
|
11
12
|
)
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def test_arch_mapping_tables_are_complete():
|
|
15
16
|
for arch in ("arm64", "x86_64"):
|
|
16
17
|
assert arch in ARCH_TO_DOCKER_PLATFORM
|
|
17
|
-
assert arch in
|
|
18
|
+
assert arch in ARCH_TO_PIP_PLATFORMS
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def test_arch_mapping_values():
|
|
21
22
|
assert ARCH_TO_DOCKER_PLATFORM["arm64"] == "linux/arm64"
|
|
22
23
|
assert ARCH_TO_DOCKER_PLATFORM["x86_64"] == "linux/amd64"
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_pip_platform_flags_span_the_range_and_cap_at_2_34():
|
|
27
|
+
"""Multiple --platform flags so pip picks the best COMPILED wheel per package; a single
|
|
28
|
+
tag silently dropped compiled wheels (e.g. wrapt -> py3-none-any). Cap at glibc 2.34."""
|
|
29
|
+
for arch, tag_arch in (("x86_64", "x86_64"), ("arm64", "aarch64")):
|
|
30
|
+
flags = pip_platform_flags(arch)
|
|
31
|
+
tags = ARCH_TO_PIP_PLATFORMS[arch]
|
|
32
|
+
# Repeated --platform, one per tag, in declared (newest-first) order.
|
|
33
|
+
assert flags == " ".join(f"--platform {t}" for t in tags)
|
|
34
|
+
assert flags.count("--platform ") == len(tags)
|
|
35
|
+
# Must include both the historical floors that each broke one direction.
|
|
36
|
+
assert f"manylinux_2_17_{tag_arch}" in flags # pydantic-core (2_17-only) still resolves
|
|
37
|
+
assert f"manylinux_2_28_{tag_arch}" in flags # wrapt's compiled cp313 wheel resolves
|
|
38
|
+
# Never a baseline above the runtime's glibc 2.34 (would be unloadable).
|
|
39
|
+
for n in (35, 36, 38, 40):
|
|
40
|
+
assert f"manylinux_2_{n}_" not in flags
|
|
25
41
|
|
|
26
42
|
|
|
27
43
|
def test_build_python_lambda_raises_on_unknown_arch(tmp_path: Path):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_nodejs_lambda/handler/index.js
RENAMED
|
File without changes
|
|
File without changes
|
{repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_nodejs_lambda/handler/package.json
RENAMED
|
File without changes
|
|
File without changes
|
{repro_lambda-0.5.1 → repro_lambda-0.5.2}/tests/fixtures/sample_python_lambda/handler/app.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|