Skip to content

uv workspace projects fail to bundle — workspace member pyproject.toml files collide in flat archive #57

@glk1001

Description

@glk1001

This was written with the help of Claude code:

When using a uv workspace (multiple packages each with their own pyproject.toml under subdirectories), pycrucible --embed fails at runtime with:

error: Workspace member `/path/to/pycrucible_payload/src/my-package` is missing a `pyproject.toml`
Error: Custom { kind: Other, error: "uv run failed" }

Root cause:

The pyproject.toml for a uv workspace root declares [tool.uv.workspace] with members = ["src/pkg-a", "src/pkg-b", ...], each of which has its own pyproject.toml. pycrucible's flat archive format can only embed one file per basename, so the workspace member pyproject.toml files cannot be included. At runtime, uv reads the workspace config from the root pyproject.toml, tries to locate the member packages, and fails because their pyproject.toml files are absent from the bundle.

Workaround (for today):

Before calling pycrucible --embed, we use a Python script to strip the [tool.uv.workspace], [tool.uv.sources], and workspace package dependency entries from the root pyproject.toml, then restore it afterward. The workspace packages are located at runtime via PYTHONPATH set in pycrucible.toml:


  cp -p pyproject.toml pyproject.toml.bundle_bak
  trap 'mv -f pyproject.toml.bundle_bak pyproject.toml 2>/dev/null' EXIT
  python3 <<'PYEOF'
  import re
  with open('pyproject.toml') as f:
      content = f.read()
  for pkg in ['pkg-a', 'pkg-b', 'pkg-c', 'pkg-d']:
      content = re.sub('\n    "' + pkg + '",', '', content)
  content = re.sub(r'\n\[tool\.uv\.workspace\]\n.*?(?=\n\[)', '', content, flags=re.DOTALL)
  content = re.sub(r'\n\[tool\.uv\.sources\]\n.*?(?=\n\[|\Z)', '', content, flags=re.DOTALL)
  with open('pyproject.toml', 'w') as f:
      f.write(content)
  PYEOF

  uv run pycrucible --embed . -o my-app

  mv pyproject.toml.bundle_bak pyproject.toml
  trap - EXIT

Suggested fix:

Ideally pycrucible would detect [tool.uv.workspace] in the root pyproject.toml and either:

  1. Automatically strip workspace-only sections before embedding (since the member pyproject.toml files can't be included anyway), or
  2. Embed each workspace member pyproject.toml under its full relative path (i.e. src/pkg-a/pyproject.toml) rather than flattening to pyproject.toml

Option 1 seems lower-risk and more immediately useful.

Environment:

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions