---
title: "PyPI (Python) Packages and Feeds in Proget"
nav-title: "PyPI (Python)"
order: 13
---

The Python Package Index ([PyPI](https://pypi.org/)) is the main repository for software and libraries written in the Python programming language. Since version 5.2, ProGet supports the creation of PyPI feeds to host and deploy custom Python software packages.

ProGet's ["Feeds"](/docs/proget/feeds/feed-overview) can act as PyPI package repositories that let you centralize your package management and keep a handle on which packages your organization uses. Along with [publishing and hosting your private Python packages](/docs/proget/feeds/pypi/howto-pypi-publish), ProGet also acts as a [proxy for the PyPI repository](/docs/proget/feeds/pypi/howto-pypi-proxy), allowing you to cache and manage dependencies pulled from [PyPI](https://pypi.org/).

The instructions on this page use [pip](https://pip.pypa.io/), however you can also integrate other tools such as [PipEnv and Poetry](/docs/proget/feeds/pypi/integrate-pypi-others) with your PyPI feeds. 

## Using Your PyPI Feed as a Source to Install Packages

To use your PyPI feed when installing packages you can either set it globally in your with the `pip config` command, or run the `pip install` command. 

### Using a `pip Config` File

Setting your feed globally in the [pip config](https://pip.pypa.io/en/stable/topics/configuration/) file using the [`pip config`](https://pip.pypa.io/en/stable/cli/pip_config/) command makes it a default source for all installations. To store your feed you will need to use `pip config` with a `--global` parameter containing your feed endpoint URL.

```bash
$ pip config --global set global.index-url https://«proget-server»/pypi/«feed-name»/simple 
```

This command will generate a `pip config` file that looks like:

```bash
[global]
index-url = https://«proget-server»/pypi/«feed-name»/simple 
```

Then you can install packages simply using the `pip install` command:

```bash
pip install «package-name»==«package-version»
```

::: (Info) (Note: Scoping)
The `pip config` can be scoped to global (`--global`), user (`--user`), and to the environment (`--site`). The commands above are scoped to the global scope.
:::

### Using `pip install` With a URL Parameter

For one-off installations, you can also use `pip install`. Note this is not persistent —meaning you’ll need to re-specify the URL each time you install from your feed. Using a [pip config](https://pip.pypa.io/en/stable/topics/configuration/) file is more convenient for long-term use.

To install Python packages with the URL in the `pip install` command, you will need to add a `--extra-index-url` parameter containing your feed endpoint URL:

```bash
$ pip install «package-name»==«package-version» --extra-index-url https://«proget-server»/pypi/«feed-name»/simple
```

## Connecting to Another PyPI Repository

You can connect a PyPI feed to another PyPI repository. Packages that are downloaded or pulled through the feed will be automatically cached and installed in the feed. See [PyPI Package Management](#pypi-package-management) to learn more. Most PyPI repositories do not provide a user interface and are not designed to be searched or browsed, which makes their display in ProGet challenging.  However, you can still navigate to a specific package page by typing the exact name in the search box.

When possible, ProGet displays a default list of packages in a feed sorted by download count. For PyPI connectors, ProGet instead uses the RSS feed which is provided by PyPI.org to expose the latest package uploads.

### Non-PyPI.org repositories

PyPI.org implements a JSON API that provides some extra metadata for packages (such as a readme file), but most other repositories do not have this. Very basic information can be browsed in the ProGet UI if you know the exact name of the package, but this should primarily be used as a proxy instead of browsed directly

You may need to use the "Advanced" tab of the connector to specify an alternative `/simple` path; for example, if you try to connect to `https://download.pytorch.org/whl/cu124` without specifying this, you will receive `403` errors; changing the simple path to `/` will resolve this

### ProGet 2023
ProGet only supports searching package name and summary fields via the XML-RPC API (implemented by PyPI.org), other use cases of this API are not supported by ProGet. Connectors to other PyPI feeds require the PyPI JSON API to be implemented (both ProGet and PyPI.org support this)

Package names are generally normalized (as per the [PEP503 specs](https://www.python.org/dev/peps/pep-0503)), but packages where versions only differ by `-` and `_` (e.g. `my-package 1.0` and `my_package 1.1`) aren't properly listed under `my-package`. In addition, UI-based searching does not treat `_` and `-` the same
 
If these limitations are more than minor inconveniences, [please let us know](https://forums.inedo.com/) so we can figure out how to fix them.

## Authenticating to a PyPI Feed

If you've configured your feed to require authentication, you can use `pip` to authenticate to it, or alternatively use [PipEnv or Poetry](/docs/proget/feeds/pypi/integrate-pypi-others#authenticate-feed). 

:::(info) (Authenticating with an API Key)
Feeds can be authenticated with a ProGet username and password (`«username»:«password»`), but we strongly recommend using an [API Key](/docs/proget/api/apikeys) for authentication, with `api` as the username, and then API Key as the password (`api:«api-key»`)
:::

### Authenticating with `pip config`

Using `pip config` securely stores credentials in your [pip config](https://pip.pypa.io/en/stable/topics/configuration/) file, protecting your credentials. This is also convenient for repeated installs, removing the need to re-enter credentials.

To use a [pip config](https://pip.pypa.io/en/stable/topics/configuration/) file to store the authenticated feed, run the `pip config` command:

```bash
$ pip config --global set global.index-url https://api:«api-key»@«proget-server»/pypi/«feed-name»/simple 
$ pip config --global set global.trusted-host «proget-server»
```

These commands will generate a `pip config` file that looks like:

```bash
[global]
index-url = https://api:«api-key»@«proget-server»/pypi/«feed-name»/simple 
trusted-host = «proget-server»
```

Then you can install packages simply using the `pip install` command:

```bash
pip install «package-name»==«package-version»
```

### Authenticating with `pip install`

Alternatively you can authenticate with `pip install`. This is good for quick, one-off installations but exposes sensitive information in plain text, both in your shell history and process list. For this reason storing your credentials in your pip config file is generally recommended.

To pass basic authentication along with the URL in the `pip install` command, you will need to add a `--trusted-host` parameter containing your ProGet host and insert the API Key into the beginning of your URL. The `pip install` command would look like this:

```bash
$ pip install «package-name»==«package-version» --trusted-host «proget-server» -i https://api:«api-key»@«proget-server»/pypi/«feed-name»/simple 
```

## Creating Python Packages

To create a Python package that can be hosted by ProGet, you will need `setuptools` installed (run `pip install setuptools wheel`). Then run the standard `python` command:

```bash
$ python setup.py sdist bdist_wheel
```

For more detail on how to create a Python package, see [HOWTO: Upload Python Packages to a Private PyPI Repository in ProGet](/docs/proget/feeds/pypi/howto-pypi-publish#create-package). You can also read more on [best practices for authoring PyPi packages](https://blog.inedo.com/python/packages-authoring-best-practices/) on the Inedo Blog.

## Uploading Python Packages to a PyPI Feed

To publish your Python package to your ProGet PyPI feed, you can use [pgutil](/docs/proget/api/pgutil).

pgutil will require some [minor configuration](/docs/proget/api/pgutil#sources) before use. This includes setting up your ProGet instance and API key as a source by running:

```bash
$ pgutil sources add --name=Default --url=«proget-url» --api-key=«api-key»
```

To upload your package you would enter:

```bash
$ pgutil packages upload --feed=«feed-name» --input-file=«path-to-package»
```

For more examples on uploading, read [HOWTO: Publish npm Packages to a Private Registry in ProGet](/docs/proget/feeds/pypi/howto-pypi-publish#upload-package)

### Uploading with Twine

It's also possible to use the `twine upload` command if want to use [twine](https://pypi.org/project/twine/). To use an [API Key](/docs/proget/api/apikeys), you will need to use `api` for the username and the API key as the password. 

:::(warn)(Feed Endpoint URL)
Note that the feed endpoint URLs used when pushing packages vary slightly from the standard feed URL, ending with `/legacy` rather than `/simple`
:::

## Yanked or Deprecated PyPI Packages

When managing Python packages in ProGet, you can "Yank" packages (called "Deprecation" in ProGet), helping users releases that are no longer recommended for general use, such as those with critical bugs or vulnerabilities. Unlike deletion, a yanked version remains available but is excluded from default installation behavior unless explicitly requested. When yanking a package, users can include a reason that will be displayed in ProGet. 

To yank a package in ProGet, you can do so either in the ProGet UI or using [pgutil](/docs/proget/api/pgutil) with the [`set package status`](/docs/proget/api/packages/status) command: 

```bash
$ pgutil packages status deprecated --feed «feed-name» --package=«package-name» --version=«version» --reason=«reason-as-text»
```
