mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-03 10:33:49 +00:00

This adds `alpha`, `beta`, `rc`, `stable`, `post`, and `dev` modes to `uv version --bump`. The components that `--bump` accepts are ordered as follows: major > minor > patch > stable > alpha > beta > rc > post > dev Bumping a component "clears" all lesser component (`alpha`, `beta`, and `rc` all overwrite each other): * `--bump minor` on `1.2.3a4.post5.dev6` => `1.3.0` * `--bump alpha` on `1.2.3a4.post5.dev6` => `1.2.3a5` * `--bump dev ` on `1.2.3a4.post5.dev6` => `1.2.3a4.post5.dev7` In addition, `--bump` can now be repeated. The primary motivation of this is "bump stable version and also enter a prerelease", but it technically lets you express other things if you want them: * `--bump patch --bump alpha` on `1.2.3` => `1.2.4a1` ("bump patch version and go to alpha 1") * `--bump minor --bump patch` on `1.2.3` => `1.3.1` ("bump minor version and got to patch 1") * `--bump minor --bump minor` on `1.2.3` => `1.4.0` ("bump minor version twice") The `--bump` flags are sorted by their priority, so that you don't need to remember the priority yourself. This ordering is the only "useful" one that preserves every `--bump` you passed, so there's no concern about loss of expressiveness. For instance `--bump minor --bump major` would just be `--bump major` if we didn't sort, as the major bump clears the minor version. The ordering of `beta` after `alpha` means `--bump alpha --bump beta` will just result in beta 1; this is the one case where a bump request will effectively get overwritten. The `stable` mode "bumps to the next stable release", clearing the pre (`alpha`, `beta`, `rc`), `dev`, and `post` components from a version (`1.2.3a4.post5.dev6` => `1.2.3`). The choice to clear `post` here is a bit odd, in that `1.2.3.post4` => `1.2.3` is actually a version decrease, but I think this gives a more intuitive model (as preserving `post5` in the previous example is definitely wrong), and also post-releases are extremely obscure so probably no one will notice. In the cases where this behaviour isn't useful, you probably wanted to pass `--bump patch` or something anyway which *should* definitely clear the `post5` (putting it another way: the only cases where `--bump stable` has dubious behaviour is when you wanted it to do a noop, which, is a command you could have just not written at all). In all cases we preserve the "epoch" and "local" components of a version, so the `7!` and `+local` in `7!1.2.3+local` will never be modified by `--bump` (you can use the raw version set mode if you want to touch those). The preservation of `local` is another slightly odd choice, but it's a really obscure feature (so again it mostly won't come up) and when it's used it seems to mostly be used for referring to variant releases, in which case preserving it tends to be correct. Fixes #13223 --------- Co-authored-by: Zanie Blue <contact@zanie.dev>
187 lines
6.5 KiB
Markdown
187 lines
6.5 KiB
Markdown
---
|
|
title: Building and publishing a package
|
|
description: A guide to using uv to build and publish Python packages to a package index, like PyPI.
|
|
---
|
|
|
|
# Building and publishing a package
|
|
|
|
uv supports building Python packages into source and binary distributions via `uv build` and
|
|
uploading them to a registry with `uv publish`.
|
|
|
|
## Preparing your project for packaging
|
|
|
|
Before attempting to publish your project, you'll want to make sure it's ready to be packaged for
|
|
distribution.
|
|
|
|
If your project does not include a `[build-system]` definition in the `pyproject.toml`, uv will not
|
|
build it by default. This means that your project may not be ready for distribution. Read more about
|
|
the effect of declaring a build system in the
|
|
[project concept](../concepts/projects/config.md#build-systems) documentation.
|
|
|
|
!!! note
|
|
|
|
If you have internal packages that you do not want to be published, you can mark them as
|
|
private:
|
|
|
|
```toml
|
|
[project]
|
|
classifiers = ["Private :: Do Not Upload"]
|
|
```
|
|
|
|
This setting makes PyPI reject your uploaded package from publishing. It does not affect
|
|
security or privacy settings on alternative registries.
|
|
|
|
We also recommend only generating [per-project PyPI API tokens](https://pypi.org/help/#apitoken):
|
|
Without a PyPI token matching the project, it can't be accidentally published.
|
|
|
|
## Building your package
|
|
|
|
Build your package with `uv build`:
|
|
|
|
```console
|
|
$ uv build
|
|
```
|
|
|
|
By default, `uv build` will build the project in the current directory, and place the built
|
|
artifacts in a `dist/` subdirectory.
|
|
|
|
Alternatively, `uv build <SRC>` will build the package in the specified directory, while
|
|
`uv build --package <PACKAGE>` will build the specified package within the current workspace.
|
|
|
|
!!! info
|
|
|
|
By default, `uv build` respects `tool.uv.sources` when resolving build dependencies from the
|
|
`build-system.requires` section of the `pyproject.toml`. When publishing a package, we recommend
|
|
running `uv build --no-sources` to ensure that the package builds correctly when `tool.uv.sources`
|
|
is disabled, as is the case when using other build tools, like [`pypa/build`](https://github.com/pypa/build).
|
|
|
|
## Updating your version
|
|
|
|
The `uv version` command provides conveniences for updating the version of your package before you
|
|
publish it.
|
|
[See the project docs for reading your package's version](./projects.md#managing-version).
|
|
|
|
To update to an exact version, provide it as a positional argument:
|
|
|
|
```console
|
|
$ uv version 1.0.0
|
|
hello-world 0.7.0 => 1.0.0
|
|
```
|
|
|
|
To preview the change without updating the `pyproject.toml`, use the `--dry-run` flag:
|
|
|
|
```console
|
|
$ uv version 2.0.0 --dry-run
|
|
hello-world 1.0.0 => 2.0.0
|
|
$ uv version
|
|
hello-world 1.0.0
|
|
```
|
|
|
|
To increase the version of your package semantics, use the `--bump` option:
|
|
|
|
```console
|
|
$ uv version --bump minor
|
|
hello-world 1.2.3 => 1.3.0
|
|
```
|
|
|
|
The `--bump` option supports the following common version components: `major`, `minor`, `patch`,
|
|
`stable`, `alpha`, `beta`, `rc`, `post`, and `dev`. When provided more than once, the components
|
|
will be applied in order, from largest (`major`) to smallest (`dev`).
|
|
|
|
To move from a stable to pre-release version, bump one of the major, minor, or patch components in
|
|
addition to the pre-release component:
|
|
|
|
```console
|
|
$ uv version --bump patch --bump beta
|
|
hello-world 1.3.0 => 1.3.1b1
|
|
$ uv version --bump major --bump alpha
|
|
hello-world 1.3.0 => 2.0.0a1
|
|
```
|
|
|
|
When moving from a pre-release to a new pre-release version, just bump the relevant pre-release
|
|
component:
|
|
|
|
```console
|
|
uv version --bump beta
|
|
hello-world 1.3.0b1 => 1.3.1b2
|
|
```
|
|
|
|
When moving from a pre-release to a stable version, the `stable` option can be used to clear the
|
|
pre-release component:
|
|
|
|
```console
|
|
uv version --bump stable
|
|
hello-world 1.3.1b2 => 1.3.1
|
|
```
|
|
|
|
!!! info
|
|
|
|
By default, when `uv version` modifies the project it will perform a lock and sync. To
|
|
prevent locking and syncing, use `--frozen`, or, to just prevent syncing, use `--no-sync`.
|
|
|
|
## Publishing your package
|
|
|
|
Publish your package with `uv publish`:
|
|
|
|
```console
|
|
$ uv publish
|
|
```
|
|
|
|
Set a PyPI token with `--token` or `UV_PUBLISH_TOKEN`, or set a username with `--username` or
|
|
`UV_PUBLISH_USERNAME` and password with `--password` or `UV_PUBLISH_PASSWORD`. For publishing to
|
|
PyPI from GitHub Actions, you don't need to set any credentials. Instead,
|
|
[add a trusted publisher to the PyPI project](https://docs.pypi.org/trusted-publishers/adding-a-publisher/).
|
|
|
|
!!! note
|
|
|
|
PyPI does not support publishing with username and password anymore, instead you need to
|
|
generate a token. Using a token is equivalent to setting `--username __token__` and using the
|
|
token as password.
|
|
|
|
If you're using a custom index through `[[tool.uv.index]]`, add `publish-url` and use
|
|
`uv publish --index <name>`. For example:
|
|
|
|
```toml
|
|
[[tool.uv.index]]
|
|
name = "testpypi"
|
|
url = "https://test.pypi.org/simple/"
|
|
publish-url = "https://test.pypi.org/legacy/"
|
|
explicit = true
|
|
```
|
|
|
|
!!! note
|
|
|
|
When using `uv publish --index <name>`, the `pyproject.toml` must be present, i.e., you need to
|
|
have a checkout step in a publish CI job.
|
|
|
|
Even though `uv publish` retries failed uploads, it can happen that publishing fails in the middle,
|
|
with some files uploaded and some files still missing. With PyPI, you can retry the exact same
|
|
command, existing identical files will be ignored. With other registries, use
|
|
`--check-url <index url>` with the index URL (not the publishing URL) the packages belong to. When
|
|
using `--index`, the index URL is used as check URL. uv will skip uploading files that are identical
|
|
to files in the registry, and it will also handle raced parallel uploads. Note that existing files
|
|
need to match exactly with those previously uploaded to the registry, this avoids accidentally
|
|
publishing source distribution and wheels with different contents for the same version.
|
|
|
|
## Installing your package
|
|
|
|
Test that the package can be installed and imported with `uv run`:
|
|
|
|
```console
|
|
$ uv run --with <PACKAGE> --no-project -- python -c "import <PACKAGE>"
|
|
```
|
|
|
|
The `--no-project` flag is used to avoid installing the package from your local project directory.
|
|
|
|
!!! tip
|
|
|
|
If you have recently installed the package, you may need to include the
|
|
`--refresh-package <PACKAGE>` option to avoid using a cached version of the package.
|
|
|
|
## Next steps
|
|
|
|
To learn more about publishing packages, check out the
|
|
[PyPA guides](https://packaging.python.org/en/latest/guides/section-build-and-publish/) on building
|
|
and publishing.
|
|
|
|
Or, read on for [guides](./integration/index.md) on integrating uv with other software.
|