uv/crates
Ofek Lev 82820d0f4c
Allow relative Python executable paths in Windows trampoline (#3717)
## Summary

This is a prerequisite for https://github.com/astral-sh/uv/issues/3669

## Test Plan

Download one of the standalone distributions on Windows then use its
Python to run the following script and then run the scripts it creates
(only pip):

```python
from __future__ import annotations

import sys
import sysconfig
from contextlib import closing
from importlib.metadata import entry_points
from io import BytesIO
from os.path import relpath
from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo

# Change this line to your real path
LAUNCHERS_DIR = Path('C:\\Users\\ofek\\Desktop\\code\\uv\\crates\\uv-trampoline\\target\\x86_64-pc-windows-msvc\\release')
SCRIPT_TEMPLATE = """\
#!{executable}
# -*- coding: utf-8 -*-
import re
import sys
from {module} import {import_name}
if __name__ == "__main__":
    sys.argv[0] = re.sub(r"(-script\\.pyw|\\.exe)?$", "", sys.argv[0])
    sys.exit({function}())
"""


def select_entry_points(ep, group):
    return ep.select(group=group) if sys.version_info[:2] >= (3, 10) else ep.get(group, [])


def main():
    interpreters_dir = Path(sys.executable).parent
    scripts_dir = Path(sysconfig.get_path('scripts'))

    ep = entry_points()
    for group, interpreter_name, launcher_name in (
        ('console_scripts', 'python.exe', 'uv-trampoline-console.exe'),
        ('gui_scripts', 'pythonw.exe', 'uv-trampoline-gui.exe'),
    ):
        interpreter = interpreters_dir / interpreter_name
        relative_interpreter_path = relpath(interpreter, scripts_dir)
        launcher_data = (LAUNCHERS_DIR / launcher_name).read_bytes()

        for script in select_entry_points(ep, group):
            # https://github.com/astral-sh/uv/tree/main/crates/uv-trampoline#how-do-you-use-it
            with closing(BytesIO()) as buf:
                # Launcher
                buf.write(launcher_data)

                # Zipped script
                with TemporaryDirectory() as td:
                    zip_path = Path(td) / 'script.zip'
                    with ZipFile(zip_path, 'w') as zf:
                        # Ensure reproducibility
                        zip_info = ZipInfo('__main__.py', (2020, 2, 2, 0, 0, 0))
                        zip_info.external_attr = (0o644 & 0xFFFF) << 16

                        module, _, attrs = script.value.partition(':')
                        contents = SCRIPT_TEMPLATE.format(
                            executable=relative_interpreter_path,
                            module=module,
                            import_name=attrs.split('.')[0],
                            function=attrs
                        )
                        zf.writestr(zip_info, contents, compress_type=ZIP_DEFLATED)

                    buf.write(zip_path.read_bytes())

                # Interpreter path
                interpreter_path = relative_interpreter_path.encode('utf-8')
                buf.write(interpreter_path)

                # Interpreter path length
                interpreter_path_length = len(interpreter_path).to_bytes(4, 'little')
                buf.write(interpreter_path_length)

                # Magic number
                buf.write(b'UVUV')

                script_data = buf.getvalue()

            script_path = scripts_dir / f'{script.name}.exe'
            script_path.write_bytes(script_data)


if __name__ == '__main__':
    main()
```
2024-05-21 21:53:15 -04:00
..
bench Parallelize resolver (#3627) 2024-05-17 11:47:30 -04:00
cache-key Avoid panic for file url (#3306) 2024-04-29 16:39:16 +02:00
distribution-filename require serde and rkyv everywhere; remove optional serde and rkyv features (#3345) 2024-05-03 10:21:03 -04:00
distribution-types Rename DistInfoMetadata to CoreMetadata (#3699) 2024-05-21 18:26:59 +00:00
install-wheel-rs Pin the zip crate to 0.6 (#3645) 2024-05-18 17:31:53 +00:00
once-map Use FxHasher in resolver (#3641) 2024-05-17 15:04:22 -04:00
pep440-rs pep508: add PartialOrd and Ord implementations to MarkerTree 2024-05-20 19:56:24 -04:00
pep508-rs Propagate URL errors in verbatim parsing (#3720) 2024-05-21 19:58:59 +00:00
platform-tags Rename all instances of Cpython to CPython (#3702) 2024-05-21 14:52:31 -05:00
pypi-types Rename DistInfoMetadata to CoreMetadata (#3699) 2024-05-21 18:26:59 +00:00
requirements-txt Propagate URL errors in verbatim parsing (#3720) 2024-05-21 19:58:59 +00:00
uv Do not discover virtual environment interpreters in uv venv --python ... (#3728) 2024-05-21 20:00:21 -05:00
uv-auth Increase verbosity of credential fetch logs (#3550) 2024-05-13 15:55:57 +00:00
uv-build Avoid keyword arguments for PEP 517 build hooks (#3517) 2024-05-10 17:15:08 -04:00
uv-cache Separate cache construction from initialization (#3607) 2024-05-15 12:29:39 -04:00
uv-client Add offline support to uv tool run and uv run (#3676) 2024-05-21 15:58:15 -05:00
uv-configuration Add UV_CONCURRENT_INSTALLS variable in favor of RAYON_NUM_THREADS (#3646) 2024-05-17 23:12:37 -04:00
uv-dev Rewrite Python interpreter discovery (#3266) 2024-05-21 14:37:23 -05:00
uv-dispatch Parallelize resolver (#3627) 2024-05-17 11:47:30 -04:00
uv-distribution Propagate URL errors in verbatim parsing (#3720) 2024-05-21 19:58:59 +00:00
uv-extract Remove unused seek methods (#3526) 2024-05-11 17:31:32 +00:00
uv-fs Get cargo shear passing (#3533) 2024-05-13 01:43:45 +00:00
uv-git uv-resolver: make PubGrubPackage orderable 2024-05-20 19:56:24 -04:00
uv-installer Remove some dependencies on EditableRequirement (#3727) 2024-05-21 23:36:53 +00:00
uv-interpreter Add support for requesting pypy interpreters by implementation name (#3706) 2024-05-21 16:48:43 -05:00
uv-normalize Improve JSON Schema and add export script (#3461) 2024-05-08 16:15:16 +00:00
uv-requirements Propagate URL errors in verbatim parsing (#3720) 2024-05-21 19:58:59 +00:00
uv-resolver Rewrite Python interpreter discovery (#3266) 2024-05-21 14:37:23 -05:00
uv-trampoline Allow relative Python executable paths in Windows trampoline (#3717) 2024-05-21 21:53:15 -04:00
uv-types Refactor editables for supporting them in bluejay commands (#3639) 2024-05-20 16:22:12 +00:00
uv-version Bump version to v0.1.45 (#3674) 2024-05-20 16:34:05 -04:00
uv-virtualenv Rewrite Python interpreter discovery (#3266) 2024-05-21 14:37:23 -05:00
uv-warnings Rename to uv (#1302) 2024-02-15 11:19:46 -06:00
uv-workspace Make --offline a global argument (#3729) 2024-05-22 00:09:05 +00:00
README.md Rename uv-traits and split into separate modules (#2674) 2024-03-26 15:39:43 -05:00

Crates

bench

Functionality for benchmarking uv.

cache-key

Generic functionality for caching paths, URLs, and other resources across platforms.

distribution-filename

Parse built distribution (wheel) and source distribution (sdist) filenames to extract structured metadata.

distribution-types

Abstractions for representing built distributions (wheels) and source distributions (sdists), and the sources from which they can be downloaded.

install-wheel-rs

Install built distributions (wheels) into a virtual environment.]

once-map

A waitmap-like concurrent hash map for executing tasks exactly once.

pep440-rs

Utilities for interacting with Python version numbers and specifiers.

pep508-rs

Utilities for interacting with PEP 508 dependency specifiers.

platform-host

Functionality for detecting the current platform (operating system, architecture, etc.).

platform-tags

Functionality for parsing and inferring Python platform tags as per PEP 425.

uv

Command-line interface for the uv package manager.

uv-build

A PEP 517-compatible build frontend for uv.

uv-cache

Functionality for caching Python packages and associated metadata.

uv-client

Client for interacting with PyPI-compatible HTTP APIs.

uv-dev

Development utilities for uv.

uv-dispatch

A centralized struct for resolving and building source distributions in isolated environments. Implements the traits defined in uv-types.

uv-distribution

Client for interacting with built distributions (wheels) and source distributions (sdists). Capable of fetching metadata, distribution contents, etc.

uv-extract

Utilities for extracting files from archives.

uv-fs

Utilities for interacting with the filesystem.

uv-git

Functionality for interacting with Git repositories.

uv-installer

Functionality for installing Python packages into a virtual environment.

uv-interpreter

Functionality for detecting and leveraging the current Python interpreter.

uv-normalize

Normalize package and extra names as per Python specifications.

uv-package

Types and functionality for working with Python packages, e.g., parsing wheel files.

uv-requirements

Utilities for reading package requirements from pyproject.toml and requirements.txt files.

uv-resolver

Functionality for resolving Python packages and their dependencies.

uv-types

Shared traits for uv, to avoid circular dependencies.

pypi-types

General-purpose type definitions for types used in PyPI-compatible APIs.

uv-virtualenv

A venv replacement to create virtual environments in Rust.

uv-warnings

User-facing warnings for uv.

requirements-txt

Functionality for parsing requirements.txt files.