diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f0bbfed2..7275fd83a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,63 @@ +## 0.9.0 + +Released on 2025-10-07. + +### Breaking changes + +This breaking release is primarily motivated by the release of Python 3.14, which contains some breaking changes (we recommend reading the ["What's new in Python 3.14"](https://docs.python.org/3/whatsnew/3.14.html) page). uv may use Python 3.14 in cases where it previously used 3.13, e.g., if you have not pinned your Python version and do not have any Python versions installed on your machine. While we think this is uncommon, we prefer to be cautious. We've included some additional small changes that could break workflows. + +There are no breaking changes to [`uv_build`](https://docs.astral.sh/uv/concepts/build-backend/). If you have an upper bound in your `[build-system]` table, you should update it. + +- **Python 3.14 is now the default stable version** + + The default Python version has changed from 3.13 to 3.14. This applies to Python version installation when no Python version is requested, e.g., `uv python install`. By default, uv will use the system Python version if present, so this may not cause changes to general use of uv. For example, if Python 3.13 is installed already, then `uv venv` will use that version. If no Python versions are installed on a machine and automatic downloads are enabled, uv will now use 3.14 instead of 3.13, e.g., for `uv venv` or `uvx python`. This change will not affect users who are using a `.python-version` file to pin to a specific Python version. + +- **Allow use of free-threaded variants in Python 3.14+ without explicit opt-in** ([#16142](https://github.com/astral-sh/uv/pull/16142)) + + Previously, free-threaded variants of Python were considered experimental and required explicit opt-in (i.e., with `3.14t`) for usage. Now uv will allow use of free-threaded Python 3.14+ interpreters without explicit selection. The GIL-enabled build of Python will still be preferred, e.g., when performing an installation with `uv python install 3.14`. However, e.g., if a free-threaded interpreter comes before a GIL-enabled build on the `PATH`, it will be used. This change does not apply to free-threaded Python 3.13 interpreters, which will continue to require opt-in. + +- **Use Python 3.14 stable Docker images** ([#16150](https://github.com/astral-sh/uv/pull/16150)) + + Previously, the Python 3.14 images had an `-rc` suffix, e.g., `python:3.14-rc-alpine` or + `python:3.14-rc-trixie`. Now, the `-rc` suffix has been removed to match the stable + [upstream images](https://hub.docker.com/_/python). The `-rc` images tags will no longer be + updated. This change should not break existing workflows. + +- **Upgrade Alpine Docker image to Alpine 3.22** + + Previously, the `uv:alpine` Docker image was based on Alpine 3.21. Now, this image is based on Alpine 3.22. The previous image can be recovered with `uv:alpine3.21` and will continue to be updated until a future release. + +- **Upgrade Debian Docker images to Debian 13 "Trixie"** + + Previously, the `uv:debian` and `uv:debian-slim` Docker images were based on Debian 12 "Bookworm". Now, these images are based on Debian 13 "Trixie". The previous images can be recovered with `uv:bookworm` and `uv:bookworm-slim` and will continue to be updated until a future release. + +- **Fix incorrect output path when a trailing `/` is used in `uv build`** ([#15133](https://github.com/astral-sh/uv/pull/15133)) + + When using `uv build` in a workspace, the artifacts are intended to be written to a `dist` directory in the workspace root. A bug caused workspace root determination to fail when the input path included a trailing `/` causing the `dist` directory to be placed in the child directory. This bug has been fixed in this release. For example, `uv build child/` is used, the output path will now be in `/dist/` rather than `/child/dist/`. + +### Python + +- Add CPython 3.14.0 +- Add CPython 3.13.8 + +### Enhancements + +- Don't warn when dependency is constraint by other dependency ([#16149](https://github.com/astral-sh/uv/pull/16149)) + +### Bug fixes + +- Fix `uv python upgrade / install` output when there is a no-op for one request ([#16158](https://github.com/astral-sh/uv/pull/16158)) +- Surface pinned-version hint when `uv tool upgrade` can’t move the tool ([#16081](https://github.com/astral-sh/uv/pull/16081)) +- Ban pre-release versions in `uv python upgrade` requests ([#16160](https://github.com/astral-sh/uv/pull/16160)) +- Fix `uv python upgrade` replacement of installed binaries on pre-release to stable ([#16159](https://github.com/astral-sh/uv/pull/16159)) + +### Documentation + +- Update `uv pip compile` args in `layout.md` ([#16155](https://github.com/astral-sh/uv/pull/16155)) + ## 0.8.24 Released on 2025-10-06. diff --git a/Cargo.lock b/Cargo.lock index edd7e32f2..ceb62d2aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5276,7 +5276,7 @@ dependencies = [ [[package]] name = "uv" -version = "0.8.24" +version = "0.9.0" dependencies = [ "anstream", "anyhow", @@ -5489,7 +5489,7 @@ dependencies = [ [[package]] name = "uv-build" -version = "0.8.24" +version = "0.9.0" dependencies = [ "anstream", "anyhow", @@ -6776,7 +6776,7 @@ dependencies = [ [[package]] name = "uv-version" -version = "0.8.24" +version = "0.9.0" [[package]] name = "uv-virtualenv" diff --git a/crates/uv-build/Cargo.toml b/crates/uv-build/Cargo.toml index e0af266bf..811e2bfa8 100644 --- a/crates/uv-build/Cargo.toml +++ b/crates/uv-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uv-build" -version = "0.8.24" +version = "0.9.0" edition = { workspace = true } rust-version = { workspace = true } homepage = { workspace = true } diff --git a/crates/uv-build/pyproject.toml b/crates/uv-build/pyproject.toml index 707c88eef..55f0adef6 100644 --- a/crates/uv-build/pyproject.toml +++ b/crates/uv-build/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uv-build" -version = "0.8.24" +version = "0.9.0" description = "The uv build backend" authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }] requires-python = ">=3.8" diff --git a/crates/uv-version/Cargo.toml b/crates/uv-version/Cargo.toml index 93693ba94..f9d86b45e 100644 --- a/crates/uv-version/Cargo.toml +++ b/crates/uv-version/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uv-version" -version = "0.8.24" +version = "0.9.0" edition = { workspace = true } rust-version = { workspace = true } homepage = { workspace = true } diff --git a/crates/uv-workspace/src/workspace.rs b/crates/uv-workspace/src/workspace.rs index 455bbb5a4..06bd7f34e 100644 --- a/crates/uv-workspace/src/workspace.rs +++ b/crates/uv-workspace/src/workspace.rs @@ -201,6 +201,10 @@ impl Workspace { let path = std::path::absolute(path) .map_err(WorkspaceError::Normalize)? .clone(); + // Remove `.` and `..` + let path = uv_fs::normalize_path(&path); + // Trim trailing slashes. + let path = path.components().collect::(); let project_path = path .ancestors() @@ -1363,6 +1367,10 @@ impl ProjectWorkspace { let project_path = std::path::absolute(install_path) .map_err(WorkspaceError::Normalize)? .clone(); + // Remove `.` and `..` + let project_path = uv_fs::normalize_path(&project_path); + // Trim trailing slashes. + let project_path = project_path.components().collect::(); // Check if workspaces are explicitly disabled for the project. if project_pyproject_toml diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index e60faa1e8..930cce574 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uv" -version = "0.8.24" +version = "0.9.0" edition = { workspace = true } rust-version = { workspace = true } homepage = { workspace = true } diff --git a/crates/uv/tests/it/build.rs b/crates/uv/tests/it/build.rs index b18690b52..6d55a5a01 100644 --- a/crates/uv/tests/it/build.rs +++ b/crates/uv/tests/it/build.rs @@ -2084,3 +2084,65 @@ fn venv_included_in_sdist() -> Result<()> { Ok(()) } + +/// Ensure that workspace discovery works with and without trailing slash. +/// +/// +#[test] +fn test_workspace_trailing_slash() { + let context = TestContext::new("3.12"); + + // Create a workspace with a root and a member. + context.init().arg("--lib").assert().success(); + context.init().arg("--lib").arg("child").assert().success(); + + uv_snapshot!(context.filters(), context.build().arg("child"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Building source distribution (uv build backend)... + Building wheel from source distribution (uv build backend)... + Successfully built dist/child-0.1.0.tar.gz + Successfully built dist/child-0.1.0-py3-none-any.whl + "); + + // Check that workspace discovery still works. + uv_snapshot!(context.filters(), context.build().arg("child/"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Building source distribution (uv build backend)... + Building wheel from source distribution (uv build backend)... + Successfully built dist/child-0.1.0.tar.gz + Successfully built dist/child-0.1.0-py3-none-any.whl + "); + + // Check general normalization too. + uv_snapshot!(context.filters(), context.build().arg("./child/"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Building source distribution (uv build backend)... + Building wheel from source distribution (uv build backend)... + Successfully built dist/child-0.1.0.tar.gz + Successfully built dist/child-0.1.0-py3-none-any.whl + "); + + uv_snapshot!(context.filters(), context.build().arg("./child/../child/"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Building source distribution (uv build backend)... + Building wheel from source distribution (uv build backend)... + Successfully built dist/child-0.1.0.tar.gz + Successfully built dist/child-0.1.0-py3-none-any.whl + "); +} diff --git a/docs/concepts/build-backend.md b/docs/concepts/build-backend.md index 348fc250f..ac8c9afe5 100644 --- a/docs/concepts/build-backend.md +++ b/docs/concepts/build-backend.md @@ -31,7 +31,7 @@ To use uv as a build backend in an existing project, add `uv_build` to the ```toml title="pyproject.toml" [build-system] -requires = ["uv_build>=0.8.24,<0.9.0"] +requires = ["uv_build>=0.9.0,<0.10.0"] build-backend = "uv_build" ``` diff --git a/docs/concepts/projects/init.md b/docs/concepts/projects/init.md index c3dbeed0b..32f459827 100644 --- a/docs/concepts/projects/init.md +++ b/docs/concepts/projects/init.md @@ -111,7 +111,7 @@ dependencies = [] example-pkg = "example_pkg:main" [build-system] -requires = ["uv_build>=0.8.24,<0.9.0"] +requires = ["uv_build>=0.9.0,<0.10.0"] build-backend = "uv_build" ``` @@ -134,7 +134,7 @@ dependencies = [] example-pkg = "example_pkg:main" [build-system] -requires = ["uv_build>=0.8.24,<0.9.0"] +requires = ["uv_build>=0.9.0,<0.10.0"] build-backend = "uv_build" ``` @@ -195,7 +195,7 @@ requires-python = ">=3.11" dependencies = [] [build-system] -requires = ["uv_build>=0.8.24,<0.9.0"] +requires = ["uv_build>=0.9.0,<0.10.0"] build-backend = "uv_build" ``` diff --git a/docs/concepts/projects/workspaces.md b/docs/concepts/projects/workspaces.md index 4d8253f2c..bb2d232c1 100644 --- a/docs/concepts/projects/workspaces.md +++ b/docs/concepts/projects/workspaces.md @@ -75,7 +75,7 @@ bird-feeder = { workspace = true } members = ["packages/*"] [build-system] -requires = ["uv_build>=0.8.24,<0.9.0"] +requires = ["uv_build>=0.9.0,<0.10.0"] build-backend = "uv_build" ``` @@ -106,7 +106,7 @@ tqdm = { git = "https://github.com/tqdm/tqdm" } members = ["packages/*"] [build-system] -requires = ["uv_build>=0.8.24,<0.9.0"] +requires = ["uv_build>=0.9.0,<0.10.0"] build-backend = "uv_build" ``` @@ -188,7 +188,7 @@ dependencies = ["bird-feeder", "tqdm>=4,<5"] bird-feeder = { path = "packages/bird-feeder" } [build-system] -requires = ["uv_build>=0.8.24,<0.9.0"] +requires = ["uv_build>=0.9.0,<0.10.0"] build-backend = "uv_build" ``` diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 2eaaa94f7..031ae2f0c 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -25,7 +25,7 @@ uv provides a standalone installer to download and install uv: Request a specific version by including it in the URL: ```console - $ curl -LsSf https://astral.sh/uv/0.8.24/install.sh | sh + $ curl -LsSf https://astral.sh/uv/0.9.0/install.sh | sh ``` === "Windows" @@ -41,7 +41,7 @@ uv provides a standalone installer to download and install uv: Request a specific version by including it in the URL: ```pwsh-session - PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.8.24/install.ps1 | iex" + PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.9.0/install.ps1 | iex" ``` !!! tip diff --git a/docs/guides/integration/aws-lambda.md b/docs/guides/integration/aws-lambda.md index 80fe94b68..64ffc9062 100644 --- a/docs/guides/integration/aws-lambda.md +++ b/docs/guides/integration/aws-lambda.md @@ -92,7 +92,7 @@ the second stage, we'll copy this directory over to the final image, omitting th other unnecessary files. ```dockerfile title="Dockerfile" -FROM ghcr.io/astral-sh/uv:0.8.24 AS uv +FROM ghcr.io/astral-sh/uv:0.9.0 AS uv # First, bundle the dependencies into the task root. FROM public.ecr.aws/lambda/python:3.13 AS builder @@ -334,7 +334,7 @@ And confirm that opening http://127.0.0.1:8000/ in a web browser displays, "Hell Finally, we'll update the Dockerfile to include the local library in the deployment package: ```dockerfile title="Dockerfile" -FROM ghcr.io/astral-sh/uv:0.8.24 AS uv +FROM ghcr.io/astral-sh/uv:0.9.0 AS uv # First, bundle the dependencies into the task root. FROM public.ecr.aws/lambda/python:3.13 AS builder diff --git a/docs/guides/integration/docker.md b/docs/guides/integration/docker.md index 88f5ba2b7..f8519a1e5 100644 --- a/docs/guides/integration/docker.md +++ b/docs/guides/integration/docker.md @@ -31,7 +31,7 @@ $ docker run --rm -it ghcr.io/astral-sh/uv:debian uv --help The following distroless images are available: - `ghcr.io/astral-sh/uv:latest` -- `ghcr.io/astral-sh/uv:{major}.{minor}.{patch}`, e.g., `ghcr.io/astral-sh/uv:0.8.24` +- `ghcr.io/astral-sh/uv:{major}.{minor}.{patch}`, e.g., `ghcr.io/astral-sh/uv:0.9.0` - `ghcr.io/astral-sh/uv:{major}.{minor}`, e.g., `ghcr.io/astral-sh/uv:0.8` (the latest patch version) @@ -95,7 +95,7 @@ And the following derived images are available: As with the distroless image, each derived image is published with uv version tags as `ghcr.io/astral-sh/uv:{major}.{minor}.{patch}-{base}` and -`ghcr.io/astral-sh/uv:{major}.{minor}-{base}`, e.g., `ghcr.io/astral-sh/uv:0.8.24-alpine`. +`ghcr.io/astral-sh/uv:{major}.{minor}-{base}`, e.g., `ghcr.io/astral-sh/uv:0.9.0-alpine`. In addition, starting with `0.8` each derived image also sets `UV_TOOL_BIN_DIR` to `/usr/local/bin` to allow `uv tool install` to work as expected with the default user. @@ -136,7 +136,7 @@ Note this requires `curl` to be available. In either case, it is best practice to pin to a specific uv version, e.g., with: ```dockerfile -COPY --from=ghcr.io/astral-sh/uv:0.8.24 /uv /uvx /bin/ +COPY --from=ghcr.io/astral-sh/uv:0.9.0 /uv /uvx /bin/ ``` !!! tip @@ -154,7 +154,7 @@ COPY --from=ghcr.io/astral-sh/uv:0.8.24 /uv /uvx /bin/ Or, with the installer: ```dockerfile -ADD https://astral.sh/uv/0.8.24/install.sh /uv-installer.sh +ADD https://astral.sh/uv/0.9.0/install.sh /uv-installer.sh ``` ### Installing a project @@ -590,5 +590,5 @@ Verified OK !!! tip These examples use `latest`, but best practice is to verify the attestation for a specific - version tag, e.g., `ghcr.io/astral-sh/uv:0.8.24`, or (even better) the specific image digest, + version tag, e.g., `ghcr.io/astral-sh/uv:0.9.0`, or (even better) the specific image digest, such as `ghcr.io/astral-sh/uv:0.5.27@sha256:5adf09a5a526f380237408032a9308000d14d5947eafa687ad6c6a2476787b4f`. diff --git a/docs/guides/integration/github.md b/docs/guides/integration/github.md index 73bbfcfb4..976c1fe2c 100644 --- a/docs/guides/integration/github.md +++ b/docs/guides/integration/github.md @@ -47,7 +47,7 @@ jobs: uses: astral-sh/setup-uv@v6 with: # Install a specific version of uv. - version: "0.8.24" + version: "0.9.0" ``` ## Setting up Python diff --git a/docs/guides/integration/pre-commit.md b/docs/guides/integration/pre-commit.md index f3c6ec504..7bd134d44 100644 --- a/docs/guides/integration/pre-commit.md +++ b/docs/guides/integration/pre-commit.md @@ -19,7 +19,7 @@ To make sure your `uv.lock` file is up to date even if your `pyproject.toml` fil repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.8.24 + rev: 0.9.0 hooks: - id: uv-lock ``` @@ -30,7 +30,7 @@ To keep a `requirements.txt` file in sync with your `uv.lock` file: repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.8.24 + rev: 0.9.0 hooks: - id: uv-export ``` @@ -41,7 +41,7 @@ To compile requirements files: repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.8.24 + rev: 0.9.0 hooks: # Compile requirements - id: pip-compile @@ -54,7 +54,7 @@ To compile alternative requirements files, modify `args` and `files`: repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.8.24 + rev: 0.9.0 hooks: # Compile requirements - id: pip-compile @@ -68,7 +68,7 @@ To run the hook over multiple files at the same time, add additional entries: repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.8.24 + rev: 0.9.0 hooks: # Compile requirements - id: pip-compile diff --git a/pyproject.toml b/pyproject.toml index caf24bc96..67bfbb1d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "uv" -version = "0.8.24" +version = "0.9.0" description = "An extremely fast Python package and project manager, written in Rust." authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }] requires-python = ">=3.8" diff --git a/scripts/packages/built-by-uv/pyproject.toml b/scripts/packages/built-by-uv/pyproject.toml index b95f9862f..fe590308f 100644 --- a/scripts/packages/built-by-uv/pyproject.toml +++ b/scripts/packages/built-by-uv/pyproject.toml @@ -24,5 +24,5 @@ data = "assets" headers = "header" [build-system] -requires = ["uv_build>=0.8.0,<0.9.0"] +requires = ["uv_build>=0.8.0,<0.10.0"] build-backend = "uv_build" diff --git a/scripts/packages/fake-uv/pyproject.toml b/scripts/packages/fake-uv/pyproject.toml index 75c4e14c1..103bff35d 100644 --- a/scripts/packages/fake-uv/pyproject.toml +++ b/scripts/packages/fake-uv/pyproject.toml @@ -7,5 +7,5 @@ requires-python = ">=3.8" scripts = "scripts" [build-system] -requires = ["uv_build>=0.8.0,<0.9"] +requires = ["uv_build>=0.8.0,<0.10"] build-backend = "uv_build" diff --git a/scripts/packages/package.name.with.dots/pyproject.toml b/scripts/packages/package.name.with.dots/pyproject.toml index c32104e45..45215a0b0 100644 --- a/scripts/packages/package.name.with.dots/pyproject.toml +++ b/scripts/packages/package.name.with.dots/pyproject.toml @@ -7,5 +7,5 @@ requires-python = ">=3.8" scripts = "scripts" [build-system] -requires = ["uv_build>=0.8.0,<0.9"] +requires = ["uv_build>=0.8.0,<0.10"] build-backend = "uv_build"