astral-sh / uv

An extremely fast Python package and project manager, written in Rust.
https://docs.astral.sh/uv
Apache License 2.0
23.99k stars 690 forks source link

Support of using locked version when building. #7911

Open Renkai opened 2 weeks ago

Renkai commented 2 weeks ago

Hi Y'all! Due to some limitation of where I work, I can only install wheels using pip in production, but it's free to use uv to build wheels. So when using uv, I want to define a loose range for dependencies for testing, let uv decide the final version for me, but produce a wheel with restrict dependency versions for pip install later. Is there a best practice exists?

Here is a some hypothetical user interface:

uv init --lib proj-for-pip
uv add requests
#got 
#dependencies = [
#    "requests>=2.32.3",
#]
#in pyproject.toml
#
#[[package]]
#name = "requests"
#version = "2.32.3"
#in uv.lock

uv build
# got dist/proj_for_pip-0.1.0-py3-none-any.whl
# Requires-Dist: requests>=2.32.3 in metadata of the wheel

uv build --some-parameter-to-lock-version
# got dist/proj_for_pip-0.1.0-py3-none-any.whl
# Requires-Dist: requests==2.32.3 in metadata of the wheel
konstin commented 2 weeks ago

Does using uv export from the project and using that as requirements or constraints input to pip work for you?

The python specs (PEP 621) require us to emit the same values for Requires-Dist: as we find in dependencies, so I'm trying to find a workaround for you that works around PEP 621 restrictions.

Renkai commented 2 weeks ago

@konstin I tried constraint, but it still use >= in the metadata, here is what I tried.

➜  proj-for-pip git:(master) ✗ uv export --no-emit-project > requirements.txt
Resolved 6 packages in 0.67ms
➜  proj-for-pip git:(master) ✗ cat requirements.txt
# This file was autogenerated by uv via the following command:
#    uv export --no-emit-project
certifi==2024.8.30 \
    --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 \
    --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8
charset-normalizer==3.3.2 \
    --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
    --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
    --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
    --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
    --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
    --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
    --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
    --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
    --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
    --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
    --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
    --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
    --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
    --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
    --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
    --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
    --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc
idna==3.10 \
    --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
    --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
requests==2.32.3 \
    --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
    --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
urllib3==2.2.3 \
    --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 \
    --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac
➜  proj-for-pip git:(master) ✗ uv build --build-constraint requirements.txt
Building source distribution...
Building wheel from source distribution...
Successfully built dist/proj_for_pip-0.1.0.tar.gz and dist/proj_for_pip-0.1.0-py3-none-any.whl
➜  proj-for-pip git:(master) ✗ cd dist
➜  dist git:(master) ✗ unzip proj_for_pip-0.1.0-py3-none-any.whl
Archive:  proj_for_pip-0.1.0-py3-none-any.whl
  inflating: proj_for_pip/__init__.py
  inflating: proj_for_pip/py.typed
  inflating: proj_for_pip-0.1.0.dist-info/METADATA
  inflating: proj_for_pip-0.1.0.dist-info/WHEEL
  inflating: proj_for_pip-0.1.0.dist-info/RECORD
➜  dist git:(master) ✗ cat proj_for_pip-0.1.0.dist-info/METADATA
Metadata-Version: 2.3
Name: proj-for-pip
Version: 0.1.0
Summary: Add your description here
Requires-Python: >=3.12
Requires-Dist: requests>=2.32.3
Renkai commented 2 weeks ago

As far as I read from the documentation: https://docs.astral.sh/uv/reference/cli/#uv-build This parameter has not defined it should overwrite the metadata of distribution or not. If we want to implement this feature, should we add another parameter or change the behavior of this parameter?

--build-constraint, -b build-constraint

    Constrain build dependencies using the given requirements files when building distributions.

    Constraints files are requirements.txt-like files that only control the version of a build dependency that’s installed. However, including a package in a constraints file will not trigger the inclusion of that package on its own.

    May also be set with the UV_BUILD_CONSTRAINT environment variable.
leodevian commented 2 weeks ago

You can add your constrained dependencies in requirements.in, compile it using uv pip compile requirements.in > requirements.txt and declare dependencies as dynamic in your pyproject.toml. Then you can use the hatch-requirements-txt plugin to enforce locked dependencies in your build. uv sync will work as expected for main dependencies but will fail for optional dependencies (even though they are declared in METADATA). I might write an issue about that.

Renkai commented 2 weeks ago

You can add your constrained dependencies in requirements.in, compile it using uv pip compile requirements.in > requirements.txt and declare dependencies as dynamic in your pyproject.toml. Then you can use the hatch-requirements-txt plugin to enforce locked dependencies in your build. uv sync will work as expected for main dependencies but will fail for optional dependencies (even though they are declared in METADATA). I might write an issue about that.

Does it mean I can't use uv add to manage my dependencies?

leodevian commented 2 weeks ago

You can add your constrained dependencies in requirements.in, compile it using uv pip compile requirements.in > requirements.txt and declare dependencies as dynamic in your pyproject.toml. Then you can use the hatch-requirements-txt plugin to enforce locked dependencies in your build. uv sync will work as expected for main dependencies but will fail for optional dependencies (even though they are declared in METADATA). I might write an issue about that.

Does it mean I can't use uv add to manage my dependencies?

Unfortunately, yes :/

konstin commented 2 weeks ago

Build constraints are a slightly different feature, they constrain the versions of the resolution of [build-system] requires = [...]; it doesn't affect what version requirements appear in the final wheel.