Skip to content

fix(python-uv): take into account dependencies on other workspace members#887

Open
noritada wants to merge 1 commit into
aws:developfrom
noritada:working
Open

fix(python-uv): take into account dependencies on other workspace members#887
noritada wants to merge 1 commit into
aws:developfrom
noritada:working

Conversation

@noritada

@noritada noritada commented Jul 9, 2026

Copy link
Copy Markdown

This PR fixes an issue where an application created as a member of a
uv workspace would fail to build if they depended on other workspace
members.

The following shows the problematic workspace structure and the error
message.

workspace root
├── lib
│   ├── pyproject.toml
│   └── src
├── pyproject.toml
├── sam-app
│   ├── __init__.py
│   ├── app.py
│   ├── pyproject.toml
│   ├── samconfig.toml
│   └── template.yaml
└── uv.lock
Build Failed
Error: PythonUvBuilder:ResolveDependencies - UV package build failed: Failed to build from pyproject.toml: Lock file operation failed: Failed to install dependencies using uv: UV pip install failed: Using CPython 3.13.0 interpreter at: /path/to/workspace/.venv/bin/python3
error: Distribution not found at: file:///path/to/workspace/sam-app/lib

Even though lib and sam-app are in the same directory level in the
workspace, the workflow attempts to install lib under sam-app.

In the workflow, uv export outputs a list of dependency packages,
which is then passed to uv pip install for installation. When doing
so, uv export outputs relative paths from the workspace root.
Therefore, uv pip install must be run from the workspace root, not
from the application directory.

Additionally, dependencies on other packages within the workspace are
exported as editable installations (e.g., -e ./lib) by default.
When this is passed to uv pip install, only the .pth (path
configuration) file for the package will be installed without the
package body. To prevent this, the --no-editable option needs to be
used.

Commands to reproduce the build failure

uv init --bare
uv init --lib lib
sam init --name sam-app --runtime python3.14 --architecture arm64 \
    --dependency-manager pip --package-type Zip \
    --app-template hello-world
cd sam-app
uv init
uv add lib@../lib
# remove requirements.txt and edit the app
# edit template.yaml to configure `BuildMethod: python-uv` and `CodeUri: .`
sam build --beta-features

@noritada noritada requested a review from a team as a code owner July 9, 2026 17:03
@github-actions github-actions Bot added pr/external stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at. labels Jul 9, 2026

@aws-sam-tooling-bot aws-sam-tooling-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Results

Reviewed: 37cd1d1..e96d649
Files: 1
Comments: 1

# For packages in the workspace, exported paths are relative to the workspace root,
# regardless of where in the workspace uv export is called
workspace_args = ["workspace", "dir"]
rc, stdout, stderr = self._uv_runner._uv.run_uv_command(workspace_args, cwd=project_dir)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[GENERAL] This change introduces a second run_uv_command invocation inside _build_from_lock_file (for uv workspace dir), but the existing unit tests were not updated and will fail:

  • tests/unit/workflows/python_uv/test_packager.py::test_build_from_lock_file asserts self.mock_uv_runner._uv.run_uv_command.assert_called_once(), which now sees two calls (export + workspace dir).
  • tests/unit/workflows/python_uv/test_packager.py::test_build_dependencies_pyproject_with_uv_lock has the same assertion and will also break.

In addition, those tests set run_uv_command.return_value = (0, b"", b"") (bytes). The new line workspace_dir = stdout.strip() will yield b"" under this mock, which is then passed as cwd to install_requirements. Since install_requirements is mocked in the unit tests this does not fail there, but tests should be updated to use strings (matching production OSUtils.run_subprocess, which returns text=True output) and to explicitly cover the new uv workspace dir path — including the failure branch (rc != 0 raising LockFileError) and verifying that install_requirements is invoked with cwd=workspace_dir rather than project_dir. Without such coverage, regressions in the workspace‑resolution logic (which is the core of this fix) will go undetected.

Example update for test_build_from_lock_file:

def test_build_from_lock_file(self):
   # First call: export (returns empty stdout). Second call: workspace dir.
   self.mock_uv_runner._uv.run_uv_command.side_effect = [
       (0, "", ""),
       (0, "/workspace/root", ""),
   ]

   self.builder._build_from_lock_file(
       lock_path="/workspace/root/sam-app/uv.lock",
       target_dir="/target",
       scratch_dir="/scratch",
       python_version="3.9",
       architecture=X86_64,
       config=UvConfig(),
   )

   self.assertEqual(self.mock_uv_runner._uv.run_uv_command.call_count, 2)
   # export runs from project_dir, install runs from the workspace root
 , installkwargs = self.mock_uv_runner.install_requirements.call_args
   self.assertEqual(install_kwargs["cwd"], "/workspace/root")

…bers

This commit fixes an issue where an application created as a member of a
uv workspace would fail to build if they depended on other workspace
members.

The following shows the problematic workspace structure and the error
message.

```
workspace root
├── lib
│   ├── pyproject.toml
│   └── src
├── pyproject.toml
├── sam-app
│   ├── __init__.py
│   ├── app.py
│   ├── pyproject.toml
│   ├── samconfig.toml
│   └── template.yaml
└── uv.lock
```

```
Build Failed
Error: PythonUvBuilder:ResolveDependencies - UV package build failed: Failed to build from pyproject.toml: Lock file operation failed: Failed to install dependencies using uv: UV pip install failed: Using CPython 3.13.0 interpreter at: /path/to/workspace/.venv/bin/python3
error: Distribution not found at: file:///path/to/workspace/sam-app/lib
```

Even though `lib` and `sam-app` are in the same directory level in the
workspace, the workflow attempts to install `lib` under `sam-app`.

In the workflow, `uv export` outputs a list of dependency packages,
which is then passed to `uv pip install` for installation. When doing
so, [`uv export` outputs relative paths from the workspace root][1].
Therefore, `uv pip install` must be run from the workspace root, not
from the application directory.

Additionally, dependencies on other packages within the workspace are
exported as editable installations (e.g., `-e ./lib`) by default.
When this is passed to `uv pip install`, only the `.pth` (path
configuration) file for the package will be installed without the
package body. To prevent this, the `--no-editable` option needs to be
used.

[1]: astral-sh/uv#20238
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr/external stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant