Command Palette

Search for a command to run…

ZarynZaryn
Packages·4 min read

Python packages (pip, uv, Poetry)

Install Python packages through Zaryn with pip, uv or Poetry, publish your own, install Python itself, and keep private packages private. One index for your projects and pypi.org, safe from look-alike packages. Every step explained.

Python's installers (**pip**, **uv**, **Poetry**) download packages from an *index*. Zaryn gives you one index for everything: - **Your projects** published on Zaryn, public or private. - **Everything on pypi.org**, through Zaryn's mirror: every file is checked against the sha256 pypi.org lists before Zaryn keeps it, and pip checks it again. - **Safe from look-alikes.** A name that exists on Zaryn always comes from Zaryn, so nobody can publish a same-named package on pypi.org and sneak it into your installs (this is called *dependency confusion*). And new names on Zaryn can't be ones pypi.org already has, so nobody can do it the other way round either. The index's address: ```text https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` ## Install packages through Zaryn ### pip Once per computer: ```bash pip config set global.index-url https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` That's all: `pip install requests` now goes through Zaryn. Or for one command only: ```bash pip install --index-url https://api.zaryn.xyz/v1/packages/pypi/all/simple/ requests ``` ### uv For every project on this computer, set it in your shell start file (`~/.bashrc` or similar): ```bash export UV_DEFAULT_INDEX=https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` Or for one project, in its `pyproject.toml`: ```toml [[tool.uv.index]] name = "zaryn" url = "https://api.zaryn.xyz/v1/packages/pypi/all/simple/" default = true ``` `uv add`, `uv sync` and `uv pip install` then use Zaryn. ### Poetry ```bash poetry source add --priority=primary zaryn https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` ### All of them at once With the `zev` command installed, `zev mirror on pip uv` writes the pip and uv settings for you, and `zev mirror off pip uv` removes them. See [Mirrors](/docs/en/package-mirrors#all-at-once-zev-mirror). ## Install Python itself (uv) uv can download Python too (`uv python install 3.13`, or automatically when a project needs it). Those downloads come from GitHub; to get them through Zaryn: ```bash export UV_PYTHON_INSTALL_MIRROR=https://api.zaryn.xyz/v1/packages/python/-/standalone uv python install 3.13 ``` Each build is checked against the release's SHA256SUMS before Zaryn keeps it, and uv checks it against the checksum it has built in. ## Publish your own package ### Build it From the folder with your `pyproject.toml`: ```bash python -m pip install build twine python -m build ``` This puts a wheel (`.whl`) and a source archive (`.tar.gz`) into `dist/`. ### Upload it Create a token on [Packages](/packages) (**Create a publish token**). Then, with twine: ```bash twine upload --repository-url https://api.zaryn.xyz/v1/packages/pypi/ \ -u __token__ -p YOUR_TOKEN dist/* ``` - `-u __token__` is literal: it tells Zaryn the password is a token. - To avoid typing it each time, put this in `~/.pypirc` and run `twine upload -r zaryn dist/*`: ```ini [distutils] index-servers = zaryn [zaryn] repository = https://api.zaryn.xyz/v1/packages/pypi/ username = __token__ password = YOUR_TOKEN ``` With uv or Poetry instead: ```bash uv publish --publish-url https://api.zaryn.xyz/v1/packages/pypi/ --username __token__ --password YOUR_TOKEN poetry config repositories.zaryn https://api.zaryn.xyz/v1/packages/pypi/ poetry publish -r zaryn --username __token__ --password YOUR_TOKEN ``` A version that's already uploaded can't be replaced: raise the version in `pyproject.toml` for a fix. ### Choosing a name A **new** name must not exist on pypi.org; Zaryn checks when you first upload. If it's taken there, pick another, for example with your team's prefix (`acme-utils`). This is what keeps the single index safe for everyone. ### Install it With the index set up as above, it's just `pip install your-package` or `uv add your-package`. Its dependencies from pypi.org come through the same index. ## Install straight from a Zaryn repository Any commit of a repository with a `pyproject.toml` (or `setup.py`) can be installed without publishing it first: open the repository, then the **install** tab next to the clone commands, and copy the line. It looks like this: ```bash pip install https://zaryn.xyz/api/v1/repos/<owner>/<repo>/branches/main/archive/<commit>.tar.gz ``` The address names a commit, so it always installs exactly the same code. In `pyproject.toml` the same works as a dependency: `"mytool @ https://zaryn.xyz/api/v1/repos/…/archive/<commit>.tar.gz"`. The repository must be public (or give pip your token in the address). ## Private packages (Premium) Make a package private on its page (**Make private**). Only you, or members of the organization that owns it, can see or install it. Installers then need your token, written into the index address: ```bash pip install --index-url https://__token__:$ZARYN_TOKEN@api.zaryn.xyz/v1/packages/pypi/all/simple/ your-package ``` For uv, set `UV_INDEX_ZARYN_USERNAME=__token__` and `UV_INDEX_ZARYN_PASSWORD=$ZARYN_TOKEN` (with the `zaryn` index from `pyproject.toml` above). ## When something goes wrong | You see | What it means | Fix | |---|---|---| | `403` "… is a project on pypi.org" when uploading | new names can't be ones pypi.org has | choose another name | | `403` "this token can't publish packages" | the token lacks `package:write` | create one on [Packages](/packages) | | `403` "this package name belongs to someone else" | another account uploaded that name first | choose another name | | `409` | that file was already uploaded | raise the version | | `503` "couldn't check that this name is free on pypi.org" | pypi.org didn't answer when you uploaded a new name | try again in a minute | | pip: "No matching distribution" | wrong index address, or a private package without the token | check the address ends in `/all/simple/` | | pip: "not a trusted or secure host" | the address starts with `http://` | use the `https://` address | ## How it works Every index Zaryn serves speaks both formats installers use: the classic HTML page (PEP 503) and JSON (PEP 691), whichever the installer asks for. It also gives each wheel's metadata as a separate small file (PEP 658), so pip and uv work out which versions fit without downloading whole wheels; this makes resolving noticeably faster. Files are stored by their SHA-256, which the index lists, so the installer checks every download. Names are normalized the way PyPI does it: `My_Package` and `my-package` are the same name. The addresses, if you need them separately: `/v1/packages/pypi/simple/` is only your projects on Zaryn, `/v1/packages/pypi/mirror/simple/` is only pypi.org, and `/v1/packages/pypi/all/simple/` is both.