Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8290c3f
Update uv_build version automatically
konstin Aug 25, 2025
a23f1a2
Update scripts/update_uv_build_version.py
konstin Aug 26, 2025
7500df2
Review
konstin Aug 26, 2025
77d8c71
Use same `actions/checkout@v4` as zizmor job
konstin Aug 26, 2025
7df08f4
Linters
konstin Aug 26, 2025
6497762
Undo accidental cosmetic change
konstin Aug 26, 2025
083e986
Clarify that the Dynamic metadata field only applies when building fr…
pfmoore Aug 27, 2025
42d1cbb
Grr, keyboard is doubling up letters :-(
pfmoore Aug 27, 2025
875b13f
Refer to auditwheel rather than cibuildwheel
pfmoore Aug 27, 2025
6569d5c
Clarify prebuilt wheels
pfmoore Aug 27, 2025
cd571af
Remove advice for tools that modify wheels
pfmoore Aug 27, 2025
31d7277
Update .github/workflows/update-uv-build-version.yml
konstin Aug 28, 2025
ce4251e
Create PR as draft
konstin Sep 15, 2025
4f0a3c6
Vagrant link is failing CI, drop it entirely
ncoghlan Sep 16, 2025
f99923a
Merge pull request #1912 from ncoghlan/remove-failing-vagrant-link
webknjaz Sep 16, 2025
c327427
Avoid binary gender assumptions in example
ncoghlan Sep 16, 2025
332cc30
Use a more obviously gender neutral title
ncoghlan Sep 16, 2025
159fc06
Update example output
ncoghlan Sep 16, 2025
8e2589d
Merge remote-tracking branch 'origin/main' into avoid-binary-gender-e…
ncoghlan Sep 16, 2025
a1842f5
Merge branch 'main' into dynamic_clarification
ncoghlan Sep 16, 2025
bceb264
ci: remove workflow_dispatch from cron.yml
woodruffw Sep 16, 2025
ace5183
Merge pull request #1901 from pfmoore/dynamic_clarification
ncoghlan Sep 16, 2025
c7ffbcc
ci: add pull_request event subtypes
woodruffw Sep 16, 2025
b036f24
update_uv_build_version: remove unneeded format
woodruffw Sep 16, 2025
a6c4683
Merge pull request #1913 from ncoghlan/avoid-binary-gender-example
webknjaz Sep 16, 2025
a1588cc
Merge pull request #1899 from konstin/konsti/update-uv-build-version-…
woodruffw Sep 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ on:
branches-ignore:
- gh-readonly-queue/** # Temporary merge queue-related GH-made branches
pull_request:
types:
- opened # default
- synchronize # default
- reopened # default
- ready_for_review # used in PRs created from GitHub Actions workflows
workflow_call:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true

permissions: {}

jobs:
build:
name: ${{ matrix.noxenv }}
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/update-uv-build-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---

name: Update uv build version

on:
schedule:
- cron: "0 6 * * 1" # mondays at 6am
workflow_dispatch:

jobs:
update-uv-build-version:
name: Update uv_build version
if: github.repository_owner == 'pypa' # suppress noise in forks
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up uv
uses: astral-sh/setup-uv@v5
- name: Update uv_build version
id: update_script
run: uv run scripts/update_uv_build_version.py
- # If there are no changes, no pull request will be created and the action exits silently.
name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update uv_build version to ${{ steps.update_script.outputs.version }}
title: Update uv_build version to ${{ steps.update_script.outputs.version }}
draft: true # Trigger CI by un-drafting the PR, otherwise `GITHUB_TOKEN` PRs don't trigger CI.
body: |
Automated update of uv_build version bounds for uv ${{ steps.update_script.outputs.version }}.

This PR was created automatically by the cron workflow, ping `@konstin` for problems.
branch: bot/update-uv-build-version
delete-branch: true

...
64 changes: 64 additions & 0 deletions scripts/update_uv_build_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# /// script
# requires-python = ">= 3.12"
# dependencies = [
# "httpx>=0.28.1,<0.29",
# "packaging>=25.0",
# ]
# ///
import os
import re
from pathlib import Path

import httpx
from packaging.utils import parse_wheel_filename
from packaging.version import Version


def main():
response = httpx.get(
"https://pypi.org/simple/uv-build/",
headers={"Accept": "application/vnd.pypi.simple.v1+json"},
)
response.raise_for_status()
data = response.json()
current_release = None
for file in data["files"]:
if not file["filename"].endswith(".whl"):
continue
_name, version, _build, _tags = parse_wheel_filename(file["filename"])
if version.is_prerelease:
continue
if current_release is None or version > current_release:
current_release = version

[major, minor, _patch] = current_release.release
if major != 0:
raise NotImplementedError("The script needs to be updated for uv 1.x")
upper_bound = Version(f"{major}.{minor + 1}.0")

repository_root = Path(__file__).parent.parent
existing = repository_root.joinpath(
"source/shared/build-backend-tabs.rst"
).read_text()
replacement = f'requires = ["uv_build >= {current_release}, <{upper_bound}"]'
searcher = re.compile(re.escape('requires = ["uv_build') + ".*" + re.escape('"]'))
if not searcher.search(existing):
raise RuntimeError("Could not `uv-build` entry")
updated = searcher.sub(replacement, existing)

if existing != updated:
print("Updating source/shared/build-backend-tabs.rst")
Path("source/shared/build-backend-tabs.rst").write_text(updated)
if github_output := os.environ.get("GITHUB_OUTPUT"):
with open(github_output, "a") as f:
f.write(f"version={current_release}\n")
f.write("updated=true\n")
else:
print("Already up-to-date source/shared/build-backend-tabs.rst")
if github_output := os.environ.get("GITHUB_OUTPUT"):
with open(github_output, "a") as f:
f.write("updated=false\n")


if __name__ == "__main__":
main()
55 changes: 23 additions & 32 deletions source/guides/creating-command-line-tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,22 @@ named after the main module:


def greet(
name: Annotated[str, typer.Argument(help="The (last, if --gender is given) name of the person to greet")] = "",
gender: Annotated[str, typer.Option(help="The gender of the person to greet")] = "",
knight: Annotated[bool, typer.Option(help="Whether the person is a knight")] = False,
name: Annotated[str, typer.Argument(help="The (last, if --title is given) name of the person to greet")] = "",
title: Annotated[str, typer.Option(help="The preferred title of the person to greet")] = "",
doctor: Annotated[bool, typer.Option(help="Whether the person is a doctor (MD or PhD)")] = False,
count: Annotated[int, typer.Option(help="Number of times to greet the person")] = 1
):
greeting = "Greetings, dear "
masculine = gender == "masculine"
feminine = gender == "feminine"
if gender or knight:
salutation = ""
if knight:
salutation = "Sir "
elif masculine:
salutation = "Mr. "
elif feminine:
salutation = "Ms. "
greeting += salutation
if name:
greeting += f"{name}!"
greeting = "Greetings, "
if doctor and not title:
title = "Dr."
if not name:
if title:
name = title.lower().rstrip(".")
else:
pronoun = "her" if feminine else "his" if masculine or knight else "its"
greeting += f"what's-{pronoun}-name"
else:
if name:
greeting += f"{name}!"
elif not gender:
greeting += "friend!"
name = "friend"
if title:
greeting += f"{title} "
greeting += f"{name}!"
for i in range(0, count):
print(greeting)

Expand Down Expand Up @@ -145,12 +134,14 @@ Let's test it:

.. code-block:: console

$ greet --knight Lancelot
Greetings, dear Sir Lancelot!
$ greet --gender feminine Parks
Greetings, dear Ms. Parks!
$ greet --gender masculine
Greetings, dear Mr. what's-his-name!
$ greet
Greetings, friend!
$ greet --doctor Brennan
Greetings, Dr. Brennan!
$ greet --title Ms. Parks
Greetings, Ms. Parks!
$ greet --title Mr.
Greetings, Mr. mr!

Since this example uses ``typer``, you could now also get an overview of the program's usage by calling it with
the ``--help`` option, or configure completions via the ``--install-completion`` option.
Expand All @@ -160,7 +151,7 @@ To just run the program without installing it permanently, use ``pipx run``, whi

.. code-block:: console

$ pipx run --spec . greet --knight
$ pipx run --spec . greet --doctor

This syntax is a bit impractical, however; as the name of the entry point we defined above does not match the package name,
we need to state explicitly which executable script to run (even though there is only on in existence).
Expand All @@ -179,7 +170,7 @@ default one and run it, which makes this command possible:

.. code-block:: console

$ pipx run . --knight
$ pipx run . --doctor

Conclusion
==========
Expand Down
12 changes: 8 additions & 4 deletions source/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ originated and where the technologies below work best:
Bringing your own kernel
^^^^^^^^^^^^^^^^^^^^^^^^

Most operating systems support some form of classical virtualization,
Most desktop operating systems support some form of classical virtualization,
running applications packaged as images containing a full operating
system of their own. Running these virtual machines, or VMs, is a
mature approach, widespread in data center environments.
Expand All @@ -348,9 +348,13 @@ These techniques are mostly reserved for larger scale deployments in
data centers, though certain complex applications can benefit from
this packaging. The technologies are Python agnostic, and include:

* `Vagrant <https://www.vagrantup.com/>`_
* `VHD <https://en.wikipedia.org/wiki/VHD_(file_format)>`_, `AMI <https://en.wikipedia.org/wiki/Amazon_Machine_Image>`_, and :doc:`other formats <openstack:user/formats>`
* `OpenStack <https://www.redhat.com/en/topics/openstack>`_ - A cloud management system in Python, with extensive VM support
* KVM on Linux
* Hyper-V on Windows
* `VHD <https://en.wikipedia.org/wiki/VHD_(file_format)>`_,
`AMI <https://en.wikipedia.org/wiki/Amazon_Machine_Image>`_,
and :doc:`other formats <openstack:user/formats>`
* `OpenStack <https://www.redhat.com/en/topics/openstack>`_ -
A cloud management system written in Python, with extensive VM support

Bringing your own hardware
^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
14 changes: 14 additions & 0 deletions source/specifications/core-metadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ only, and indicates that the field value was calculated at wheel build time,
and may not be the same as the value in the sdist or in other wheels for the
project.

Note in particular that if you have obtained a prebuilt wheel, you cannot
assume that a field which is not marked as ``Dynamic`` will have the same value
in other wheels, as some wheels are not built directly from the sdist, but are
modified from existing wheels (the ``auditwheel`` tool does this, for example,
and it's commonly used when building wheels for PyPI). Such modifications
*could* include changing metadata (even non-dynamic metadata). Similarly, if
you have a sdist and a wheel which you didn't build from that sdist, you cannot
assume that the wheel's metadata matches that of the sdist, even if the field
is not marked as ``Dynamic``.

Full details of the semantics of ``Dynamic`` are described in :pep:`643`.

.. _core-metadata-platform:
Expand Down Expand Up @@ -923,6 +933,10 @@ Example::
History
=======

- August 2025: Clarified that ``Dynamic`` only affects how fields
must be treated when building a wheel from a sdist, not when modifying
a wheel.

- August 2024: Core metadata 2.4 was approved through :pep:`639`.

- Added the ``License-Expression`` field.
Expand Down
Loading