Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Excluding a file from non-editable installs with uv sync --no-editable #10391

Open
mjpieters opened this issue Jan 8, 2025 · 3 comments
Open
Labels
needs-mre Needs more information for reproduction

Comments

@mjpieters
Copy link

mjpieters commented Jan 8, 2025

I have a packaged app project with a docker image, built with uv:

RUN --mount=from=ghcr.io/astral-sh/uv:0.5.14@sha256:f0786ad49e2e684c18d38697facb229f538a6f5e374c56f54125aabe7d14b3f7,source=/uv,target=/bin/uv \
    --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    --mount=type=bind,source=src/,target=src/ \
    uv sync --no-group dev --no-editable

The project uses hatch as the build backend, and excludes a single file that is only used during development (a third-party tool needs to be able to import it)

[build-system]
requires = ["hatchling==1.27.0"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.sdist]
exclude = [
    "src/project_name/_dev_support_plugin.py",
]

When I run uv build and inspect the sdist and wheel, the plugin file is not packaged, as intended:

% rm -rf dist/
% uv build
# ...
% tar tzvf dist/*.tar.gz | grep plugin 
# no output
% zipinfo dist/*.whl | grep plugin
# no output

However, the docker image does include the file, the .venv/lib/python3.13/site-packages/project_name/_dev_support_plugin.py exists and is importable.

I expected that uv would have used the build backend to create the source distribution for such installs, but that's apparently not the case.

To simplify and debug, I next used uv sync locally to verify this isn't specific to docker:

% uv sync --no-group dev --no-editable
...
% ls .venv/lib/python3.13/site-packages/project_name/ | grep plugin
_dev_support_plugin.py

I then also tried to run the above with --reinstall and --no-cache with the same results. I also tried excluding the file by adding a [tool.hatch.build.targets.wheel] section with the same exclude configuration, but this makes no difference either.

Is there any way I can exclude files from being installed when using --no-editable or should I relocate the plugin to some other place and add that to the import path for the 3rd-party tool to import?

@charliermarsh
Copy link
Member

We do use the same build frontend to build the distribution for such installs, so I would expect the file to be excluded there too. Can you provide a full reproduction, like a Git repo that I can clone and run? It's a fairly bespoke setup so it's a lot of work for me to reproduce it myself.

@charliermarsh charliermarsh added the needs-mre Needs more information for reproduction label Jan 8, 2025
@mjpieters
Copy link
Author

mjpieters commented Jan 8, 2025

We do use the same build frontend to build the distribution for such installs, so I would expect the file to be excluded there too. Can you provide a full reproduction, like a Git repo that I can clone and run? It's a fairly bespoke setup so it's a lot of work for me to reproduce it myself.

It's an open source project but I haven't committed the work for this yet (I'm dithering on a GraphQL dev pipeline, the plugin is for a code generator): https://github.com/mjpieters/pyright-analysis-action. So, not yet?

But, I found it easy enough to create a stand-alone test for this; here is the reproducer, with bash functions to do test the issue:

mkdir /tmp/reproducer
cd /tmp/reproducer
uv init --vcs none --python 3.13 --package --name reproducer
>>pyproject.toml cat << EOF

[tool.hatch.build.targets.sdist]
exclude = [
    "src/reproducer/dontinclude.py",
]
EOF
touch src/reproducer/dontinclude.py
function test_dists {
    rm -rf dist/; uv build
    if tar tzvf dist/reproducer-0.1.0.tar.gz| grep -q dontinclude; then echo -e '\033[1;31mFAILED\033[0m'; return; fi
    if zipinfo dist/reproducer-0.1.0-py3-none-any.whl| grep -q dontinclude; then echo -e '\033[1;31mFAILED\033[0m'; return; fi
    echo -e '\033[1;32mSUCCESS\033[0m'
}
function test_uv_sync {
    rm -rf .venv
    uv sync --no-editable --no-cache
    if [ -f .venv/lib/python3.13/site-packages/reproducer/dontinclude.py ]; then echo -e '\033[1;31mFAILED\033[0m'; return; fi
    echo -e '\033[1;32mSUCCESS\033[0m'
}

You can then verify that dontinclude.py is not part of the sdist or wheel artefacts by invoking the test_dists function:

% test_dists
Building source distribution...
Building wheel from source distribution...
Successfully built dist/reproducer-0.1.0.tar.gz
Successfully built dist/reproducer-0.1.0-py3-none-any.whl
SUCCESS

and finally, verify that uv sync --no-editable does include the file with the test_uv_sync function:

% test_uv_sync
Creating virtual environment at: .venv
Resolved 1 package in 4ms
   Built reproducer @ file:///private/tmp/reproducer
Prepared 1 package in 706ms
Installed 1 package in 2ms
 + reproducer==0.1.0 (from file:///private/tmp/reproducer)
FAILED

And, as this probably matters, here's my current uv version, OS version and platform architecture:

% uv --version
uv 0.5.15 (Homebrew 2025-01-07)
% sw_vers
ProductName:		macOS
ProductVersion:		14.7.2
BuildVersion:		23H311
% arch
arm64

@mjpieters
Copy link
Author

I note that the same issue also applies to uv run --with ., as shown by the following test command run in the same /tmp/reproducer directory:

% uv run --with . python -c 'import reproducer, os; print("\x1b[1;31mFAILED\x1b[0m" if "dontinclude.py" in os.listdir(os.path.dirname(reproducer.__file__)) else "\x1b[1;32mSUCCESS\x1b[0m")'
FAILED

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-mre Needs more information for reproduction
Projects
None yet
Development

No branches or pull requests

2 participants