← Back to issue list

uv plugin documentation is misleading

View original Github issue

Metadata

Project
craft-parts
Number
#1580
Type
issue
State
open
Author
dilyn-corner
Labels
Created
2026-05-11 21:01:49+00:00
Updated
2026-05-11 21:05:53+00:00
Closed

Current evaluation

No evaluation has been recorded for this issue yet.

Issue body

### What needs to get done The uv plugin documentation should be updated to explain the consequences of using certain environment variables, and potentially their workarounds (or an example snap be made to explain how to appropriately handle uv and python). I've tested this for both core22 and core24, and both seem impacted. I think core26+ and bare are fine, as the plugin(s) handle the interpreter differently in those cases. ### Why it needs to get done As written, the uv plugin documentation does not adequately explain the impacts of using certain environment variables. This results in broken snaps due to unexpected behavior (at least, it's unexpected for me). Consider the (common) case where the snap must package its own python interpreter (due to, say, a python version requirement). In this case, one must add: ```yaml build-environment: - UV_PYTHON: "python3.xy" - PARTS_PYTHON_INTERPRETER: "python3.xy" - UV_PYTHON_PREFERENCE: "only-managed" - UV_PYTHON_DOWNLOADS: "auto" ``` The first two variables must be used to tell uv which python version to use, and the (undocumented, at least here) `PARTS_PYTHON_INTERPRETER` must be specified in order for the `uv venv` command to use the correct python version and avoid errors relating to the build being unable to find the correct python. The last two variables must be used to force uv to fetch its own python, mostly *because of this issue I'm experiencing itself*, cleaning the contents of `$CRAFT_PART_INSTALL`: ```bash :: + uv venv --relocatable --allow-existing --python /usr/bin/python3.10 /root/parts/my-part/install :: Using CPython 3.10.12 interpreter at: /usr/bin/python3.10 :: warning: The requested interpreter resolved to Python 3.10.12, which is incompatible with the project's Python requirement: `>=3.11, <4.0` (from `project.requires-python`) :: Creating virtual environment at: /root/parts/my-part/install :: Activate with: source /root/parts/my-part/install/bin/activate :: + PARTS_PYTHON_VENV_INTERP_PATH=/root/parts/my-part/install/bin/python3.11 :: + uv sync --no-dev --no-editable --reinstall --extra cpu :: Using CPython 3.11.0rc1 interpreter at: /root/parts/my-part/install/usr/bin/python3.11 :: Removed virtual environment at: /root/parts/my-part/install :: Creating virtual environment at: /root/parts/my-part/install :: Building immich-ml @ file:///root/parts/my-part/build/machine-learning :: × Failed to build `immich-ml @ file:///root/parts/my-part/build/machine-learning` :: ├─▶ Failed to identify base Python interpreter :: ╰─▶ failed to canonicalize path `/root/parts/my-part/install/usr/bin/python3.11`: No such file or directory (os error 2) ``` https://github.com/canonical/craft-parts/blob/0910f51749eda1416b08e8389527f81e2ef8ce9f/craft_parts/plugins/uv_plugin.py#L108 However, when this is done, the venv target directory (`$CRAFT_PART_INSTALL`) is fully cleaned. This means that any `stage-packages` for this part will be unpacked, and then removed. You can see this with the minimal part: ```yaml parts: my-part: plugin: uv source: somesource stage-packages: [hello] build-environment: - UV_PYTHON: "python3.xy" - PARTS_PYTHON_INTERPRETER: "python3.xy" - UV_PYTHON_PREFERENCE: "only-managed" - UV_PYTHON_DOWNLOADS: "auto" override-build: | exit 1 ``` And inspecting `$CRAFT_PART_INSTALL` (`snapcraft --debug`), then removing the `override-build` and checking again (you'll see that the previous contents of `$CRAFT_PART_INSTALL` no longer exist). Below is a "minimal" reproducer: ```yaml name: not-staging # you probably want to 'snapcraft register <name>' base: core22 # the base snap is the execution environment for this snap version: '0.1' # just for humans, typically '1.2+git' or '1.3.2' summary: Single-line elevator pitch for your amazing snap # 79 char long summary description: | This is my-snap's description. You have a paragraph or two to tell the most important story about your snap. Keep it under 100 words though, we live in tweetspace and your description wants to look good in the snap store. grade: devel # must be 'stable' to release into candidate/stable channels confinement: devmode # use 'strict' once you have the right plugs and slots package-repositories: - type: apt ppa: deadsnakes/ppa key-id: F23C5A6CF475977595C89F51BA6932366A755776 parts: my-part: plugin: uv source: https://github.com/immich-app/immich source-depth: 1 source-type: git source-tag: v2.7.5 source-subdir: machine-learning uv-extras: [cpu] build-snaps: [astral-uv] build-packages: [libpython3.11-dev, python3.11-dev] stage-packages: - gunicorn:all - libgl1:${CRAFT_ARCH_BUILD_FOR} - libmimalloc2.0:${CRAFT_ARCH_BUILD_FOR} - libpython3.11:${CRAFT_ARCH_BUILD_FOR} - python3.11:${CRAFT_ARCH_BUILD_FOR} - python3-minimal:${CRAFT_ARCH_BUILD_FOR} - python3.11-minimal:${CRAFT_ARCH_BUILD_FOR} build-environment: - UV_PYTHON: "python3.11" - PARTS_PYTHON_INTERPRETER: "python3.11" - UV_PYTHON_PREFERENCE: "only-managed" - UV_PYTHON_DOWNLOADS: "auto" ``` Below is a corrected version which handles everything in the anticipated manner (following snapcraft's lead): ```yaml name: not-staging # you probably want to 'snapcraft register <name>' base: core22 # the base snap is the execution environment for this snap version: '0.1' # just for humans, typically '1.2+git' or '1.3.2' summary: Single-line elevator pitch for your amazing snap # 79 char long summary description: | This is my-snap's description. You have a paragraph or two to tell the most important story about your snap. Keep it under 100 words though, we live in tweetspace and your description wants to look good in the snap store. grade: devel # must be 'stable' to release into candidate/stable channels confinement: devmode # use 'strict' once you have the right plugs and slots package-repositories: - type: apt ppa: deadsnakes/ppa key-id: F23C5A6CF475977595C89F51BA6932366A755776 parts: my-part-deps: plugin: nil stage-packages: - gunicorn:all - libgl1:${CRAFT_ARCH_BUILD_FOR} - libmimalloc2.0:${CRAFT_ARCH_BUILD_FOR} python-libs: plugin: nil stage-packages: - libpython3.11:${CRAFT_ARCH_BUILD_FOR} - python3.11:${CRAFT_ARCH_BUILD_FOR} - python3-minimal:${CRAFT_ARCH_BUILD_FOR} - python3.11-minimal:${CRAFT_ARCH_BUILD_FOR} my-part: after: [python-libs] plugin: uv source: https://github.com/immich-app/immich source-depth: 1 source-type: git source-tag: v2.7.5 source-subdir: machine-learning uv-extras: [cpu] build-snaps: [astral-uv] build-packages: [libpython3.11-dev, python3.11-dev] build-environment: - UV_PYTHON: "python3.11" - PARTS_PYTHON_INTERPRETER: "python3.11" override-build: |- craftctl default unlink "${CRAFT_PART_INSTALL}/bin/python" ln -sf python3 "${CRAFT_PART_INSTALL}/bin/python" ln -sf ../usr/bin/python3 "${CRAFT_PART_INSTALL}/bin/python3" ```

Evaluation history

No evaluation history available.