# Install Python packages from CloudRepo

> Point pip at a CloudRepo repository with a repository token, install your private packages, keep public packages on PyPI, and fix a 401, 403 or 404.

pip reads CloudRepo like any other Python package index: give it the repository’s index URL, with the token in it, and install. This page is for the person whose project installs from a repository. To upload packages there, see [Publish Python packages](/docs/formats/python.html).

You need a Python repository and a repository token that reaches it. If you have neither yet: [create a repository](/docs/manage/repositories.html#creating-a-repository) and [create a token](/docs/authenticate/repository-tokens.html). A token that is **Read only** is enough to install.

## Point pip at the repository

pip takes the credential inside the index URL. The username is the email address of the account that created the token, with the `@` written as `%40`, and the password is the token. On Windows the file is `pip.ini`.

`~/.config/pip/pip.conf`

```ini
[global]
index-url = https://you%40example.com:YOUR_REPOSITORY_TOKEN@your-org.mycloudrepo.io/repositories/your-repo/simple/
```

The index URL is `https://<organization>.mycloudrepo.io/repositories/<repository>/simple/`: your organization’s name, then the repository’s name as the admin portal shows it. Without `/simple/` the URL answers the same index.

This file makes CloudRepo pip’s default index for every install. If a project installs public packages too, do not set `index-url` globally: use the three-step install below, which names CloudRepo only where it is needed.

To use the index for one command or one shell, or in CI, set `PIP_INDEX_URL` from your secret store instead of writing a file, and do not pass the URL on the command line:

**Terminal**

```bash
export PIP_INDEX_URL="https://you%40example.com:${CLOUDREPO_TOKEN}@your-org.mycloudrepo.io/repositories/your-repo/simple/"
pip install my-package
```

Expected: pip downloads `my-package` from `your-org.mycloudrepo.io` and prints `Successfully installed`.

## Install private and public packages together

Install your private packages from CloudRepo alone. Anyone can publish a package on PyPI under your private package’s name, and an install that can read PyPI as well may install theirs instead.

These steps assume pip’s default index is PyPI, so they do not use the `index-url` in the `pip.conf` above, or `PIP_INDEX_URL` in your shell. Step 2’s requirements file names CloudRepo itself. With a global `index-url`, step 1 would read CloudRepo instead of PyPI, and a hosted repository holds no public package.

pip cannot tie a package to an index. Given a second index (`--extra-index-url`, the `extra-index-url` key in `pip.conf`, or `PIP_EXTRA_INDEX_URL`), pip reads both as one and installs the highest version it finds in either, and an exact `==` pin does not help when both indexes have that version. So install in three steps, with one index each:

**Terminal**

```bash
# 1. Public packages, from PyPI (pip's default index)
pip install -r requirements.txt


# 2. Private packages, from CloudRepo and nothing else
pip install -r requirements-private.txt


# 3. Your own project, last, without its dependencies (steps 1 and 2 installed them)
pip install --no-deps -e .
```

`requirements-private.txt`

```ini
--index-url https://${CLOUDREPO_USERNAME}:${CLOUDREPO_TOKEN}@your-org.mycloudrepo.io/repositories/your-repo/simple/
acme-ml-core==3.2.1
acme-feature-pipeline==2.0.0
```

- The `--index-url` line makes CloudRepo the only index for that command. Use the repository that hosts your private packages, not one that proxies PyPI. pip fills in `${CLOUDREPO_USERNAME}` and `${CLOUDREPO_TOKEN}` from the environment, so the file holds no credential and is safe to commit. `CLOUDREPO_USERNAME` is your plain email address.
- Nothing step 1 installs may depend on a private package, your own project included: pip would fetch that private package from PyPI in step 1. Keep private package names, and `.` or `-e .`, out of `requirements.txt`.
- Step 3 builds your project in an isolated environment that pip fills from PyPI. If `[build-system] requires` names a private package, put it in `requirements-private.txt`, put the public build requirements (such as `setuptools`) in `requirements.txt`, and run step 3 as `pip install --no-deps --no-build-isolation -e .`.
- List the public packages that your private packages depend on in `requirements.txt`. Step 2 then finds them installed. If one is missing, step 2 fails rather than looking for it on PyPI.

Hashes protect something else. With `pip install --require-hashes -r requirements.txt`, pip installs only files whose SHA-256 you recorded, so a file published later under the same name and version is refused, whichever index serves it. Hashes do not choose the index: with two indexes the install can stop with a hash error instead of installing your copy. Record them from an install that read CloudRepo alone for your private packages, because a hash taken from PyPI’s copy protects PyPI’s copy.

## When pip answers 401, 403 or 404

pip prints the status it received, or `No matching distribution found` for a package it cannot find. Check these in order:

- **401 Unauthorized.** The credential was refused. The username must be the email address of the account that created the token, with the `@` written as `%40` (pip also accepts a bare `@`). `__token__` is refused: that is the convention on pypi.org, and CloudRepo does not use it. The password must be the token itself, and a token that is expired or revoked fails the same way: the **Repository Tokens** page in the admin portal shows its status.
- **403 Forbidden.** The token does not reach this repository. A token reaches only the repositories ticked when it was created, so use one that includes it.
- **404 Not Found, or no matching distribution.** The repository does not hold that name and version, or the index URL is wrong. Check the organization and repository names in it. A proxy repository that the token does not reach also answers `404`, not `403`.

More: [Repository tokens](/docs/authenticate/repository-tokens.html), for every client’s credential; [Proxy repositories](/docs/consume/proxy-repositories.html), to install public packages through CloudRepo; [Python repositories](/docs/formats/python.html), for uploading, overwrite protection and the other settings.

---

The page: https://www.cloudrepo.io/docs/consume/python.html
