aws / aws/aws-lambda-builders

Feature request: Add native uv support and configuration

Open
#839 2 comments 1 reaction 0 assignees View on GitHub
stage/needs-triage type/feature
Dominant language
Python
Stars
380
Forks
161
Avg merge
1d 1h
Merged PRs (30d)
2

Description

### Describe your idea/feature/enhancement

I wish the AWS Lambda Builders would support native `uv` usage instead of using `uv export` to facilitate dependency management (as designed [here](https://github.com/aws/aws-lambda-builders/blob/051c6ef2fd0079190c758f1622af7a68e48eb723/aws_lambda_builders/workflows/python_uv/DESIGN.md)).

I know that experimental uv support was just added (related: https://github.com/aws/aws-lambda-builders/pull/756 and https://github.com/aws/aws-lambda-builders/issues/818). It mirrors the workaround I've been using for a while, but lacks certain capabilities that I need (and also have workarounds for).

### Additional Details

It would be nice to be able to pass certain variables or arguments in order to use specific `uv` features, like described below

1. I noticed that the `uv export` doesn't include a `--no-dev`, which bloats the final artifact:

https://github.com/aws/aws-lambda-builders/blob/ed7d955598e4f8974f9baba25cf1600176aa0054/aws_lambda_builders/workflows/python_uv/packager.py#L326-L338

This seems to be in conflict with one statement from the design document:

https://github.com/aws/aws-lambda-builders/blob/051c6ef2fd0079190c758f1622af7a68e48eb723/aws_lambda_builders/workflows/python_uv/DESIGN.md?plain=1#L26

2. Currently, `--no-hashes` is hard coded, but in my environment I do require hashes in my `pyproject.toml`. This causes an issue because my `[tool.uv.pip]` config leaks into the builder subprocess, causing a conflict.

I'm not sure what phase things are currently in, given this is deployed, but still experimental, but I did note the following:

https://github.com/aws/aws-lambda-builders/blob/051c6ef2fd0079190c758f1622af7a68e48eb723/aws_lambda_builders/workflows/python_uv/DESIGN.md?plain=1#L311-L329

Which mentions "Advanced configuration options", and so it may be planned, future work to add support for `--no-dev`, etc.

3. It would be very useful to be able to natively mount a local package into the final build artifact. I already support this in my flow which wraps `aws-lambda-builder`/`sam` but I'd rather it be supported natively

I had Opus 4.6 do a write-up of some of the details/issues it had migrating from my current workaround to the new experimental approach, which may be helpful. I'm doing this with the `sam` cli.

Details

```md

Upstream Issues in aws-lambda-builders UV Workflow

All bugs are in the experimental PythonUvBuilder workflow (aws-lambda-builders, shipped with SAM CLI >= 1.155.2). The
relevant code lives in aws_lambda_builders/workflows/python_uv/.

Bug 1: Dev dependencies included in build artifact

File: packager.py, _build_from_lock_file() ~line 326-338

Problem: The uv export command is missing --no-dev. All dependencies from [dependency-groups] dev in pyproject.toml
are exported and installed into the Lambda artifact.

Impact: Build artifact balloons from ~144M to ~408M (in our case), including pytest, pyright, cfn-lint, coverage,
etc. Exceeds Lambda's 250MB unzipped size limit.

Expected: uv export should include --no-dev to exclude development dependencies from production builds.

Current code:
export_args = [
"export",
"--format", "requirements.txt",
"--no-emit-project",
"--no-hashes",
"--output-file", temp_requirements,
"--python", python_version,
]

Fix: Add "--no-dev" to export_args.

---
Bug 2: --cached mode fails with CopyDependenciesAction

File: workflow.py, _setup_build_actions() ~line 142-151

Problem: When --cached is used (i.e. dependencies_dir is set), deps are installed to .aws-sam/deps// but the
CopyDependenciesAction is constructed with swapped semantics. It tries to os.listdir(artifact_dir)
(.aws-sam/build/ExampleFunction) which doesn't exist yet — the deps are in destination_dir (.aws-sam/deps/).

Error: [Errno 2] No such file or directory: '.aws-sam/build/ExampleFunction'

Current code:
CopyDependenciesAction(
source_dir=source_dir,
artifact_dir=artifacts_dir, # .aws-sam/build/ExampleFunction (empty)
destination_dir=self.dependencies_dir, # .aws-sam/deps/... (has deps)
)

The DependencyManager.yield_source_dest() does os.listdir(self._artifact_dir) then copies FROM artifact_dir TO
dest_dir — which is backwards. Deps are in dependencies_dir but it tries to read from artifacts_dir.

Impact: Every sam build with --cached fails for the UV workflow. Without --cached, builds always re-download deps.

---
Bug 3: [tool.uv.pip] config leaks into builder subprocess

File: packager.py, _build_from_lock_file() ~line 345-353

Problem: The uv pip install command runs with cwd=project_dir, which makes uv read [tool.uv.pip] settings from the
project's pyproject.toml. If the project has require-hashes = true (common security practice), but the builder
exported with --no-hashes, uv pip install fails because it requires hashes that aren't present.

Error: error: In --require-hashes mode, all requirements must have a hash, but none were provided for: aenum==3.1.16

Root cause: The builder explicitly exports with --no-hashes (line 331) but doesn't account for the project's
[tool.uv.pip] config overriding the install behavior. The uv pip install inherits the project's pyproject.toml
settings since it runs from the project directory.

Possible fixes:
- Pass --no-verify-hashes to the uv pip install command
- Run uv pip install with UV_NO_VERIFY_HASHES=true in the subprocess env
- Export WITH hashes instead of --no-hashes (then the require-hashes config is satisfied)
- Run uv pip install from a temp dir without pyproject.toml context

---
Our Workarounds

┌────────────────────────┬───────────────────────────────────────────────────────────────────────────┐
│ Bug │ Workaround │
├────────────────────────┼───────────────────────────────────────────────────────────────────────────┤
│ Bug 1 (dev deps) │ Generate our own uv export --no-dev requirements file, pass as --manifest │
├────────────────────────┼───────────────────────────────────────────────────────────────────────────┤
│ Bug 2 (--cached) │ Don't use --cached flag │
├────────────────────────┼───────────────────────────────────────────────────────────────────────────┤
│ Bug 3 (require-hashes) │ Removed generate-hashes/require-hashes from pyproject.toml [tool.uv.pip] │
└────────────────────────┴───────────────────────────────────────────────────────────────────────────┘

Bugs 1 and 2 are worked around by the same mechanism: since we generate our own requirements-*.txt via uv export
--no-dev --no-hashes --frozen --no-emit-project, the lambda-builders use the _build_from_requirements path (simple uv
pip install -r) instead of the buggy _build_from_lock_file path. This also avoids the --cached
CopyDependenciesAction issue since we don't use --cached.
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.